Skip to content

feat: build settings by allow-list, node architecture, go_build payload (ADR 0019) - #45

Merged
kfeofantov merged 1 commit into
mainfrom
feat/build-settings-and-node-arch
Aug 22, 2026
Merged

kfeofantov merged 1 commit into
mainfrom
feat/build-settings-and-node-arch

Conversation

@kfeofantov

Copy link
Copy Markdown
Contributor

Slice: the build-settings allow-list, node_metadata.architecture, and the go_dependencies → go_build rename. ADR 0019 in this PR.

What was wrong

internal/nodescan read the whole build-settings block of every kept binary and threw all but one bit of it away — hasPGO returned a boolean, everything else was discarded. What was discarded is what decides whether a Go workload can be advised: GOAMD64 (a v1 binary on a v3 fleet leaves instructions unused), CGO_ENABLED, -race (multiples of CPU and memory in production), and vcs.* (which commit, and whether the tree was dirty).

Allow-list, not deny-list

Build settings are the one place where strings a person typed into a CI pipeline enter the agent. This repository's own image carries:

build	-ldflags="-X main.version=a5edd4b-dirty"
build	-pgo=/home/jenkins/workspace/.../default.pgo   ← an absolute path on the build machine

And the key set belongs to the Go toolchain, which may grow it in any release. A deny-list protects only against the keys we thought to name. The filter lives in the scanner, so nothing outside the list crosses the node→controller channel (invariant 4).

Kept: CGO_ENABLED, GOARCH, GOAMD64, GOARM64, GOARM, -race, -trimpath, vcs, vcs.revision, vcs.time, vcs.modified. A value beyond 128 chars is dropped whole, never truncated — a prefix of an unexpected string is still an unexpected string, and would ship looking legitimate.

Rename

go_dependencies already carried go_version and main_module; it was facts about a build from the day it shipped, and settings made the name plainly wrong. No backend consumes it yet, so this costs a golden file now instead of a protocol migration later. inventory.BuildDependencies → BuildFacts, spool file go-build-<digest>.json.

ADR 0018 names the old method names and is not edited — accepted ADRs are immutable; ADR 0019 carries the forwarding address.

vcs.* and why its absence is normal

The toolchain stamps it only when three conditions hold in a container build: .git in the build context, git in the builder image, and matching ownership. The last fails loudly — COPY . . then USER nonroot makes go build error out, not skip silently, and the usual response (-buildvcs=false) removes the stamp permanently. ADR 0019 records this, and backend-requirements.md requires the backend not to treat a missing vcs.* as a coverage gap.

Verified against real images from this repo: the agent image carries vcs.revision and vcs.modified=true; the e2e sample (context test/e2e/sample/, no .git) carries no vcs.* at all.

Node architecture

GOARCH is not a finding on its own — it is one half of a comparison, and the other half existed nowhere in the agent's data. One field from an object already watched: no new informer, no new RBAC.

Verification

  • make test (incl. go vet -tags e2e ./...) and make lint green.
  • make inventory-e2e in kind: PASS, 122.78s, with the settings assertion from a real cluster:
    inventory_test.go:162: sample build settings: map[CGO_ENABLED:0 GOARCH:arm64 GOARM64:v8.0]
    
    No vcs.* (as documented), no -ldflags, no -pgo, no -buildmode. The e2e restates the allow-list independently, so widening it in the scanner alone cannot silently widen what leaves a cluster.
  • Nothing changed after the image was built, so the run matches this commit exactly.

Docs updated in the same PR per CLAUDE.md: security.md §8 enumerates the allow-list in full and names what is dropped; backend-requirements.md gets the go_build ingest rules, the optional-keys rule, and the architecture join.

🤖 Generated with Claude Code

…ad (ADR 0019)

The scanner read every binary's build-settings block and kept one bit of it
(the PGO boolean), discarding the facts that decide whether a Go workload can
be advised at all: microarchitecture level, CGO, race builds, and the commit a
binary was built from.

Keep an allow-listed subset on the node, before the channel: CGO_ENABLED,
GOARCH, GOAMD64, GOARM64, GOARM, -race, -trimpath and vcs.*. Allow-list rather
than deny-list because build settings are the one place where operator-written
strings enter the agent — a real -ldflags carries build-machine paths and
internal hostnames, -pgo carries a path — and because the toolchain owns the
key set and may grow it in any release. An over-long value is dropped whole
rather than truncated.

Rename the ADR 0017 payload go_dependencies -> go_build, with settings
alongside modules: it already carried go_version and main_module, so it was
facts about a build from the day it shipped. No backend consumes it yet, so the
rename costs a golden file now instead of a migration later.

Add node_metadata.nodes[].architecture, read from an object already watched.
GOARCH is not a finding on its own — it is one half of a comparison, and the
other half did not exist anywhere in the agent's data.

Verified in kind: the sample build ships CGO_ENABLED=0, GOARCH=arm64,
GOARM64=v8.0 and no vcs.* — its build context holds no .git, which ADR 0019
documents as the common case for containerized builds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@kfeofantov
kfeofantov merged commit d0b0681 into main Aug 22, 2026
3 checks passed
@kfeofantov
kfeofantov deleted the feat/build-settings-and-node-arch branch August 22, 2026 11:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant