Thanks for your interest in bpfcompat. This document is the short, opinionated version of how to work with the codebase.
- Security disclosures go through
SECURITY.md, not public issues. If you've found a vulnerability, please email the address listed there and wait for a coordinated disclosure window before publishing. - Tests are mandatory for behavior changes. The CI gate runs
go test -race,go vet,golangci-lint, andgovulncheck. Bench/fuzz additions are welcome but not required for every PR. - No
panic()in production code. The only acceptable process-terminating call isos.Exitfromcmd/bpfcompat/main.go. - Don't loosen the JSON body cap or DisallowUnknownFields. They're load
bearing for the API version contract (see
docs/openapi.yamland the/api/v1/move). Changes that need a richer wire shape should ride av2route, not relax the v1 one.
make build # produces bin/bpfcompat with version ldflags
make validator-static # builds the C validator (needs libbpf-dev + clang)
make test # go test ./...
make openapi-sync # copies docs/openapi.yaml into the embed locationRun the API server locally:
BPFCOMPAT_API_WRITE_KEY=dev-key \
BPFCOMPAT_API_ENABLE_METRICS=true \
BPFCOMPAT_LOG_LEVEL=debug \
BPFCOMPAT_LOG_FORMAT=text \
./bin/bpfcompat serve --addr 127.0.0.1:8080For VM-backed validation you'll need qemu-system-x86_64, qemu-img,
ssh, scp, jq, pkg-config, libbpf-dev, and /dev/kvm. make doctor
checks for them.
- Open an issue (or comment on an existing one) describing the change before you start a non-trivial PR. Security-adjacent changes especially benefit from an early design conversation.
- Branch from
main. Keep PRs focused — one logical change per PR. - Run
golangci-lint run --new-from-rev=origin/mainlocally before pushing. Pre-existing lint debt is tracked separately; new code should be clean. - Update
CHANGELOG.mdunder the[Unreleased]heading with a one-line summary of your change. Categorize as Added / Changed / Fixed / Security. - If you touch
docs/openapi.yaml, runmake openapi-syncand commit the updatedinternal/api/openapi_spec.yaml. CI fails on drift.
gofmt+goimportsenforced viagolangci-lint.- Public types and exported functions need at least a one-line doc comment.
- Comments explain why, not what. Don't repeat the code in English. Surrounding context (related security finding, historical bug, related design decision) is what we want to capture.
- Tests live next to the code (
foo.go↔foo_test.go). Integration tests that span packages can live underinternal/<pkg>/integration. - Errors: wrap with
%wand surface domain sentinels (registry.ErrNotFound,cloudregistry.ErrUnauthorized) so handlers can map to status codes without string matching.
Imperative mood, capitalized first line under ~70 characters, optional body wrapped at 80. Reference the issue number when relevant. Example:
api: refuse new validate submissions during shutdown drain (#42)
Bind the global shutting flag at the top of handleValidateStart so callers
get a clean 503 instead of starting a job we're about to cancel mid-flight.
Goroutines launched before the flag flipped continue to a normal terminal
state and drain via inflight.WaitGroup.
- Register via
registerAPIRoute(mux, "/your/route", handler)so both/api/v1/your/routeand the legacy/api/your/routeget the same handler. - Pick the right auth gate:
- State change →
requireWriteAuthorizationForAction(w, r, "your_action") - Read-only →
requireReadAuthorizationForAction(w, r, "your_action")
- State change →
- Use
decodeJSONBody(w, r, &req)for JSON bodies — neverjson.NewDecoderdirectly (the helper enforces size/unknown-field/smuggling rules). - Record the route in
docs/openapi.yamland re-runmake openapi-sync. - Add a tests file that exercises the auth gate, the happy path, and at least one error path.
- If the handler triggers a runtime side effect (fetch, execute, registry
change), bump the corresponding metric counter via the helpers in
internal/api/metrics.go.
- Define the constant in the package that consumes it (don't centralize — the consumer documents the semantics).
- Surface the default + description in the env reference (
docs/env-reference.md) and viabpfcompat env. - Document any operational risk (e.g.
BPFCOMPAT_FETCH_ALLOW_INTERNAL_HOSTScarries an SSRF unlock) inSECURITY.mdunder the hardening guidance section.
By submitting a contribution you agree to license it under the terms in
LICENSE (Apache-2.0). See the appendix in that file for the
required boilerplate header on new source files.