Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions .agents/skills/manage-ci/references/current-inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,17 @@ successful manual canary does not prove PR isolation. Fork PR validation
remains hosted and is the no-Depot-authority half of the sentinel acceptance
evidence; only the exact same-repository sentinel ref may exercise the
diagnostic Depot job. All three sentinel cache phases attest the
provider-injected `ACTIONS_CACHE_URL`/`ACTIONS_RESULTS_URL` structure and
require a runtime token before invoking `actions/cache`; the non-loopback
check includes all IPv4 `127/8` and IPv4-mapped IPv6 loopback spellings.
provider-injected `ACTIONS_CACHE_URL`/`ACTIONS_RESULTS_URL` structure before
invoking pinned `actions/cache` restore/save actions. The shell attestation
does not require ambient `ACTIONS_RUNTIME_TOKEN`: GitHub's
`NodeScriptActionHandler` injects that credential into the cache actions, while
the shell `ScriptHandler` does not. Successful full restore/save is the
credential/token proof. The non-loopback check includes all IPv4 `127/8`
and IPv4-mapped IPv6 loopback spellings.
The protected PR probe clears and fully restores its saved poison key, requires
a cache hit and exact marker bytes before the trusted-seed gate, and thereby
proves the same-job Node token/write path; main verify's poison miss remains
the cross-scope proof.
Bracketed IPv6 authorities use the fixed runner's Python 3.8+ stdlib
`ipaddress` classifier; parser absence/version/invalidity fails closed.
Attestation reports only value-free variable/reason classes and fails closed
Expand Down
38 changes: 34 additions & 4 deletions .github/workflows/ci-quality-slice.yml
Original file line number Diff line number Diff line change
Expand Up @@ -400,10 +400,6 @@ jobs:
}
attest_cache_endpoint ACTIONS_CACHE_URL
attest_cache_endpoint ACTIONS_RESULTS_URL
if [[ -z "${ACTIONS_RUNTIME_TOKEN:-}" ]]; then
echo "cache backend attestation failed (variable=ACTIONS_RUNTIME_TOKEN reason=missing)" >&2
exit 1
fi

- name: Restore trusted authority marker
id: restore_seed
Expand Down Expand Up @@ -451,6 +447,40 @@ jobs:
path: .depot-authority-sentinel
key: ${{ steps.validate.outputs.poison_key }}

- name: Clear local poison marker before proof restore
shell: bash
run: rm -rf -- .depot-authority-sentinel

- name: Restore saved PR poison marker
id: restore_poison
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
with:
path: .depot-authority-sentinel
key: ${{ steps.validate.outputs.poison_key }}
fail-on-cache-miss: true

- name: Validate saved PR poison marker content
shell: bash
env:
SENTINEL_ID: ${{ steps.validate.outputs.sentinel_id }}
PR_NUMBER: ${{ steps.validate.outputs.pr_number }}
CACHE_HIT: ${{ steps.restore_poison.outputs.cache-hit }}
run: |
set -euo pipefail
if [[ "$CACHE_HIT" != "true" ]]; then
echo "saved PR poison marker restore did not report a cache hit" >&2
exit 1
fi
expected_file="$(mktemp)"
trap 'rm -f "$expected_file"' EXIT
printf 'mesh-llm-depot-authority-pr-marker-v1\nsentinel_id=%s\npr_number=%s\n' \
"$SENTINEL_ID" "$PR_NUMBER" > "$expected_file"
if [[ ! -f .depot-authority-sentinel/marker ]] ||
! cmp -s "$expected_file" .depot-authority-sentinel/marker; then
echo "saved PR poison marker content mismatch" >&2
exit 1
fi

- name: Require trusted seed isolation after poison publication
shell: bash
env:
Expand Down
8 changes: 0 additions & 8 deletions .github/workflows/depot-canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -428,10 +428,6 @@ jobs:
}
attest_cache_endpoint ACTIONS_CACHE_URL
attest_cache_endpoint ACTIONS_RESULTS_URL
if [[ -z "${ACTIONS_RUNTIME_TOKEN:-}" ]]; then
echo "cache backend attestation failed (variable=ACTIONS_RUNTIME_TOKEN reason=missing)" >&2
exit 1
fi

