github.com/google/osv-scalibr@v0.4.1/binary/scalibr/scalibr.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // The scalibr command wraps around the SCALIBR library to create a standalone 16 // CLI for extraction + detection with direct access to the local machine's filesystem. 17 package main 18 19 import ( 20 "flag" 21 "os" 22 23 "github.com/google/osv-scalibr/binary/cli" 24 "github.com/google/osv-scalibr/binary/scanrunner" 25 "github.com/google/osv-scalibr/log" 26 ) 27 28 func main() { 29 os.Exit(run(os.Args)) 30 } 31 32 func run(args []string) int { 33 var subcommand string 34 if len(args) >= 2 { 35 subcommand = args[1] 36 } 37 switch subcommand { 38 case "scan": 39 flags, err := parseFlags(args[2:]) 40 if err != nil { 41 log.Errorf("Error parsing CLI args: %v", err) 42 return 1 43 } 44 return scanrunner.RunScan(flags) 45 default: 46 // Assume 'scan' if subcommand is not recognized/specified. 47 flags, err := parseFlags(args[1:]) 48 if err != nil { 49 log.Errorf("Error parsing CLI args: %v", err) 50 return 1 51 } 52 return scanrunner.RunScan(flags) 53 } 54 } 55 56 func parseFlags(args []string) (*cli.Flags, error) { 57 fs := flag.NewFlagSet("scalibr", flag.ExitOnError) 58 printVersion := fs.Bool("version", false, `Prints the version of the scanner`) 59 root := fs.String("root", "", `The root dir used by detectors and by file walking during extraction (e.g.: "/", "c:\" or ".")`) 60 resultFile := fs.String("result", "", "The path of the output scan result file") 61 var output cli.Array 62 fs.Var(&output, "o", "The path of the scanner outputs in various formats, e.g. -o textproto=result.textproto -o spdx23-json=result.spdx.json -o cdx-json=result.cyclonedx.json") 63 pluginsToRun := cli.NewStringListFlag(nil) 64 fs.Var(&pluginsToRun, "plugins", "Comma-separated list of plugin to run") 65 var extractorOverride cli.Array 66 fs.Var(&extractorOverride, "extractor-override", `Override extractor for files matching a glob pattern. Format: <plugin-name>:<glob-pattern>. Can be specified multiple times.`) 67 extractorsToRun := cli.NewStringListFlag(nil) 68 fs.Var(&extractorsToRun, "extractors", "[Legacy field, prefer using --plugins instead] Comma-separated list of extractor plugins to run") 69 detectorsToRun := cli.NewStringListFlag(nil) 70 fs.Var(&detectorsToRun, "detectors", "[Legacy field, prefer using --plugins instead] Comma-separated list of detectors plugins to run") 71 annotatorsToRun := cli.NewStringListFlag(nil) 72 // TODO(b/400910349): Remove once integrators stop using this CLI arg. 73 fs.Var(&annotatorsToRun, "annotators", "[Legacy field, prefer using --plugins instead] Comma-separated list of annotators plugins to run") 74 var pluginCFG cli.Array 75 fs.Var(&pluginCFG, "plugin-config", "Plugin-specific config values. Example: --plugin-config=\"max_file_size_bytes:10000000 plugin_specific: {go_binary: {version_from_content: true} }\", or --plugin-config=go_binary:{version_from_content:true}. See binary/proto/config.proto for more settings") 76 ignoreSubDirs := fs.Bool("ignore-sub-dirs", false, "Non-recursive mode: Extract only the files in the top-level directory and skip sub-directories") 77 var dirsToSkip cli.StringListFlag 78 fs.Var(&dirsToSkip, "skip-dirs", "Comma-separated list of file paths to avoid traversing") 79 skipDirRegex := fs.String("skip-dir-regex", "", "If the regex matches a directory, it will be skipped. The regex is matched against the absolute file path.") 80 skipDirGlob := fs.String("skip-dir-glob", "", "If the glob matches a directory, it will be skipped. The glob is matched against the absolute file path.") 81 maxFileSize := fs.Int("max-file-size", 0, "Files larger than this size in bytes are skipped. If 0, no limit is applied.") 82 useGitignore := fs.Bool("use-gitignore", false, "Skip files declared in .gitignore files in source repos.") 83 remoteImage := fs.String("remote-image", "", "The remote image to scan. If specified, SCALIBR pulls and scans this image instead of the local filesystem.") 84 imageTarball := fs.String("image-tarball", "", "The path to a tarball containing a container image. These are commonly procuded using `docker save`. If specified, SCALIBR scans this image instead of the local filesystem.") 85 imageDockerLocal := fs.String("image-local-docker", "", "The docker image that is available in the local filesystem. These are the images from the output of \"docker image ls\". If specified, SCALIBR scans this image. The name of the image MUST also include the tag of the image <image_name>:<image_tag>.") 86 imagePlatform := fs.String("image-platform", "", "The platform of the remote image to scan. If not specified, the platform of the client is used. Format is os/arch (e.g. linux/arm64)") 87 spdxDocumentName := fs.String("spdx-document-name", "", "The 'name' field for the output SPDX document") 88 spdxDocumentNamespace := fs.String("spdx-document-namespace", "", "The 'documentNamespace' field for the output SPDX document") 89 spdxCreators := fs.String("spdx-creators", "", "The 'creators' field for the output SPDX document. Format is --spdx-creators=creatortype1:creator1,creatortype2:creator2") 90 cdxComponentName := fs.String("cdx-component-name", "", "The 'metadata.component.name' field for the output CDX document") 91 cdxComponentType := fs.String("cdx-component-type", "", "The 'metadata.component.type' field for the output CDX document") 92 cdxComponentVersion := fs.String("cdx-component-version", "", "The 'metadata.component.version' field for the output CDX document") 93 cdxAuthors := fs.String("cdx-authors", "", "The 'authors' field for the output CDX document. Format is --cdx-authors=author1,author2") 94 verbose := fs.Bool("verbose", false, "Enable this to print debug logs") 95 explicitPlugins := fs.Bool("explicit-plugins", false, "If set, the program will exit with an error if not all plugins' required plugins are explicitly enabled.") 96 filterByCapabilities := fs.Bool("filter-by-capabilities", true, "If set, plugins whose requirements (network access, OS, etc.) aren't satisfied by the scanning environment will be silently disabled instead of throwing a validation error.") 97 windowsAllDrives := fs.Bool("windows-all-drives", false, "Scan all drives on Windows") 98 offline := fs.Bool("offline", false, "Offline mode: Run only plugins that don't require network access") 99 100 if err := fs.Parse(args); err != nil { 101 return nil, err 102 } 103 pathsToExtract := fs.Args() 104 105 flags := &cli.Flags{ 106 PrintVersion: *printVersion, 107 Root: *root, 108 ResultFile: *resultFile, 109 Output: output, 110 PluginsToRun: pluginsToRun.GetSlice(), 111 ExtractorOverride: extractorOverride, 112 ExtractorsToRun: extractorsToRun.GetSlice(), 113 DetectorsToRun: detectorsToRun.GetSlice(), 114 AnnotatorsToRun: annotatorsToRun.GetSlice(), 115 PluginCFG: pluginCFG, 116 PathsToExtract: pathsToExtract, 117 IgnoreSubDirs: *ignoreSubDirs, 118 DirsToSkip: dirsToSkip.GetSlice(), 119 SkipDirRegex: *skipDirRegex, 120 SkipDirGlob: *skipDirGlob, 121 MaxFileSize: *maxFileSize, 122 UseGitignore: *useGitignore, 123 RemoteImage: *remoteImage, 124 ImageLocal: *imageDockerLocal, 125 ImageTarball: *imageTarball, 126 ImagePlatform: *imagePlatform, 127 SPDXDocumentName: *spdxDocumentName, 128 SPDXDocumentNamespace: *spdxDocumentNamespace, 129 SPDXCreators: *spdxCreators, 130 CDXComponentName: *cdxComponentName, 131 CDXComponentType: *cdxComponentType, 132 CDXComponentVersion: *cdxComponentVersion, 133 CDXAuthors: *cdxAuthors, 134 Verbose: *verbose, 135 ExplicitPlugins: *explicitPlugins, 136 FilterByCapabilities: *filterByCapabilities, 137 WindowsAllDrives: *windowsAllDrives, 138 Offline: *offline, 139 } 140 if err := cli.ValidateFlags(flags); err != nil { 141 return nil, err 142 } 143 return flags, nil 144 }