Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,9 @@ Use `--config <path>` to add an explicit config file. See the generated [Config
Managed plugins let you add detectors, matchers, and auditors without forking Bomly:

```bash
bomly plugin install github:bomly-dev/bomly-plugin-bun-lock-detector@v0.1.0
bomly plugin enable bomly.examples.detector.bun-lock
bomly plugin verify bomly.examples.detector.bun-lock
bomly plugins install github:bomly-dev/bomly-plugin-bun-lock-detector@v0.1.0
bomly plugins enable bomly.examples.detector.bun-lock
bomly plugins verify bomly.examples.detector.bun-lock
```

See [Plugins](docs/PLUGINS.md) for install, trust, and authoring guidance.
Expand Down
2 changes: 1 addition & 1 deletion dev-docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ Bomly uses a hybrid plugin model:

- Built-in detectors, matchers, and auditors stay in-process by default.
- External managed plugins are installed into `~/.bomly/plugins`.
- Runtime preparation loads enabled external plugins into the registry as adapters so the scan engine still owns orchestration. External plugins are disabled on install and become runnable only after `bomly plugin enable <id>`.
- Runtime preparation loads enabled external plugins into the registry as adapters so the scan engine still owns orchestration. External plugins are disabled on install and become runnable only after `bomly plugins enable <id>`.

Managed plugins currently expose the same three runtime roles as core components:

Expand Down
4 changes: 2 additions & 2 deletions docs/DETECTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ For example, the `npm` chain is `npm-detector` → `syft-detector`:
Per-ecosystem chains are listed in [`detectors/ecosystems/`](detectors/ecosystems/). The full live list lives in the CLI:

```bash
bomly plugin list --detectors
bomly plugin list --detectors --json
bomly plugins list --detectors
bomly plugins list --detectors --json
```

## Native vs. Syft
Expand Down
2 changes: 1 addition & 1 deletion docs/GLOSSARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,6 @@ The vocabulary Bomly uses, with one-sentence definitions and pointers to the doc

**Plugin** — An external binary that adds a detector, matcher, auditor, or analyzer over Bomly's v1 gRPC protocol. See [Plugins](PLUGINS.md).

**Built-in** — Components compiled into the Bomly binary. Listed by `bomly plugin list`.
**Built-in** — Components compiled into the Bomly binary. Listed by `bomly plugins list`.

**`bomly` vs. `bomly-lite`** — `bomly` ships with Syft and Grype linked in; `bomly-lite` shells out to external `syft` and `grype` on `PATH`. Same flags, same outputs.
4 changes: 2 additions & 2 deletions docs/MATCHERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ Bomly is **offline-safe by default**. Matchers that use the network only run whe
The full live list lives in the CLI:

```bash
bomly plugin list --matchers
bomly plugin list --matchers --json
bomly plugins list --matchers
bomly plugins list --matchers --json
```

## Running matchers
Expand Down
70 changes: 35 additions & 35 deletions docs/PLUGINS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Bomly plugins let you extend scans without changing the Bomly binary. Today, man
- **matchers** that enrich packages with vulnerabilities, licenses, lifecycle data, or other package metadata
- **auditors** that turn graph and registry data into findings or risk scores

External analyzer plugins are not supported yet. `bomly plugin list --analyzers` can show built-in reachability analyzers, but the external plugin runtime currently serves only detectors, matchers, and auditors through `sdk.ServeDetector`, `sdk.ServeMatcher`, and `sdk.ServeAuditor`.
External analyzer plugins are not supported yet. `bomly plugins list --analyzers` can show built-in reachability analyzers, but the external plugin runtime currently serves only detectors, matchers, and auditors through `sdk.ServeDetector`, `sdk.ServeMatcher`, and `sdk.ServeAuditor`.

## Start Here

Expand Down Expand Up @@ -55,10 +55,10 @@ Plugins do not get install hooks, post-install scripts, or automatic execution f
Installed external plugins are disabled by default. They do not participate in scans until you enable them:

```bash
bomly plugin enable <plugin-id>
bomly plugins enable <plugin-id>
```

Treat `bomly plugin enable` as the trust decision. When enabled, a plugin runs with the same user-level privileges as the Bomly process. It can read and write files, make network connections, spawn child processes, and access environment variables available to that user.
Treat `bomly plugins enable` as the trust decision. When enabled, a plugin runs with the same user-level privileges as the Bomly process. It can read and write files, make network connections, spawn child processes, and access environment variables available to that user.

Repository-declared plugins are never executed automatically. The host must explicitly install and enable the plugin before it can run.

Expand All @@ -71,81 +71,81 @@ git clone git@github.com:bomly-dev/bomly-plugin-bun-lock-detector.git
cd bomly-plugin-bun-lock-detector
go test ./...
go build -o ./bin/bomly-plugin-bun-lock-detector .
bomly plugin install ./bin/bomly-plugin-bun-lock-detector --dev
bomly plugin enable bomly.examples.detector.bun-lock
bomly plugins install ./bin/bomly-plugin-bun-lock-detector --dev
bomly plugins enable bomly.examples.detector.bun-lock
bomly scan --path ./my-bun-project --detectors bomly.examples.detector.bun-lock
```

The matcher and auditor examples use the same workflow:

```bash
bomly plugin enable clearlydefined-license-matcher
bomly plugins enable clearlydefined-license-matcher
bomly scan --enrich --matchers +clearlydefined-license-matcher

bomly plugin enable bomly.examples.auditor.meme-deps
bomly plugins enable bomly.examples.auditor.meme-deps
bomly scan --audit --auditors +bomly.examples.auditor.meme-deps
```

Check that Bomly can see any installed plugin:

```bash
bomly plugin list --external
bomly plugin info <plugin-id>
bomly plugin verify <plugin-id>
bomly plugin test <plugin-id>
bomly plugin doctor <plugin-id>
bomly plugins list --external
bomly plugins info <plugin-id>
bomly plugins verify <plugin-id>
bomly plugins test <plugin-id>
bomly plugins doctor <plugin-id>
```

Disable or uninstall it later:

```bash
bomly plugin disable <plugin-id>
bomly plugin uninstall <plugin-id>
bomly plugins disable <plugin-id>
bomly plugins uninstall <plugin-id>
```

## Common Commands

List plugins:

```bash
bomly plugin list
bomly plugin list --external
bomly plugin list --detectors
bomly plugin list --matchers --json
bomly plugin list --auditors
bomly plugins list
bomly plugins list --external
bomly plugins list --detectors
bomly plugins list --matchers --json
bomly plugins list --auditors
```

Show one plugin:

```bash
bomly plugin info <plugin-id>
bomly plugin info <plugin-id> --json
bomly plugins info <plugin-id>
bomly plugins info <plugin-id> --json
```

Install a plugin:

```bash
bomly plugin install ./dist/bomly-plugin-example.tar.gz
bomly plugin install ./bin/bomly-plugin-example --dev
bomly plugin install https://example.com/bomly-plugin-example.tar.gz --checksum sha256:...
bomly plugin install https://example.com/bomly-plugin-example.tar.gz --insecure-skip-checksum
bomly plugin install github:bomly-dev/bomly-plugin-bun-lock-detector@v0.1.0
bomly plugins install ./dist/bomly-plugin-example.tar.gz
bomly plugins install ./bin/bomly-plugin-example --dev
bomly plugins install https://example.com/bomly-plugin-example.tar.gz --checksum sha256:...
bomly plugins install https://example.com/bomly-plugin-example.tar.gz --insecure-skip-checksum
bomly plugins install github:bomly-dev/bomly-plugin-bun-lock-detector@v0.1.0
```

Check a plugin:

```bash
bomly plugin verify <plugin-id> # manifest, checksum, binary, runtime descriptor
bomly plugin test <plugin-id> # runtime readiness
bomly plugin doctor <plugin-id> # verify + test
bomly plugins verify <plugin-id> # manifest, checksum, binary, runtime descriptor
bomly plugins test <plugin-id> # runtime readiness
bomly plugins doctor <plugin-id> # verify + test
```

Enable, disable, or remove a plugin:

```bash
bomly plugin enable <plugin-id>
bomly plugin disable <plugin-id>
bomly plugin uninstall <plugin-id>
bomly plugins enable <plugin-id>
bomly plugins disable <plugin-id>
bomly plugins uninstall <plugin-id>
```

## Select Plugins During A Scan
Expand Down Expand Up @@ -266,7 +266,7 @@ For private GitHub Releases, set one of these environment variables before insta
```bash
export BOMLY_GITHUB_TOKEN=<token-with-release-access>
# Also accepted: GITHUB_TOKEN, GH_TOKEN, GITHUB_AUTH_TOKEN
bomly plugin install github:bomly-dev/bomly-plugin-bun-lock-detector@v0.1.0
bomly plugins install github:bomly-dev/bomly-plugin-bun-lock-detector@v0.1.0
```

Bomly attaches the token only to `github:owner/repo@tag` metadata, checksum, and asset downloads. Direct URL installs do not receive GitHub auth headers.
Expand Down Expand Up @@ -303,7 +303,7 @@ External plugins are native OS subprocesses. They are not sandboxed, not contain
**Recommended practices:**

- Always supply `--checksum` for direct URL installs.
- Run `bomly plugin verify <id>` before enabling any plugin installed from an external source.
- Treat `bomly plugin enable` as the explicit trust decision for granting execution privileges.
- Run `bomly plugins verify <id>` before enabling any plugin installed from an external source.
- Treat `bomly plugins enable` as the explicit trust decision for granting execution privileges.
- Prefer `github:owner/repo@tag` installs when releases publish `SHA256SUMS`.
- Do not enable plugins you did not build or obtain from a source you control.
10 changes: 5 additions & 5 deletions docs/plugins/how-to-implement-auditor.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ For development, build and install the binary directly:

```bash
go build -o ./bin/bomly-plugin-meme-auditor .
bomly plugin install ./bin/bomly-plugin-meme-auditor --dev
bomly plugin enable bomly.examples.auditor.meme-deps
bomly plugins install ./bin/bomly-plugin-meme-auditor --dev
bomly plugins enable bomly.examples.auditor.meme-deps
```

For distribution, package a package-only `bomly-plugin.json` manifest with the binary:
Expand All @@ -157,9 +157,9 @@ The manifest contains package and install fields only. Bomly probes the binary a
Check installation and runtime readiness:

```bash
bomly plugin verify bomly.examples.auditor.meme-deps
bomly plugin test bomly.examples.auditor.meme-deps
bomly plugin doctor bomly.examples.auditor.meme-deps
bomly plugins verify bomly.examples.auditor.meme-deps
bomly plugins test bomly.examples.auditor.meme-deps
bomly plugins doctor bomly.examples.auditor.meme-deps
```

Run only this auditor:
Expand Down
10 changes: 5 additions & 5 deletions docs/plugins/how-to-implement-detector.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ For development, build and install the binary directly:

```bash
go build -o ./bin/bomly-plugin-bun-lock-detector .
bomly plugin install ./bin/bomly-plugin-bun-lock-detector --dev
bomly plugin enable bomly.examples.detector.bun-lock
bomly plugins install ./bin/bomly-plugin-bun-lock-detector --dev
bomly plugins enable bomly.examples.detector.bun-lock
```

For distribution, package a package-only `bomly-plugin.json` manifest with the binary:
Expand All @@ -148,9 +148,9 @@ The manifest contains package and install fields only: ID, kind, version, runtim
Check installation and runtime readiness:

```bash
bomly plugin verify bomly.examples.detector.bun-lock
bomly plugin test bomly.examples.detector.bun-lock
bomly plugin doctor bomly.examples.detector.bun-lock
bomly plugins verify bomly.examples.detector.bun-lock
bomly plugins test bomly.examples.detector.bun-lock
bomly plugins doctor bomly.examples.detector.bun-lock
```

Run only this detector:
Expand Down
10 changes: 5 additions & 5 deletions docs/plugins/how-to-implement-matcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ For development, build and install the binary directly:

```bash
go build -o ./bin/bomly-plugin-clearlydefined-matcher .
bomly plugin install ./bin/bomly-plugin-clearlydefined-matcher --dev
bomly plugin enable clearlydefined-license-matcher
bomly plugins install ./bin/bomly-plugin-clearlydefined-matcher --dev
bomly plugins enable clearlydefined-license-matcher
```

For distribution, package a package-only `bomly-plugin.json` manifest with the binary:
Expand All @@ -163,9 +163,9 @@ The manifest contains package and install fields only. Bomly probes the binary a
Check installation and runtime readiness:

```bash
bomly plugin verify clearlydefined-license-matcher
bomly plugin test clearlydefined-license-matcher
bomly plugin doctor clearlydefined-license-matcher
bomly plugins verify clearlydefined-license-matcher
bomly plugins test clearlydefined-license-matcher
bomly plugins doctor clearlydefined-license-matcher
```

Run only this matcher during enrichment:
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/help_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func optionValuesHelpSection(cmd *cobra.Command) string {
return ""
}

return "\n\nExplore available detectors, matchers, and auditors with `bomly plugin list`."
return "\n\nExplore available detectors, matchers, and auditors with `bomly plugins list`."
}

func exitCodesHelpSection(cmd *cobra.Command) string {
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/help_cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestOptionValuesHelpSection(t *testing.T) {

cmd.Flags().String("ecosystems", "", "")
got := optionValuesHelpSection(cmd)
if !strings.Contains(got, "bomly plugin list") {
if !strings.Contains(got, "bomly plugins list") {
t.Fatalf("expected plugin list hint, got %q", got)
}
}
Expand Down
15 changes: 8 additions & 7 deletions internal/cli/plugin_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ import (

func newPluginCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "plugin",
Short: "Manage Bomly managed plugins",
Example: " bomly plugin list --all\n" +
" bomly plugin info osv",
Use: "plugins",
Aliases: []string{"plugin"},
Short: "Manage Bomly managed plugins",
Example: " bomly plugins list --all\n" +
" bomly plugins info osv",
}
cmd.AddCommand(
newPluginListCmd(),
Expand Down Expand Up @@ -55,7 +56,7 @@ func newPluginListCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "List built-in and installed plugins",
Example: " bomly plugin list --detectors\n bomly plugin list --external --json",
Example: " bomly plugins list --detectors\n bomly plugins list --external --json",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
options, err := commandOptions(cmd)
Expand Down Expand Up @@ -176,7 +177,7 @@ func newPluginInfoCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "info <id>",
Short: "Show plugin metadata",
Example: " bomly plugin info osv\n bomly plugin info npm-native --json",
Example: " bomly plugins info osv\n bomly plugins info npm-native --json",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
options, err := commandOptions(cmd)
Expand Down Expand Up @@ -910,7 +911,7 @@ func pluginInfoPackageManagers(info managedplugin.Info) []plugschema.PackageMana

// pluginInfoLanguages returns the SupportedLanguages list for plugin
// kinds that carry one. Today only Analyzer plugins do; other kinds
// return nil so `bomly plugin info` cleanly omits the Languages line.
// return nil so `bomly plugins info` cleanly omits the Languages line.
func pluginInfoLanguages(info managedplugin.Info) []plugschema.Language {
if info.Kind == plugschema.PluginKindAnalyzer && info.AnalyzerDescriptor != nil {
return append([]plugschema.Language(nil), info.AnalyzerDescriptor.SupportedLanguages...)
Expand Down
20 changes: 20 additions & 0 deletions internal/cli/plugin_cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,26 @@ func assertInOrder(t *testing.T, value string, parts []string) {
}
}

func TestPluginCommandAlias(t *testing.T) {
root := newPluginTestRoot(t)

plural, _, err := root.Find([]string{"plugins"})
if err != nil {
t.Fatalf("root.Find(plugins) error = %v", err)
}
if plural.Name() != "plugins" {
t.Fatalf("expected canonical command name %q, got %q", "plugins", plural.Name())
}

singular, _, err := root.Find([]string{"plugin"})
if err != nil {
t.Fatalf("root.Find(plugin) error = %v", err)
}
if singular != plural {
t.Fatal("expected the plugin alias to resolve to the plugins command")
}
}

func newPluginTestRoot(t *testing.T) *cobra.Command {
t.Helper()
t.Setenv("HOME", t.TempDir())
Expand Down
14 changes: 10 additions & 4 deletions internal/cli/root_cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ func TestRootHelp_IncludesAvailableOptionValuesSection(t *testing.T) {
t.Fatalf("expected help output to contain %q, got:\n%s", expected, helpText)
}
}
if strings.Contains(helpText, "Explore available detectors, matchers, and auditors with `bomly plugin list`.") {
if strings.Contains(helpText, "Explore available detectors, matchers, and auditors with `bomly plugins list`.") {
t.Fatalf("expected root help output to omit selector guidance, got:\n%s", helpText)
}
for _, nonGlobal := range []string{"--enrich", "--audit", "--analyze", "--ecosystems", "--detectors"} {
Expand Down Expand Up @@ -423,7 +423,7 @@ func TestRootHelp_CommandExamplesRender(t *testing.T) {
"bomly scan -o spdx=bomly.spdx.json",
"bomly scan --url https://github.com/bomly-dev/bomly-cli --ref main --json",
"bomly scan --container alpine:3.20",
"Explore available detectors, matchers, and auditors with `bomly plugin list`.",
"Explore available detectors, matchers, and auditors with `bomly plugins list`.",
},
notInText: []string{"Exit Codes:"},
},
Expand All @@ -440,9 +440,15 @@ func TestRootHelp_CommandExamplesRender(t *testing.T) {
notInText: []string{"Exit Codes:"},
},
{
name: "plugin",
name: "plugins",
args: []string{"plugins", "--help"},
examples: []string{"Examples:", "bomly plugins list --all"},
notInText: []string{"Exit Codes:"},
},
{
name: "plugin-alias",
args: []string{"plugin", "--help"},
examples: []string{"Examples:", "bomly plugin list --all"},
examples: []string{"Examples:", "bomly plugins list --all"},
notInText: []string{"Exit Codes:"},
},
}
Expand Down
Loading