fix(ci): unshallow gate replay history

This commit is contained in:
2026-08-01 09:58:46 -05:00
parent 0b4aa4751a
commit e89599758b
4 changed files with 7 additions and 3 deletions
+3
View File
@@ -72,9 +72,12 @@ steps:
# step-level `when`, because a gate can be disabled by changes outside its own path.
gate-verify:
image: *node_image
# Woodpecker's shallow marker makes merge-base reject even present parents;
# full history is required for prospective own-tree replay.
commands:
- *enable_pnpm
- apk add --no-cache bubblewrap
- if [ -f .git/shallow ]; then git fetch --unshallow --no-tags origin; fi
- pnpm gate:verify
depends_on:
- install
+2 -2
View File
@@ -26,8 +26,8 @@ Do not add an ownerless exception or describe an open delta as pass/green/OK.
## CI behavior
Woodpecker runs `gate-verify` on every pull request and protected-main push without path filtering. This is deliberate: changes outside gate files can make a gate inert.
Woodpecker runs `gate-verify` on every pull request and protected-main push without path filtering. This is deliberate: changes outside gate files can make a gate inert. The step unshallows the checkout first because prospective ancestry and own-tree replay require complete commit history; a shallow boundary must never be interpreted as non-ancestry.
Provider evidence input is an optional JSON array of normalized pipeline records containing `commit`, unique integer pipeline `number`, pipeline `status`, and a `gate-verify` step status. The highest numbered rerun is authoritative; ambiguous duplicates fail. Its retention window is provider-controlled and is not overstated by this repository.
Prior commit replay performs a frozen offline install from each commit's own lockfile before running that commit's verifier. Bubblewrap clears the environment, hides operator-home credentials, and disables networking for historical lifecycle and verifier code. A missing cached dependency or unavailable sandbox fails replay; current dependencies are never substituted.
Prior commit replay performs a frozen offline install from each commit's own lockfile before running that commit's verifier. Bubblewrap clears the environment, hides operator-home credentials, isolates process namespaces, and disables networking for historical lifecycle and verifier code. Archived files are snapshotted before install and must remain byte/type/mode-identical afterward. A missing cached dependency, source mutation, or unavailable sandbox fails replay; current dependencies are never substituted.
@@ -58,6 +58,7 @@ The queue guard's `get_state_from_status_json` runs `python3 - <<'PY'` while pro
- Codex security review found the Bubblewrap replay shared the runner PID namespace. Replay now unshares PID, IPC, and UTS namespaces, and an abuse-case test proves a sibling runner PID is invisible.
- Second review found empty reason diagnostics, final-symlink fixture writes, and lifecycle-script mutation of authoritative history files. Must-fail cases now require a reason pattern; writes use no-follow semantics; and replay snapshots every archived file before install and rejects any changed, deleted, or type/mode-shifted source before executing the verifier. Dedicated negative tests cover all three.
- Third code review found ambiguous duplicate provider steps and order-sensitive JSON outcome comparison. Provider evidence now requires exactly one `gate-verify` step in the authoritative rerun, and structural equality normalizes object keys. Both regressions have RED-first tests. Third security review reported no findings.
- Initial PR pipeline #2177 exposed Woodpecker's shallow boundary: the activation parent object was present but marked shallow, so `merge-base --is-ancestor` correctly refused to infer ancestry. The unconditional gate step now unshallows before prospective replay; its wiring test was observed RED before the CI fix.
## Documentation checklist
+1 -1
View File
@@ -16,7 +16,7 @@ test('Woodpecker runs gate verification on every pipeline without a path filter'
pipeline.match(/\n gate-verify:\n([\s\S]*?)(?=\n [a-z][a-z0-9-]+:|\nservices:)/)?.[1] ?? '';
assert.match(
step,
/commands:\n - \*enable_pnpm\n - apk add --no-cache bubblewrap\n - pnpm gate:verify\n/,
/commands:\n - \*enable_pnpm\n - apk add --no-cache bubblewrap\n - if \[ -f \.git\/shallow \]; then git fetch --unshallow --no-tags origin; fi\n - pnpm gate:verify\n/,
);
assert.doesNotMatch(step, /\bwhen:|\bpath:/);
});