- name: Prepare deterministic non-secret marker
shell: bash
Expand Down Expand Up @@ -632,10 +628,6 @@ jobs:
}
attest_cache_endpoint ACTIONS_CACHE_URL
attest_cache_endpoint ACTIONS_RESULTS_URL
if [[ -z "${ACTIONS_RUNTIME_TOKEN:-}" ]]; then
echo "cache backend attestation failed (variable=ACTIONS_RUNTIME_TOKEN reason=missing)" >&2
exit 1
fi

- name: Clear local poison marker before trusted restore
shell: bash
Expand Down
26 changes: 16 additions & 10 deletions .omo/specs/pr-ci-optimization.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,17 +268,23 @@ permissions, no checkout, no secrets and only the fixed
provider-injected `ACTIONS_CACHE_URL` and `ACTIONS_RESULTS_URL` to be present
and structurally attested as HTTP endpoints with a nonempty, non-GitHub,
non-loopback authority (including all IPv4 `127/8` and IPv4-mapped IPv6
loopback spellings), numeric port and explicit path, plus a nonempty
`ACTIONS_RUNTIME_TOKEN`; it reports only variable/reason classes and never
endpoint values. Manual seed/verify inputs bind to the configured sentinel ID
and use the fixed runner's Python 3.8+ stdlib `ipaddress` classifier for every
bracketed IPv6 spelling; parser absence/version/invalidity fails closed.
and exact merge ref. The PR probe restores the trusted seed (not lookup-only),
loopback spellings), numeric port and explicit path; it reports only
variable/reason classes and never endpoint values. The shell attestation does
not require ambient `ACTIONS_RUNTIME_TOKEN`: GitHub's
`NodeScriptActionHandler` injects that credential into the pinned cache
actions, while the shell `ScriptHandler` does not. Their successful full
restore/save calls provide the credential/token proof. Manual seed/verify
inputs bind to both the configured sentinel ID and the exact merge ref. Every
attestation uses the fixed runner's Python 3.8+ stdlib `ipaddress` classifier
for each bracketed IPv6 spelling; parser absence/version/invalidity fails
closed. The PR probe restores the trusted seed (not lookup-only),
validates exact seed marker content on a hit, replaces it with a deterministic
non-secret poison marker, saves the exact Stage 1 poison key, then fails only
after saving if the seed was readable. A seed miss passes with the trusted-main
`verify-pr-write` phase pending; main verify fully restores and validates exact
poison content before its expected-miss failure. Fork PRs remain hosted and
non-secret poison marker, saves the exact Stage 1 poison key, clears and fully
restores that key, and requires a cache hit and exact marker bytes before the
seed decision; only then does it fail if the seed was readable. This same-job
restore/save proves the PR Node token/write path. A seed miss passes with the
trusted-main `verify-pr-write` phase pending; main verify's poison miss remains
the cross-scope proof. Fork PRs remain hosted and
provide the no-Depot-authority evidence; only the exact same-repository
sentinel ref exercises the Depot diagnostic.

Expand Down
32 changes: 22 additions & 10 deletions ci/DEPOT_MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,11 @@ any cache action, all three cache phases attest that the provider-injected
`ACTIONS_CACHE_URL` and `ACTIONS_RESULTS_URL` are present, value-free
structurally validated HTTP endpoints with a non-GitHub/non-loopback authority
(including all IPv4 `127/8` and IPv4-mapped IPv6 loopback spellings), numeric
port and explicit path, and that `ACTIONS_RUNTIME_TOKEN` is present.
port and explicit path. The shell attestation intentionally does not require
ambient `ACTIONS_RUNTIME_TOKEN`: GitHub's `NodeScriptActionHandler` injects
that credential into the pinned Actions-cache restore/save actions, while the
shell `ScriptHandler` does not. Successful full restore/save calls provide the
credential/token proof.
Bracketed authorities use the fixed runner's Python 3.8+ stdlib `ipaddress`
classifier for every IPv6 spelling; missing, too-old or invalid parser state
fails closed with only a `parser` reason class.
Expand All @@ -308,10 +312,13 @@ remote backend. Seed and verify inputs are bound to the configured sentinel ID
and exact merge ref before cache access. Seed clears its local marker, performs
a full restore and validates the exact marker content; verify performs a full
restore and validates exact poison content before its expected-miss check. The
protected PR probe uses that same path and exact marker grammar so cache-version
metadata cannot vary across jobs. After the protected PR probe publishes the
bounded poison key, dispatch `mode=verify-pr-write` with the same validated
inputs; a hit fails because trusted main saw a PR publication. The existing
protected PR probe uses that same path and exact marker grammar, then clears
and fully restores its saved poison key, requiring a cache hit and exact bytes
before the trusted-seed gate; this same-job restore/save proves the PR Node
token/write path, while main verify's poison miss remains the cross-scope proof.
Cache-version metadata cannot vary across jobs. After the protected PR probe
publishes the bounded poison key, dispatch `mode=verify-pr-write` with the same
validated inputs; a hit fails because trusted main saw a PR publication. The existing
default `mode=audit` remains the negative resource/credential audit across the
full Depot matrix and is unchanged.

