[stack] feat(release): signed managed-release pipeline - #23
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThe release changes now build the guest agent from its standalone Go module, package the CLI with its required keyring dependency, and recover from truncated managed-host downloads. Executed checks disproved the earlier guest-agent build failure, CLI dependency assertion failure, and truncated-download retry failure. Confidence Score: 5/5No blocking failure remains. The checked release construction, package metadata, download recovery, and CI trust paths behaved as intended.
What T-Rex did
Reviews (16): Last reviewed commit: "fix(release): drain the retention reaper..." | Re-trigger Greptile |
Collaborator
Author
|
@greptile review |
Lands the release slice of the managed-cloud implementation verbatim: scripts/release/ (deterministic build/verify, signed guest-image and offline host-package builders, tag-bound version resolution, fail-closed CI authorization, and their tests) plus the release-artifacts workflow. The release policy requires an exact CI job matrix, so ci.yml is reshaped to it: the go job now tests nehemiahd, the guest agent, and the public gateway (with govulncheck); the workspace job gains the npm audit gate, the release policy checks, a root build, and the Postgres-backed control-plane migration replay + full suite; the new wire-contract job checks generated model drift (bringing scripts/openapi-models.mjs); shell now also lints authorize-ci.sh. Two workspace steps whose slices have not landed yet (live-harness syntax, deploy promotion policy) are deferred to those slices. Lockfile bumps via npm audit fix satisfy the new audit-level=high gate. Co-authored-by: Cursor <cursoragent@cursor.com>
…bootstrap CI resolves Go from the go directive (1.25.0), whose standard library now carries 30 known vulnerabilities fixed in later patches, so govulncheck fails there while a locally newer toolchain passes. Pin toolchain go1.26.5 in nehemiahd, guest-agent, and gateway. Rewrite bootstrap.sh's KVM permission warning as an explicit if: the release validate job runs the provisioning harness, whose default-severity shellcheck flags the "A && B || C" form (SC2015) on current shellcheck. Co-authored-by: Cursor <cursoragent@cursor.com>
The CLI type-checks against nehemiah-sdk's published dist/ types, which the validate job never built, so every run of the step failed with TS2307/TS18046 cascades — including on the source branch, where this job was red too. Build the SDK workspace between its own checks and the CLI's. Co-authored-by: Cursor <cursoragent@cursor.com>
The step ran `go build ./guest-agent` from the repo root, but there is no Go module at the root (each component is its own module), so every guest-images run failed with "cannot find main module". Build with -C guest-agent and emit the binary to an absolute path, matching how build.mjs compiles components (cwd set to the module directory). Co-authored-by: Cursor <cursoragent@cursor.com>
…pshot The host-packages inspector extracted with tarfile, which stops at the tar end-of-archive marker and never reads the gzip trailer, so the workflow's truncated-archive negative test proved a one-byte-truncated archive inspected cleanly. Decompress the full stream (bounded by the extraction policy) before extracting so the CRC/length trailer is always checked; verified against intact, trailer-truncated, and mid-stream-corrupted archives. Alpine republished the v3.23 indexes after the policy's snapshot was captured, so every guest-image build failed its index digest check. Refresh the four APKINDEX pins from the live repository and update the reviewed capturedAt in both places that pin it (check.mjs and the release test), per the security-refresh ritual. Co-authored-by: Cursor <cursoragent@cursor.com>
…ependency esbuild cannot bundle @napi-rs/keyring's native .node binding, so the deterministic-build job failed bundling the CLI. Mark it external and declare it (exact-pinned from the CLI workspace) as the generated package's single runtime dependency; npm resolves the platform binding at install time, matching how the Homebrew formula installs the tarball. Co-authored-by: Cursor <cursoragent@cursor.com>
The packed CLI must install with npm --offline against an empty cache, so the keyring cannot be an ordinary registry dependency. Vendor the napi-rs keyring and all twelve platform bindings into the package as a bundled dependency, each fetched at build time and verified against an exact pinned tarball digest, with the platform bindings nested under the keyring package so its per-platform require resolves offline. The post-install invariant now asserts exactly the bundled keyring dependency and that its vendored tree landed (the offline install itself still proves nothing is fetched), and check.mjs pins the new assertion plus the digest-pinned download path. Verified locally end to end: bundle, vendor, npm pack (11.9 MB), offline global install with an empty cache, vendored tree present, and bc help. Co-authored-by: Cursor <cursoragent@cursor.com>
The host-packages packager emits manifest.json with canonically sorted
keys, so parsed evidence carries operatingSystem as {codename, id,
version}. Cloning that into the release manifest broke the contract
validator's JSON.stringify deep-equality against the policy's reviewed
{id, version, codename} order. Rebuild the object in policy key order,
require the exact evidence key set, and key-sort the test fixture the
way the packager does so the suite reproduces the drift.
Co-authored-by: Cursor <cursoragent@cursor.com>
Both package-closure matrix jobs died 25 minutes in when snapshot.ubuntu.com answered 500/502 during the repeat build. Retry server and network failures up to three times with backoff, matching the curl fetchers' --retry 3. Client errors still fail immediately, policy violations are never retried, and every download remains digest-verified, so retries cannot alter the closure. Co-authored-by: Cursor <cursoragent@cursor.com>
The snapshot.ubuntu.com load balancer flapped for over ten minutes and outlived the previous three-retry, fourteen-second budget. Retry up to eight attempts with a capped backoff (about two minutes per file) so a burst cannot sink a 25-minute matrix job; client errors still fail immediately and every download stays digest-verified. Co-authored-by: Cursor <cursoragent@cursor.com>
Trivy stamps DownloadedAt with nanosecond precision while the evidence recorded observedAt in whole seconds, so when both landed in the same second the truncated observation sorted "before" the download and the evidence verifier rejected the ordering. Record observedAt at the same precision so program order is preserved in the timestamps. Co-authored-by: Cursor <cursoragent@cursor.com>
http.client.IncompleteRead is not an OSError, so a response cut off after streaming began escaped the retry handler on the first attempt and left the partial file behind. Treat http.client transport exceptions as retryable alongside the existing failures, and pin the downloader's whole retry contract — truncation retried without residue, 5xx bursts bridged, client errors immediate, exhaustion fail-closed — with a stubbed-opener harness run from the release test suite. Co-authored-by: Cursor <cursoragent@cursor.com>
Alpine republished both v3.23 main indexes this morning, so every guest-image build failed its immutable index digest check. Refresh the two changed APKINDEX pins from the live repository (both community indexes are unchanged) and update the reviewed capturedAt in check.mjs and the release test, per the security-refresh ritual. Co-authored-by: Cursor <cursoragent@cursor.com>
The device-auth suite freezes its clock at a calendar date, and once its revoked fixture families aged past the reaper's 24-hour window they sort ahead of the retention test's chain and fill the whole default family batch of 4, so a single reap pass no longer removed the chain and the new policy-enforcing workspace job started failing mid-day. Run the job to completion the way its schedule would — batched drains promise eventual removal, not first-pass removal — and assert the accumulated totals; verified against a fresh sequential Postgres run. Co-authored-by: Cursor <cursoragent@cursor.com>
michaelshimeles
force-pushed
the
stack/release
branch
from
August 11, 2026 22:21
84f779d to
fa49c54
Compare
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.
Summary
scripts/release/— deterministic build + immutable checksum verification, signed guest-image and offline host-package builders with double-build reproducibility checks, tag-bound version resolution, fail-closed CI authorization, the Homebrew formula template, and the release policy tests — plus therelease.ymlworkflow.ci.ymlto the exact four-job matrix the release policy enforces (go,workspace,wire-contract,shell): the go job now runs the nehemiahd, guest-agent, and gateway test suites with govulncheck; the workspace job gains thenpm audit --audit-level=highgate, the release policy checks, a root build, and the Postgres-backed control-plane migration replay + full 337-test suite; the new wire-contract job checks generated OpenAPI model drift (brings the 62-linescripts/openapi-models.mjs); shell also lintsauthorize-ci.sh.tests/nehemiah/, staging/production promotion policy forscripts/deploy/) are deferred to those slices. Lockfile bumps vianpm audit fix(5 high-severity advisories, all semver-compatible) satisfy the new audit gate..gitignoregainsapps/nehemiah/dist/(present on the source branch, missed when that app landed).Test plan
node --test scripts/release/test/*.test.mjs— 17/17, including the live workflow-policy validation against the reshapedci.ymlnode scripts/release/check.mjs— "release checks passed for 0.2.0-beta.0"bash infra/latitude/test/managed-provisioning.test.sh— passes with the release assertions activego test -race+govulncheck— nehemiahd, guest-agent, gateway all cleannpm audit --audit-level=high— clean after the lockfile fixesnpm run check/lint/test/build— green--no-file-parallelism— 337/337release.yml'sguest-images/host-packagesjobs are path-triggered and will run on this PR; they needubuntu-24.04-armrunners — confirm they schedule and pass in CIMade with Cursor
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.