How To Implement An Auditor Plugin
Last updated July 30, 2026View source (v0.21.1)
An auditor plugin evaluates the dependency graph and package registry after detection and optional enrichment. Use an auditor when you want to produce findings, risk scores, or policy-style decisions from data Bomly already has.
External auditor plugins are served with sdk.ServeAuditor.
The Bomly SDK API reference documents the sdk.ServeAuditor entrypoint, sdk.ServedAuditor interface, sdk.AuditRequest, sdk.AuditResult, reference-style findings, and risk-score types used below.
Minimum Shape
Create a Go main package that imports the Bomly SDK:
package main
import (
"context"
"github.com/bomly-dev/bomly-cli/sdk"
)
const pluginID = "bomly.examples.auditor.meme-deps"
type auditor struct{}
func (a *auditor) Descriptor(context.Context) (*sdk.AuditorDescriptor, error) {
return &sdk.AuditorDescriptor{
Name: pluginID,
DisplayName: "Meme Dependency Auditor",
Aliases: []string{"meme-deps"},
Tags: []string{"policy", "meme"},
}, nil
}
func (a *auditor) Ready(context.Context, *sdk.AuditRequest) (*sdk.ReadyResponse, error) {
return &sdk.ReadyResponse{Ready: true}, nil
}
func (a *auditor) Applicable(context.Context, *sdk.AuditRequest) (*sdk.ApplicableResponse, error) {
return &sdk.ApplicableResponse{Applicable: true}, nil
}
func (a *auditor) Audit(ctx context.Context, req *sdk.AuditRequest) (*sdk.AuditResponse, error) {
finding := sdk.Finding{
ID: "security-team-policy-example",
Kind: sdk.FindingKindPackage,
PackageRef: "pkg:npm/lodash@4.17.21",
PolicyStatus: sdk.FindingPolicyStatusWarn,
Title: "Dependency has unusually high meme density",
Source: pluginID,
}
return &sdk.AuditResponse{
Findings: []sdk.Finding{finding},
AuditorRuns: []string{pluginID},
AuditorFindings: map[string]int{pluginID: 1},
}, nil
}
func main() {
sdk.ServeAuditor(&auditor{})
}
The working example repo is bomly-plugin-meme-auditor. It shows a small auditor that reads graph nodes and emits reference-style package findings.
What Each Hook Does
Descriptordescribes the component identity, display name, aliases, tags, and support.Readyreports whether the plugin can run in the current environment.Applicablereports whether the auditor should run for the current request.Auditreadssdk.AuditRequestand returns findings, risk scores, and run metadata.
Read Graph And Registry Data
Bomly gives auditors the same core scan data used by built-in auditors:
req.Graphcontains dependency nodes and edges.req.Registrycontains package records keyed by PURL.req.BaselineGraphmay be present for diff-style workflows.req.Targetmay be present when a command focuses on one dependency.req.DependencyDetailChangescontains the canonical head-side dependency detail transitions during a diff audit. It is empty for scans, explains, and the base side of a diff. This optional protocol-v1 field may be absent when an older core calls the plugin.
Auditors should emit reference-style findings that point at registry packages by PURL:
finding := sdk.Finding{
ID: "GHSA-example",
Kind: sdk.FindingKindVulnerability,
PackageRef: "pkg:npm/lodash@4.17.21",
VulnerabilityID: "GHSA-example",
PolicyStatus: sdk.FindingPolicyStatusFail,
Source: pluginID,
}
Do not copy full package or vulnerability records into findings. Keep the finding focused on the decision and references.
Configuration And HTTP
Per-plugin config lives under plugins.<plugin-id>:
plugins:
bomly.examples.auditor.meme-deps:
extra_packages:
- totally-not-suspicious
Read it with:
type config struct {
PolicyFile string `json:"policy_file"`
}
var cfg config
if err := sdk.DecodePluginConfigFromEnv(&cfg); err != nil {
return nil, err
}
Auditors should normally evaluate data already present in req.Graph and req.Registry. If an auditor intentionally calls an external service, document that behavior and use Bomly's SDK HTTP provider so proxy settings work consistently:
provider, err := sdk.NewHTTPClientProviderFromEnv()
if err != nil {
return nil, err
}
client := provider.Client(20 * time.Second)
_ = client
Package And Install
For development, build and install the binary directly:
go build -o ./bin/bomly-plugin-meme-auditor .
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:
bomly-plugin.json
bin/
bomly-plugin-meme-auditor
README.md
The manifest contains package and install fields only. Bomly probes the binary at install time, verifies descriptor.name == manifest.id, and writes its own internal descriptor snapshot for plugin list, selectors, verification, and runtime registration.
Test It
Check installation and runtime readiness:
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:
bomly scan --path ./my-project --audit --auditors bomly.examples.auditor.meme-deps --json
Or add it to the default auditor set:
bomly scan --path ./my-project --audit --auditors +bomly.examples.auditor.meme-deps
Implementation Checklist
- Read
req.Graphandreq.Registry; emit reference-style findings. - Return
AuditorRunswith the auditor ID. - Use actionable finding summaries and clear policy statuses.
- Avoid external network calls unless the plugin explicitly documents them.
- Wrap errors with useful context and avoid panics.
- Do not log secrets, tokens, or credentials.
- Add unit tests for policy evaluation and finding construction.