feat(image): build OCI layouts from staged binaries - #15
Merged
Conversation
Replace OB-08 through OB-17 of go-oci-build.yml with `release-cli image build`, and have `stage --profile go` persist the artifact-local oci-build-inputs projection its first downstream reader now consumes. The old YAML verifier (OB-18 to OB-21) stays as an independent migration oracle: its script is byte-identical to main, only its step-output references moved. PR 9 replaces it. Ports 11 and 12 of the closed budget arrive as thin melange and apko exec adapters with byte-identical argv. Verified against the real pinned tools plus Docker: the unchanged verifier accepts the CLI's two-platform layout.
Every exec-adapter test wrote its POSIX shell fake into its own t.TempDir()
and immediately exec'd it. On Linux a parallel sibling's fork/exec inherits
the still-open write descriptor, so the exec fails with ETXTBSY ("text file
busy"). That is the real cause of the cancellation-test flake seen on macOS
under load and of the PR CI failure, reproduced with `go test ./...` in a
linux/amd64 golang:1.26 container.
TestMain now writes each package's fake exactly once before any test can
exec it. Per-test t.TempDir() still holds argv records, start markers,
stderr fixtures, and working directories.
gochecknoglobals joins the existing _test.go exclusion list because the
shared fixture path must be package scoped; the rule still covers
production code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR 8 of the eleven-PR
release-cliprogram (.journal/002/PLAN.md). Replaces inventory steps OB-08 through OB-17 ofgo-oci-build.ymlwith one tested Go command and fires the plan's deferred persisted-projection trigger.Scope
stage --profile gonow writesdist/oci-build-inputs.json(release.dev/oci-build-inputs/v1): profile plus, per Linux platform, the binary name, the artifact-root-relative path, and the canonical SHA-256 digest.goprof.SelectBinariesgained the shared-binary-name check the YAML used to perform, and the staging engine now hashes both canonical binaries. Thestage --jsonenvelope is unchanged.release-cli image buildstages both binaries into a scratch workspace (single streaming hash-and-copy pass, mode 0755), verifies each digest against the projection, verifies each staged file is a static 64-bit little-endianET_EXECfor its architecture withdebug/elf, writesvars.jsonandcanonical-binaries.sha256, copies both configs, builds signed APK repositories, requires exactly one nonempty.apkand a nonemptyAPKINDEX.tar.gzper architecture, copies the APK public key, composes the locked two-platform layout, and requires the lockfile, layout files, and both SBOMs to be nonempty.image.APKBuilder->internal/adapter/melange,image.Composer->internal/adapter/apko. Both are thin exec adapters with argv and working directories byte-identical to the YAML they replace, mockery-generated mocks, and bounded stderr tails. Port 13 (actenv) stays unbuilt: the workflow still reads the--jsonenvelope withjq.go-pre-publish.ymluploads the projection alongsideartifacts.json;go-oci-build.ymlreplaces three shell steps with oneimage build --jsonstep (id: build) that resolves the pinned Melange and apko binaries withmise whichand derives the build date from the tagged commit. No workflow input, output, permission, concurrency setting, timeout, or action pin changed.run:script ofVerify authoritative OCI imageis byte-identical tomain(verified by parsing both YAML documents); only itsenv:now readssteps.build.outputs.*. PR 9 replaces it.Verification
mise exec -- moon run root:check: format, lint, build, test, protocol stamp, and mock freshness all pass.stageprojection ->image build-> genuine two-platform layout. The unchanged YAML verifier, run insideubuntu:24.04with GNU tar 1.35, accepted the output and emitted animage-digestequal to an independentsha256sumoflayout/index.json. Layer inspection: mode 0755, uid/gid 0/0, executable bytes identical to both canonical inputs. Melange and apko argv were compared against the removed YAML line by line.ELF type ET_DYN, want ET_EXEC; amd64 bytes served as arm64 ->ELF machine EM_X86_64, want EM_AARCH64; populated work or output root -> refused; a second JSON value in the projection -> refused;--worknested in--output-> exit 2 before any directory is created; missing or non-RFC-3339--build-date, missingGITHUB_REF_NAME, missingGITHUB_SHA-> exit 2, one envelope, no directories created; success without--json-> zero stdout bytes.--worknested under--outputpublished the ephemeral APK private signing key inside the uploaded artifact. Round 2 re-verified every fix by execution and caught 15 of 15 mutations. Conformance audited all 24AGENTS.mdrules: 22 PASS, and the two FAIL verdicts (a false size-limit contract on the projection decoder, and three documented-versus-actual ordering claims) were fixed rather than documented away.examples/go-release'srelease-assetsjob granted less thango-pre-publish.ymldeclares, which fails a consumer run at startup with no API-visible diagnostic. Fixed here, along with the caller skeleton and permission tables indocs/reference/github-release-contract.mdand the builder grant sentence indocs/reference/oci-image-contract.md. All four caller jobs now match their callees exactly in this repo, the example, and the documented skeleton.cosign,ghup, andgitxadapter cancellation tests: fixture startup and the post-cancel bound now use separate budgets. No assertion weakened.Notes
*os.Rootfor the work and output roots; the plan forbids a filesystem port, andos.OpenRootstays at the CLI composition edge.execxpackage.