Expand Down Expand Up @@ -347,15 +354,20 @@ record the result without executing PR-controlled code. The job has
fixed `.depot-authority-sentinel` path. Before the pinned cache restore it
attests the provider-injected remote backend using the same structural
non-GitHub/non-loopback HTTP contract (including all IPv4 `127/8` and
IPv4-mapped IPv6 loopback spellings) and requires a nonempty runtime token; no
endpoint, host, path, port or token value is printed. It validates the
IPv4-mapped IPv6 loopback spellings); no endpoint, host, path, port or token
value is printed. The shell attestation does not require ambient
`ACTIONS_RUNTIME_TOKEN`; the pinned Actions-cache restore/save actions are Node
actions, whose `NodeScriptActionHandler` receives that credential while the
shell `ScriptHandler` does not. Successful full restore/save calls prove the
credential/token path. It validates the
repository variable and the actual `github.event.pull_request.number`,
restores the trusted seed (not lookup-only), validates exact seed marker
content on a hit, replaces the path with a deterministic non-secret poison
marker, saves the exact Stage 1 poison key, then fails only if the trusted seed
marker, saves the exact Stage 1 poison key, clears and fully restores that key,
requires a cache hit and exact marker bytes, then fails only if the trusted seed
was readable. A seed miss passes with a pending trusted-main
`verify-pr-write` check; a seed hit is reported only after the poison save has
completed.
`verify-pr-write` check; a seed hit is reported only after the poison
restore/save proof has completed.

