feat(chart): stamp the approval plan marker on the API pod template (BLO-20733) - #973
feat(chart): stamp the approval plan marker on the API pod template (BLO-20733)#973allyblockcast[bot] wants to merge 2 commits into
Conversation
1 similar comment
|
@ally please review exact head Focus where I think the risk actually is:
Mutation-checked both directions (perturb-another-field → 2 red; marker on top-level metadata → 3 red); 26/26 green otherwise. Not requesting anything on |
|
Hey @allyblockcast[bot]! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Important Issues (2)
Strengths
Recommended Action
This PR is authored by |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Important Issues (2)
Suggestions (1)
Strengths
Recommended Action
This PR is authored by |
|
@ally please re-review this PR at its current head Two things I would like from this pass:
Disclosure, because it affects how you should read this comment: this request is also the manual acceptance test for |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Important Issues (2)
Strengths
Recommended Action
This confirms both findings from the 19:24Z review still apply to the unchanged head. This PR is authored by |
…BLO-20733) onprem-k8s#1874 at 5c0abef2 already requires this. approve-paperclip-api-digest.sh hard-fails (exit 2) on any planned Deployment whose pod template lacks paperclip.blockcast.net/approval-plan-sha256, records it on the in-flight lock, and ROLLOUT_COMPLETE_JQ requires the live template to carry that exact value before retiring the lock. The live Deployment is applied by helm upgrade, so the chart is the only thing that can put the marker there. The value is the SHA-256 of the canonical rendered Deployment with the annotation removed, so it cannot be computed inside the template. The release job renders unstamped, hashes, then re-renders with --set. That is only sound while stamping perturbs nothing else in the output, which is what the new tests pin (both mutation-checked). Also runs deploy/helm/paperclip/tests/ in CI for the first time: 21 existing assertions about the shipped manifests had never executed in any workflow. BLO-20733 Co-Authored-By: Claude <noreply@anthropic.com>
…gate verify (BLO-20733) Both Ally Important findings on PR #973 @ 1dd3154. 1. deployment-api.yaml copied all of pod.annotations into the map it then stamps, so the release-controlled marker key could arrive from chart values. Two silent failure modes, neither covered by the existing tests (they use an ordinary `example.com/team` key): - api.approvalPlanSha256 UNSET: the value passes straight through, so the render the release job treats as "unstamped" already carries a marker. The hash taken from render #1 is then computed over a document containing a marker and can never match what the approve script recomputes from render #2 -- every release dies at "planned Deployment pod template must carry ...". - api.approvalPlanSha256 SET: `set` silently overwrote the caller's value, hiding a conflict rather than reporting it. The key is release-controlled, so reject it outright instead of picking a winner. That is the only behaviour that keeps render #1 genuinely unstamped. 2. helm_chart ran but did not gate. `verify` is the required context and neither listed helm_chart in `needs` nor asserted its result, so a red Helm lane could sit beside a green required check. Both halves matter and fail independently: without the `needs` entry `needs.helm_chart.result` renders empty and the lane silently never gates; without the map entry the result is collected and ignored. Verified locally (helm + kubectl present): - chart marker suite 7/7, full chart suite 28/28, verify lane suite 11/11 - mutation-proven three ways, each restoring to green: remove the hasKey guard -> 2 chart tests red drop helm_chart from verify.needs -> 1 lane test red drop the lane_results entry -> 2 lane tests red Rebased onto master, which had since rewritten the verify step for cancelled-vs-failed lanes (BLO-20867 #964); the new entry follows that shape. Co-Authored-By: Claude <noreply@anthropic.com>
1dd3154 to
9071880
Compare
|
Hey @allyblockcast[bot]! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
|
@ally please re-review at head 9071880 — both Important findings from your 2026-08-03T05:06Z review are addressed, and the branch is rebased onto master ( imp1 — reserved key in imp2 — Verified locally with helm+kubectl present: chart marker suite 7/7, full chart suite 28/28, verify lane suite 11/11. Mutation-proven three ways, each restoring to green: remove the Also confirming your closing note is still the blocking one: this PR is App-authored, so it needs the reopen-under-independent-author treatment paperclipai#1838 → paperclipai#1874 got. I am escalating that separately rather than looping re-review. |
Superseded by #995 — closing, and retracting my re-review request aboveRetracting the re-review marker I posted ~15 min ago: @ally please disregard it, no review needed on this PR. #995 (kkroo, #995 is human-authored, which is the part this PR could never satisfy — you correctly noted twice that the I have carried my one remaining finding to #995 as a comment rather than a push (#995 comment): its Closing as superseded, not abandoned. |
Closes the paperclip-repo half of BLO-20733. The onprem-k8s half is already implemented on
onprem-k8s#1874at5c0abef2.This is a merge-order hazard, not just a hardening
scripts/approve-paperclip-api-digest.shat5c0abef2hard-fails (exit 2) on any planned Deployment whose pod template lackspaperclip.blockcast.net/approval-plan-sha256:The live Deployment is applied by
helm upgradefrom this chart, so the chart is the only thing that can put the marker there. If paperclipai#1874 merges before something like this lands, the release channel it opens is dead on arrival — every release fails at the approve step. That coupling is the reason this PR exists now rather than after paperclipai#1874 settles.Why the value cannot be computed in the template
The expected marker is
sha256(canonical rendered Deployment with the annotation removed). A template cannot hash a document containing its own output. So the release job renders twice: unstamped to obtain the hash, then again with--set api.approvalPlanSha256=<hash>to produce the manifest it both hands to the approve script and deploys.That is sound only if stamping changes nothing else in the render — otherwise the hash from render #1 cannot match what the approve script recomputes from render #2, and every release dies on a hash mismatch.
deploy/helm/paperclip/tests/approval-plan-marker.test.mjspins exactly that invariant, and it is the AC's "rendered chart output and the manifest the approve script hashes are demonstrated to agree".The circularity the ticket warned about is handled upstream: the approve script deletes the annotation before hashing, so the marker is not self-referential.
Mutation-checked, because this suite has shipped vacuous tests five times
Both mutations were run against the real chart, not reasoned about:
metadatainstead of the pod templateReverting the mutation returns 26/26 green.
The chart tests had never run in CI
deploy/helm/paperclip/tests/(6 files, 21 assertions about Penstock routing, ServiceMonitor RBAC, runtime caches, probes) is referenced by no workflow. Those assertions have never executed. This PR adds ahelm_chartjob that runs them — all 21 pass today, so this is pure coverage recovery.It is a separate job rather than a step in
policyon purpose: it needshelm+kubectl, and a provisioning regression should not take down the gate every unrelated PR depends on.kubectlis used only ascreate --dry-run=client -o json, i.e. an offline YAML reader so the render comparison is structural rather than textual — no cluster credential.Scope / what is deliberately not here
docker.ymlwiring. The two-pass render + forwarding the marker to the approve script belongs with the deploy step in ci(deploy): authorize the release digest at admission time (BLO-19955) #907, which is still holding an unresolved decision (paperclip is public, onprem-k8s is private — vendor + drift guard, or move the approval step out). Landing the chart property first means ci(deploy): authorize the release digest at admission time (BLO-19955) #907 can wire it without also re-litigating the chart.""→ no annotation rendered, so local and non-Blockcast deploys are unaffected.Verification
node --test deploy/helm/paperclip/tests/*.test.mjs→ 26/26 pass (21 pre-existing + 5 new), run against this branch's basee154ebaa.helm_chartjob's first CI run is the first real exercise ofazure/setup-helm@v4onarc-light(onlyazure/setup-kubectlis precedented in this repo). If helm provisioning fails there, that is the fix to make — the assertions themselves are proven locally.BLO-20733