| |
| |
| package compactcli |
|
|
| import ( |
| "encoding/json" |
| "flag" |
| "io" |
|
|
| "huggingface.co/turenlabs/Vigil/source/pkg/compactonnx" |
| "huggingface.co/turenlabs/Vigil/source/pkg/compactscan" |
| ) |
|
|
| const ( |
| ResultSchema = "vigil.compact-score.v1" |
| ErrorSchema = "vigil.compact-error.v1" |
| ) |
|
|
| type Result struct { |
| SchemaVersion string `json:"schema_version"` |
| InputIndex int `json:"input_index"` |
| Label string `json:"label"` |
| MaliciousProbability float64 `json:"malicious_probability"` |
| Threshold float64 `json:"threshold"` |
| WholePackage bool `json:"whole_package"` |
| ModelRequired bool `json:"model_required"` |
| Package compactscan.Stats `json:"package"` |
| compactonnx.Markers |
| } |
|
|
| type ErrorResult struct { |
| SchemaVersion string `json:"schema_version"` |
| ErrorCode string `json:"error_code"` |
| InputIndex *int `json:"input_index,omitempty"` |
| } |
|
|
| |
| |
| |
| func Run(arguments []string, stdout, stderr io.Writer) int { |
| flags := flag.NewFlagSet("vigil-compact", flag.ContinueOnError) |
| flags.SetOutput(io.Discard) |
| modelPath := flags.String("model", "", "external compact ONNX candidate") |
| metadataPath := flags.String("metadata", "", "adjacent candidate metadata") |
| runtimeLibrary := flags.String("runtime-lib", "", "ONNX Runtime shared library") |
| requireModel := flags.Bool("require-model", false, "require ONNX model loading (compact mode never falls back)") |
| releaseMode := flags.Bool("release", false, "require the embedded released compact model") |
| format := flags.String("format", "json", "machine-readable output format (json only)") |
| if err := flags.Parse(arguments); err != nil { |
| writeError(stderr, "invalid_arguments", nil) |
| return 2 |
| } |
| if *format != "json" { |
| writeError(stderr, "unsupported_format", nil) |
| return 2 |
| } |
| if *releaseMode { |
| |
| |
| writeError(stderr, "released_compact_model_unavailable", nil) |
| return 2 |
| } |
| if *modelPath == "" { |
| code := "model_required" |
| if !*requireModel { |
| code = "model_missing_no_fallback" |
| } |
| writeError(stderr, code, nil) |
| return 2 |
| } |
| if len(flags.Args()) == 0 { |
| writeError(stderr, "package_required", nil) |
| return 2 |
| } |
|
|
| model, err := compactonnx.Load(compactonnx.Config{ |
| ModelPath: *modelPath, MetadataPath: *metadataPath, RuntimeLibrary: *runtimeLibrary, |
| }) |
| if err != nil { |
| writeError(stderr, "model_load_failed", nil) |
| return 2 |
| } |
| defer model.Close() |
|
|
| encoder := json.NewEncoder(stdout) |
| failed := false |
| for index, target := range flags.Args() { |
| pkg, stats, err := compactscan.Scan(target) |
| if err != nil { |
| writeError(stderr, "package_scan_failed", &index) |
| failed = true |
| continue |
| } |
| probability, err := model.Score(pkg) |
| if err != nil { |
| writeError(stderr, "model_score_failed", &index) |
| failed = true |
| continue |
| } |
| label := "benign" |
| if probability >= model.Threshold() { |
| label = "malicious" |
| } |
| result := Result{ |
| SchemaVersion: ResultSchema, InputIndex: index, Label: label, |
| MaliciousProbability: probability, Threshold: model.Threshold(), |
| WholePackage: true, ModelRequired: true, Package: stats, |
| Markers: model.Markers(), |
| } |
| if err := encoder.Encode(result); err != nil { |
| writeError(stderr, "output_failed", &index) |
| return 1 |
| } |
| } |
| if failed { |
| return 1 |
| } |
| return 0 |
| } |
|
|
| func writeError(output io.Writer, code string, index *int) { |
| if code == "" { |
| code = "internal_error" |
| } |
| _ = json.NewEncoder(output).Encode(ErrorResult{SchemaVersion: ErrorSchema, ErrorCode: code, InputIndex: index}) |
| } |
|
|