Fork PRs remain on the hosted path and provide the no-Depot-authority half of
the acceptance evidence; only the same-repository exact sentinel ref can
Expand Down
18 changes: 13 additions & 5 deletions ci/ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,13 +324,21 @@ at `.depot-authority-sentinel`, and gates only after publication. Before any
cache action, it attests the provider-injected `ACTIONS_CACHE_URL` and
`ACTIONS_RESULTS_URL` as value-free structural HTTP endpoints with a nonempty
non-GitHub/non-loopback authority (including all IPv4 `127/8` and IPv4-mapped
IPv6 loopback spellings), numeric port and explicit path, and requires
`ACTIONS_RUNTIME_TOKEN`; malformed/missing inputs fail closed without printing
endpoint, host, path, port or token values. Endpoint authorities are classified
IPv6 loopback spellings), numeric port and explicit path; malformed/missing
inputs fail closed without printing endpoint, host, path, port or token values.
The shell attestation intentionally does not inspect ambient
`ACTIONS_RUNTIME_TOKEN`: pinned `actions/cache` restore/save actions run as
Node actions; GitHub's `NodeScriptActionHandler` injects the runtime
credential, while the shell `ScriptHandler` does not. Successful full
restore/save calls are the credential/token proof. Endpoint authorities are
classified
with the fixed runner's Python 3.8+ stdlib `ipaddress` parser for all bracketed
IPv6 spellings; parser absence/version/invalidity fails closed. Seed and poison
markers are validated byte-for-byte on cache hits. It is outside planner
slices and does
markers are validated byte-for-byte on cache hits. After saving the PR poison,
the no-checkout job clears and fully restores that exact key, requires a cache
hit and exact bytes before the trusted-seed gate, and proves the same-job Node
token/write path; main verify's poison miss remains the cross-scope proof. It
is outside planner slices and does
not add build commands, matrices, artifacts, or producer/consumer edges; the
existing Quality lane summary still gates on its normal `quality` and
`runner_contract` jobs. Fork PRs remain hosted and provide the
Expand Down
51 changes: 43 additions & 8 deletions scripts/tests/test_depot_authority_sentinel.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,18 @@ def test_cache_probe_restores_then_publishes_before_gate(self) -> None:
)
self.assertLess(
positions["Save PR poison marker"],
positions["Clear local poison marker before proof restore"],
)
self.assertLess(
positions["Clear local poison marker before proof restore"],
positions["Restore saved PR poison marker"],
)
self.assertLess(
positions["Restore saved PR poison marker"],
positions["Validate saved PR poison marker content"],
)
self.assertLess(
positions["Validate saved PR poison marker content"],
positions["Require trusted seed isolation after poison publication"],
)
restore = self._step_block(self.sentinel, "Restore trusted authority marker")
Expand All @@ -388,7 +400,33 @@ def test_cache_probe_restores_then_publishes_before_gate(self) -> None:
"uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25",
self._step_block(self.sentinel, "Save PR poison marker"),
)
self.assertIn("rm -rf -- .depot-authority-sentinel", self.sentinel)
poison_restore = self._step_block(
self.sentinel, "Restore saved PR poison marker"
)
self.assertIn(
"uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25",
poison_restore,
)
self.assertIn(
"key: ${{ steps.validate.outputs.poison_key }}",
poison_restore,
)
self.assertIn("fail-on-cache-miss: true", poison_restore)
poison_validation = self._step_block(
self.sentinel, "Validate saved PR poison marker content"
)
self.assertIn(
'CACHE_HIT: ${{ steps.restore_poison.outputs.cache-hit }}',
poison_validation,
)
self.assertIn("mesh-llm-depot-authority-pr-marker-v1", poison_validation)
self.assertIn("cmp -s", poison_validation)
self.assertIn(
"rm -rf -- .depot-authority-sentinel",
self._step_block(
self.sentinel, "Clear local poison marker before proof restore"
),
)
self.assertIn(
"Trusted seed was not readable; pending trusted-main verify-pr-write.",
self.sentinel,
Expand Down Expand Up @@ -461,12 +499,9 @@ def test_authority_backend_attestation_is_value_free_and_fail_closed(self) -> No
valid_results,
runtime_token="",
)
self.assertNotEqual(missing_token.returncode, 0)
self.assertIn(
"cache backend attestation failed (variable=ACTIONS_RUNTIME_TOKEN reason=missing)",
missing_token.stderr,
)
self.assertNotIn("non-secret-runtime-token", missing_token.stderr)
self.assertEqual(missing_token.returncode, 0, missing_token.stderr)
self.assertEqual(missing_token.stdout, "")
self.assertEqual(missing_token.stderr, "")

with tempfile.TemporaryDirectory() as bin_dir:
tr_path = shutil.which("tr")
Expand Down Expand Up @@ -527,9 +562,9 @@ def test_authority_attestation_copies_are_identical(self) -> None:
"python_status == 3",
"ACTIONS_CACHE_URL",
"ACTIONS_RESULTS_URL",
"ACTIONS_RUNTIME_TOKEN",
):
self.assertIn(required, quality_script)
self.assertNotIn("ACTIONS_RUNTIME_TOKEN", quality_script)

def test_five_pr_entrypoints_and_existing_build_shape_are_unchanged(self) -> None:
expected = {
Expand Down
11 changes: 4 additions & 7 deletions scripts/tests/test_depot_canary_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def test_canary_sentinel_modes_are_single_runner_and_cache_bounded(self) -> None
self.assertIn("Attest provider-injected cache backend", block)
self.assertIn("ACTIONS_CACHE_URL", block)
self.assertIn("ACTIONS_RESULTS_URL", block)
self.assertIn("ACTIONS_RUNTIME_TOKEN", block)
self.assertNotIn("ACTIONS_RUNTIME_TOKEN", block)
self.assertIn("cache backend attestation failed", block)
self.assertNotIn("${endpoint,,}", block)

Expand Down Expand Up @@ -339,12 +339,9 @@ def test_all_cache_phases_attest_non_github_remote_backend(self) -> None:
valid_results,
runtime_token="",
)
self.assertNotEqual(result.returncode, 0)
self.assertIn(
"cache backend attestation failed (variable=ACTIONS_RUNTIME_TOKEN reason=missing)",
result.stderr,
)
self.assertNotIn("non-secret-runtime-token", result.stderr)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(result.stdout, "")
self.assertEqual(result.stderr, "")

def test_canary_fails_closed_on_cache_and_registry_injection(self) -> None:
self.assertIn("forbidden_names=", self.workflow)
Expand Down
Loading