From 7ace35a3129c426444ecd9f8fec90d87dcc03f16 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 17:11:48 +0900 Subject: [PATCH 1/8] test: forbid autonomous repository-write publication --- tests/test_hourly_opencode_nvidia_contract.py | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/tests/test_hourly_opencode_nvidia_contract.py b/tests/test_hourly_opencode_nvidia_contract.py index dc1410e..bf4484f 100644 --- a/tests/test_hourly_opencode_nvidia_contract.py +++ b/tests/test_hourly_opencode_nvidia_contract.py @@ -84,7 +84,7 @@ def test_credentialed_model_runner_never_executes_model_modified_code() -> None: def test_open_pull_request_gates_count_every_paginated_page() -> None: - """Refuse autonomous publication when an open PR exists beyond page one.""" + """Refuse development or reverification for an open PR beyond page one.""" workflow = " ".join( _read(PRODUCT_WORKFLOW_PATH).replace("\\\n", "").split() ) @@ -93,10 +93,34 @@ def test_open_pull_request_gates_count_every_paginated_page() -> None: "--paginate --slurp --jq 'map(length) | add // 0'" ) - assert workflow.count(complete_query) == 3 + assert workflow.count(complete_query) == 2 assert "--jq 'length'" not in workflow +def test_product_scheduler_never_publishes_a_model_modified_tree() -> None: + """End the scheduler at a digest-bound credential-free patch handoff.""" + workflow = _read(PRODUCT_WORKFLOW_PATH) + forbidden_fragments = ( + "\n publish:", + "id-token: write", + "PR_REVIEW_MERGE_TOKEN", + "OPENCODE_APPROVE_TOKEN", + "exchange_github_app_token", + "git remote set-url", + "git push ", + "gh pr create", + "gh pr merge", + "contents: write", + ) + + assert all(fragment not in workflow for fragment in forbidden_fragments) + assert "Upload the independently verified handoff" in workflow + assert "hourly-verified-product-change-${{ github.run_id }}" in workflow + assert "/opt/egressweave-reverify/egressweave.patch" in workflow + assert "/opt/egressweave-reverify/base-sha" in workflow + assert "/opt/egressweave-reverify/patch-sha256" in workflow + + def test_review_scheduler_keeps_its_existing_identity_contract() -> None: """Do not repurpose the centrally managed review-agent credential path.""" review_workflow = _read(REVIEW_WORKFLOW_PATH) @@ -120,6 +144,15 @@ def test_operator_documentation_records_the_pinned_agent_and_secret_mapping() -> assert "OpenAI Codex Action" not in documentation +def test_operator_documentation_forbids_repository_local_patch_publication() -> None: + """Document that verified patches require an external promotion boundary.""" + documentation = " ".join(_read(MAINTENANCE_DOCUMENTATION_PATH).split()) + + assert "does not create a branch, pull request, or auto-merge request" in documentation + assert "external credential-separated promotion mechanism" in documentation + assert "reconstruct and verify the exact tree" in documentation + + def test_buyer_readme_identifies_the_opencode_nvidia_maintainer() -> None: """Keep the public execution identity aligned with the audited workflow.""" readme = _read(README_PATH) From bf6aceee6cb18befdf450f31c9dd7605b6159a2e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 17:15:16 +0900 Subject: [PATCH 2/8] security: end autonomous scheduler at verified handoff --- .../workflows/hourly-product-development.yml | 185 ++---------------- 1 file changed, 17 insertions(+), 168 deletions(-) diff --git a/.github/workflows/hourly-product-development.yml b/.github/workflows/hourly-product-development.yml index 4ac8733..7a9cd8a 100644 --- a/.github/workflows/hourly-product-development.yml +++ b/.github/workflows/hourly-product-development.yml @@ -116,8 +116,7 @@ jobs: curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ --output "$archive" \ "https://github.com/anomalyco/opencode/releases/download/v${OPENCODE_VERSION}/opencode-linux-x64.tar.gz" - printf '%s %s -' "$OPENCODE_SHA256" "$archive" | sha256sum --check - + printf '%s %s\n' "$OPENCODE_SHA256" "$archive" | sha256sum --check - if ! tar --list --gzip --file "$archive" | grep -qx 'opencode'; then echo "::error::The reviewed OpenCode archive did not contain the expected executable." exit 1 @@ -232,8 +231,7 @@ jobs: set -euo pipefail result_file="${RUNNER_TEMP}/opencode-result.ndjson" if [ ! -s "$result_file" ]; then - printf '%s -' '{"type":"error","message":"OpenCode produced no final result"}' >"$result_file" + printf '%s\n' '{"type":"error","message":"OpenCode produced no final result"}' >"$result_file" exit 1 fi @@ -271,10 +269,6 @@ jobs: actions: read contents: read pull-requests: read - outputs: - publish: ${{ steps.package.outputs.publish }} - base_sha: ${{ steps.package.outputs.base_sha }} - patch_sha256: ${{ steps.package.outputs.patch_sha256 }} steps: - name: Harden runner uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 @@ -408,9 +402,8 @@ jobs: python -m compileall -q src tests ' - - name: Record the independently verified immutable patch + - name: Recheck the independently verified immutable patch if: steps.gate.outputs.verify == 'true' - id: package run: | set -euo pipefail sealed_dir="/opt/egressweave-reverify" @@ -420,164 +413,20 @@ jobs: echo "::error::The sealed patch changed during independent verification." exit 1 fi - echo "publish=true" >>"$GITHUB_OUTPUT" - echo "base_sha=$(cat "$sealed_dir/base-sha")" >>"$GITHUB_OUTPUT" - echo "patch_sha256=$expected" >>"$GITHUB_OUTPUT" - - publish: - name: Publish the independently verified change - needs: reverify - if: needs.reverify.outputs.publish == 'true' - runs-on: ubuntu-24.04 - timeout-minutes: 15 - permissions: - actions: read - contents: read - id-token: write - pull-requests: read - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 - with: - egress-policy: audit - - - name: Check out a fresh protected branch - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - with: - ref: main - fetch-depth: 1 - persist-credentials: false - - - name: Download the independently verified change - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c - with: - name: hourly-product-change-${{ github.run_id }}-${{ github.run_attempt }} - path: ${{ runner.temp }}/hourly-product-change - - - name: Recheck repository state and patch identity - id: publish_gate - env: - GH_TOKEN: ${{ github.token }} - EXPECTED_BASE_SHA: ${{ needs.reverify.outputs.base_sha }} - EXPECTED_PATCH_SHA256: ${{ needs.reverify.outputs.patch_sha256 }} - run: | - set -euo pipefail - patch_file="${RUNNER_TEMP}/hourly-product-change/egressweave.patch" - current_sha="$(git rev-parse HEAD)" - open_prs="$( - gh api "repos/${GITHUB_REPOSITORY}/pulls?state=open&per_page=100" \ - --paginate \ - --slurp \ - --jq 'map(length) | add // 0' - )" - observed_patch_sha256="$(sha256sum "$patch_file" | awk '{print $1}')" - if [ "$open_prs" -ne 0 ] || [ "$current_sha" != "$EXPECTED_BASE_SHA" ]; then - echo "publish=false" >>"$GITHUB_OUTPUT" - echo "::notice::Discarding the verified patch because repository state changed before publication." - exit 0 - fi - if [ "$observed_patch_sha256" != "$EXPECTED_PATCH_SHA256" ]; then - echo "::error::The patch artifact changed after independent reverification." - exit 1 - fi - result_file="${RUNNER_TEMP}/publish-result.json" - python scripts/ci/hourly_product_guard.py apply \ - --workspace "$GITHUB_WORKSPACE" \ - --patch-file "$patch_file" \ - --result-file "$result_file" - if [ "$(jq -r '.base_sha' "$result_file")" != "$EXPECTED_BASE_SHA" ] || \ - [ "$(jq -r '.patch_sha256' "$result_file")" != "$EXPECTED_PATCH_SHA256" ]; then - echo "::error::Publisher guard identity did not match independent reverification." + base_sha="$(cat "$sealed_dir/base-sha")" + if [[ ! "$base_sha" =~ ^[0-9a-f]{40}$ ]]; then + echo "::error::The sealed base SHA is missing or malformed." exit 1 fi - echo "publish=true" >>"$GITHUB_OUTPUT" - - name: Select a write identity that triggers downstream checks - if: steps.publish_gate.outputs.publish == 'true' - id: write_token - env: - PREFERRED_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || '' }} - OIDC_AUDIENCE: opencode-github-action - OPENCODE_API_BASE_URL: https://api.opencode.ai - run: | - set -euo pipefail - if [ -n "${PREFERRED_TOKEN:-}" ]; then - echo "::add-mask::$PREFERRED_TOKEN" - echo "token=$PREFERRED_TOKEN" >>"$GITHUB_OUTPUT" - echo "source=organization-secret" >>"$GITHUB_OUTPUT" - exit 0 - fi - - if [ -z "${ACTIONS_ID_TOKEN_REQUEST_TOKEN:-}" ] || [ -z "${ACTIONS_ID_TOKEN_REQUEST_URL:-}" ]; then - echo "::error::No external write identity is available; refusing a GITHUB_TOKEN-authored PR that would suppress downstream workflow events." - exit 1 - fi - request_url="${ACTIONS_ID_TOKEN_REQUEST_URL}" - separator="&" - case "$request_url" in - *\?*) ;; - *) separator="?" ;; - esac - oidc_response="$( - curl -fsS \ - -H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \ - "${request_url}${separator}audience=${OIDC_AUDIENCE}" - )" - oidc_token="$(jq -r '.value // empty' <<<"$oidc_response")" - if [ -z "$oidc_token" ]; then - echo "::error::OIDC token response was empty." - exit 1 - fi - token_response="$( - curl -fsS \ - -X POST \ - -H "Authorization: Bearer ${oidc_token}" \ - "${OPENCODE_API_BASE_URL}/exchange_github_app_token" - )" - app_token="$(jq -r '.token // empty' <<<"$token_response")" - if [ -z "$app_token" ]; then - echo "::error::OpenCode app token exchange returned no repository write token." - exit 1 - fi - echo "::add-mask::$app_token" - echo "token=$app_token" >>"$GITHUB_OUTPUT" - echo "source=opencode-app-oidc" >>"$GITHUB_OUTPUT" - - - name: Push a branch, open a pull request, and queue guarded auto-merge - if: steps.publish_gate.outputs.publish == 'true' - env: - GH_TOKEN: ${{ steps.write_token.outputs.token }} - TOKEN_SOURCE: ${{ steps.write_token.outputs.source }} - run: | - set -euo pipefail - result_file="${RUNNER_TEMP}/hourly-product-change/opencode-result.ndjson" - stat_file="${RUNNER_TEMP}/hourly-product-change/egressweave.stat" - title="feat: close the next bounded product gap" - narrative_sha256="$(sha256sum "$result_file" | awk '{print $1}')" - tests="$(printf '%s\n' '- `ruff check .`' '- `pytest -q`' '- `python -m compileall -q src tests`' '- `git diff --check`')" - branch="agent/hourly-product-gap-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" - - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git switch -c "$branch" - git add -A -- src/egressweave tests docs README.md CHANGELOG.md - if git diff --cached --quiet; then - echo "::error::The independently verified patch produced no committable change." - exit 1 - fi - git commit -m "$title" - git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" - git push --set-upstream origin "$branch" - - body_file="${RUNNER_TEMP}/hourly-product-change/pr-body.md" - { - printf '## Autonomous product improvement\n\nThis pull request contains one bounded, independently reverified change selected while the repository had zero open pull requests. The model narrative is retained only in the short-lived workflow artifact so untrusted generated prose is not injected into the review context. Narrative SHA-256: `%s`.\n\n' "$narrative_sha256" - printf '## Verification\n\n%s\n\n' "$tests" - printf '## Diff boundary\n\n```text\n' - cat "$stat_file" - printf '```\n\n' - printf 'Generated by the hourly bounded maintainer. Write identity: `%s`. Full CI, security scans, independent reviews, and branch protections remain authoritative.\n' "$TOKEN_SOURCE" - } >"$body_file" - - pr_url="$(gh pr create --base main --head "$branch" --title "$title" --body-file "$body_file")" - gh pr merge "$pr_url" --auto --squash + - name: Upload the independently verified handoff + if: steps.gate.outputs.verify == 'true' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: hourly-verified-product-change-${{ github.run_id }}-${{ github.run_attempt }} + path: | + /opt/egressweave-reverify/egressweave.patch + /opt/egressweave-reverify/base-sha + /opt/egressweave-reverify/patch-sha256 + if-no-files-found: error + retention-days: 3 From e0f8547ccb367ca40d4d5ae7ec2e60db53638cff Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 17:16:03 +0900 Subject: [PATCH 3/8] docs: define external-only verified patch promotion --- docs/hourly-autonomous-maintenance.md | 119 +++++++++++++++----------- 1 file changed, 69 insertions(+), 50 deletions(-) diff --git a/docs/hourly-autonomous-maintenance.md b/docs/hourly-autonomous-maintenance.md index a409095..6a98efe 100644 --- a/docs/hourly-autonomous-maintenance.md +++ b/docs/hourly-autonomous-maintenance.md @@ -1,16 +1,17 @@ # Hourly autonomous maintenance EgressWeave uses two deliberately separate hourly workflows. Pull-request -governance stays independent from product-development model execution, and -untrusted model-controlled source never shares a job with repository write -credentials. +governance stays independent from product-development model execution. The +product scheduler can produce and independently verify a bounded patch, but it +has no repository-write, ref, release, package, attestation, or publication +identity. ## Cadence | Minute | Workflow | Responsibility | |---:|---|---| | `07` | `Hourly PR Maintenance` | Inspect every open pull request, dispatch bounded review-feedback repairs, re-read live reviews and checks, update eligible branches, and merge only when the central policy permits it. | -| `37` | `Hourly Autonomous Product Development` | Run only when the repository has zero open pull requests, produce one bounded buyer-visible improvement, independently reverify it, and publish it as a normal pull request. | +| `37` | `Hourly Autonomous Product Development` | Run only when the repository has zero open pull requests, produce one bounded buyer-visible improvement, independently reverify it, and retain a short-lived digest-bound patch handoff for external review. | GitHub may delay scheduled runs while hosted-runner capacity is constrained. Workflow concurrency prevents overlapping hourly runs, while repository CI @@ -28,22 +29,28 @@ workflows from `ContextualWisdomLab/.github` at an immutable commit: updates, queues, or merges anything. The central workflow resolves its co-located scheduler implementation from the -called workflow's own immutable repository and SHA. The EgressWeave workflow -does not duplicate governance logic or execute scheduler code from a mutable -branch. +called workflow's own immutable repository and SHA. The EgressWeave product +scheduler does not repurpose or alter that inherited review-agent credential +contract. ## Zero-PR product-development loop -`.github/workflows/hourly-product-development.yml` uses three fresh Ubuntu 24.04 +`.github/workflows/hourly-product-development.yml` uses two fresh Ubuntu 24.04 runners. The model job can only emit a bounded patch and does not execute -model-modified repository code; the reverifier can execute that patch only -inside an offline least-privilege container; and the publisher can write to -GitHub but never executes modified package code. +model-modified repository code. The reverifier executes that patch only inside +an offline least-privilege container and emits a short-lived handoff containing +the exact protected-main base SHA, patch SHA-256, and patch bytes. -Every zero-open-PR decision—the initial development gate, the independent -reverification gate, and the publication gate—uses GitHub CLI pagination and -sums every REST response page. A pull request beyond the first 100 results -therefore still blocks development, reverification, and publication. +The scheduler does not create a branch, pull request, or auto-merge request. It +does not obtain a repository-write token, exchange OIDC for a GitHub App token, +move a ref, reapply a patch under a write identity, publish a package, or create +a release. + +Both zero-open-PR decisions—the initial development gate and the independent +reverification gate—use GitHub CLI pagination and sum every REST response page. +A pull request beyond the first 100 results therefore still blocks model +execution and reverification. The second gate also requires the protected-main +head to equal the exact base SHA captured before model execution. ### 1. Read-only development and patch capture @@ -59,10 +66,10 @@ model is `nvidia/nemotron-3-super-120b-a12b`. The model execution boundary provides: -- block-mode runner egress restricted to the reviewed package sources, GitHub, - and `integrate.api.nvidia.com:443`; -- deny-by-default OpenCode permissions, with edits limited to the normal bounded - source, test, documentation, README, and CHANGELOG paths; +- block-mode runner egress restricted to reviewed package sources, GitHub, and + `integrate.api.nvidia.com:443`; +- deny-by-default OpenCode permissions, with edits limited to the bounded source, + test, documentation, README, and CHANGELOG paths; - an isolated empty `HOME` and XDG configuration/data/cache roots, plus `OPENCODE_DISABLE_PROJECT_CONFIG=true`, so repository or runner OpenCode configuration, auto-discovered agents, commands, and plugins cannot augment @@ -72,7 +79,7 @@ The model execution boundary provides: workflow edits; - no Ruff, pytest, compileall, Python-module, code-generation, or other model-modified repository execution while the model credential is present; - only exact read-only Git diff/status shell commands are permitted; + only exact read-only Git diff and status commands are permitted; - disabled OpenCode auto-update, remote model-list refresh, default plugins, and LSP downloads; - an exact credential-disclosure scan that reports only affected paths and never @@ -89,14 +96,15 @@ After model execution, only the protected baseline copy of `scripts/ci/hourly_product_guard.py` runs on the host. It uses an alternate Git index and NUL-safe path handling to reject deletions, renames, mode changes, executables, links, binaries, unsafe paths, oversized files, and oversized -diffs. The job uploads only the resulting patch, diff stat, and a short-lived -model summary. The patch is authoritative; generated prose is never injected -into the pull-request review context. +diffs. The job uploads the resulting patch, diff stat, and model result only for +the next credential-free job. That first artifact is untrusted until independent +reverification succeeds. ### 2. Credential-free isolated reverification A fresh runner has no secrets, no OIDC permission, and no repository-write -permission. Before applying the patch, it builds a verifier image from the +permission. Before applying the patch, it rechecks all open pull-request pages +and the exact protected-main base SHA. It then builds a verifier image from the protected branch and installs the trusted dependency and test toolchain. The Python base image is resolved to an immutable repository digest, and the built verifier is addressed by its immutable image ID. @@ -112,21 +120,34 @@ Modified source and tests then execute only in a container configured with: - a read-only source mount and no Docker socket, secrets, or host write mount. Inside that boundary, Ruff, pytest, and compileall run against the patched -source. A successful job emits only the protected base SHA and SHA-256 digest -of the independently verified patch. - -### 3. Credential-isolated publication - -A third fresh runner checks the zero-PR condition, protected-branch SHA, patch -SHA-256, and guard result again. It applies the patch for publication but does -not install or execute the modified package or tests. Only after those checks -does it obtain a write identity, preferring an organization maintenance secret -and otherwise using the centrally operated OpenCode GitHub App OIDC exchange. - -The publisher creates an `agent/hourly-product-gap-*` branch and pull request -and requests squash auto-merge. It never writes directly to `main`. Normal CI, -security scans, independent review, unresolved-thread checks, branch -protection, and the hourly PR loop remain authoritative. +source. The job rehashes the sealed patch and validates the 40-character base +SHA before uploading exactly three owner-readable files: + +```text +egressweave.patch +base-sha +patch-sha256 +``` + +The artifact name includes the workflow run and attempt, and retention is three +days. Successful reverification proves only that this exact patch passed the +configured checks against this exact base in the isolated job. It is not a pull +request, approval, merge authorization, provenance statement, or release. + +### 3. External promotion boundary + +No repository-local product-development job promotes the verified handoff. A +future external credential-separated promotion mechanism may consume it only +after independent review of that mechanism and its immutable source. Before any +repository write, that mechanism must independently acquire the exact artifact, +verify the base SHA and patch SHA-256, reconstruct and verify the exact tree, +recheck the live protected-main head and complete pull-request state, and obtain +all required independent approvals and security gates. + +No such promotion mechanism is claimed by this repository. When it is absent, +the verified artifact expires without publication. Operators must not manually +reinterpret a successful reverification job as permission to push, open a pull +request, enable auto-merge, or bypass branch protection. ## Model change boundary @@ -151,22 +172,20 @@ The scheduled product-development workflow requires: - `NVIDIA_NIM_API_KEY`, mapped only to OpenCode's `NVIDIA_API_KEY` environment variable for the NVIDIA NIM endpoint; -- either `PR_REVIEW_MERGE_TOKEN`, `OPENCODE_APPROVE_TOKEN`, or a working - organization OpenCode App OIDC exchange for a write identity that triggers - downstream pull-request events; - the standard Docker installation available on GitHub-hosted Ubuntu runners. -The workflow fails closed when the model credential, immutable verifier image, -container isolation, or external write identity is unavailable. It never falls -back to a repository `GITHUB_TOKEN`-authored pull request or a direct `main` -write. +The workflow fails closed when the model credential, protected base identity, +immutable verifier image, container isolation, or patch identity is unavailable. +It has no fallback repository-write identity and does not reuse review-agent, +release, package, attestation, or ref credentials. ## Manual operation -Both workflows support `workflow_dispatch`. Manual runs use the same checks, -concurrency, permissions, patch boundary, container isolation, full REST -pagination, and publication gates as scheduled runs. A manual run cannot bypass -the zero-open-PR condition or any repository policy. +Both workflows support `workflow_dispatch`. Manual product-development runs use +the same read-only permissions, exact-base checks, patch boundary, container +isolation, full REST pagination, and non-publication boundary as scheduled runs. +A manual run cannot bypass the zero-open-PR condition or turn the verified +handoff into a repository write. ## Agent implementation references From 52994ae4f512682e03869a5b0874e62afacc2f40 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 17:21:11 +0900 Subject: [PATCH 4/8] chore: record credential-free product handoff boundary --- CHANGELOG.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ae7996..e82e059 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,13 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). without changing the centrally managed review-agent credential contract. ### Security +- End the hourly product-development scheduler at a credential-free, + exact-base- and SHA-256-bound verified patch handoff. It no longer obtains + repository-write or OIDC authority, reapplies model-generated changes under a + write identity, pushes branches, opens pull requests, or queues auto-merge. + Any future promotion must be external, independently reviewed, + credential-separated, and reconstruct and verify the exact tree before any + repository write. - Revalidate the complete canonical evidence set and the closed owner-only manifest after publication but before reporting success. A second independent bounded evidence pass must reproduce the exact strict manifest bytes, while a @@ -128,9 +135,9 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). tools, credential-disclosure detection, isolated reverification, and normal PR protections remain mandatory; the central review scheduler and inherited review agent identity contract are unchanged. -- Paginate and aggregate every GitHub REST page at all three zero-open-PR - boundaries so an open pull request beyond the first 100 results still blocks - model execution, independent reverification, and publication. +- Paginate and aggregate every GitHub REST page at both zero-open-PR boundaries + so an open pull request beyond the first 100 results still blocks model + execution and independent reverification. - Bound outbound request-body consumption in both pinned transports. Oversized declared `Content-Length` values fail before connection-pool dispatch, while chunked, missing-length, and dishonestly under-declared bodies are counted as From 21c3ecaea7506db3f2c4f887fb8837645cf41434 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 17:32:40 +0900 Subject: [PATCH 5/8] test: bind verified handoff to exact base --- tests/test_hourly_opencode_nvidia_contract.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_hourly_opencode_nvidia_contract.py b/tests/test_hourly_opencode_nvidia_contract.py index bf4484f..a386963 100644 --- a/tests/test_hourly_opencode_nvidia_contract.py +++ b/tests/test_hourly_opencode_nvidia_contract.py @@ -114,11 +114,23 @@ def test_product_scheduler_never_publishes_a_model_modified_tree() -> None: ) assert all(fragment not in workflow for fragment in forbidden_fragments) + assert ": write" not in workflow + assert "Require the exact handoff base before applying the patch" in workflow + assert 'handoff_base_sha="$(cat "$handoff_base_sha_file")"' in workflow + assert '[ "$current_sha" != "$EXPECTED_BASE_SHA" ] ||' in workflow + assert '[ "$handoff_base_sha" != "$EXPECTED_BASE_SHA" ]; then' in workflow + assert "The patch handoff base does not match the exact checkout" in workflow + assert 'result_base_sha="$(jq -r ".base_sha" "$result_file")"' in workflow + assert '[ "$result_base_sha" != "$EXPECTED_BASE_SHA" ]; then' in workflow assert "Upload the independently verified handoff" in workflow + assert 'if [[ ! "$base_sha" =~ ^[0-9a-f]{40}$ ]]; then' in workflow assert "hourly-verified-product-change-${{ github.run_id }}" in workflow assert "/opt/egressweave-reverify/egressweave.patch" in workflow assert "/opt/egressweave-reverify/base-sha" in workflow assert "/opt/egressweave-reverify/patch-sha256" in workflow + handoff = workflow.split("Upload the independently verified handoff", 1)[1] + assert "if-no-files-found: error" in handoff + assert "retention-days: 3" in handoff def test_review_scheduler_keeps_its_existing_identity_contract() -> None: From f6df03ce2f07ec3f2907b1f9ce5f50889b3dcbcf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 17:34:54 +0900 Subject: [PATCH 6/8] security: bind verified patch to exact handoff base --- .../workflows/hourly-product-development.yml | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/.github/workflows/hourly-product-development.yml b/.github/workflows/hourly-product-development.yml index 7a9cd8a..80211d2 100644 --- a/.github/workflows/hourly-product-development.yml +++ b/.github/workflows/hourly-product-development.yml @@ -99,10 +99,10 @@ jobs: set -euo pipefail baseline="${RUNNER_TEMP}/hourly-pristine" git clone --quiet --local --no-hardlinks . "$baseline" - git -C "$baseline" rev-parse HEAD >"${RUNNER_TEMP}/hourly-development-base-sha" - sudo chown -R root:root "$baseline" "${RUNNER_TEMP}/hourly-development-base-sha" + git -C "$baseline" rev-parse HEAD >"${RUNNER_TEMP}/base-sha" + sudo chown -R root:root "$baseline" "${RUNNER_TEMP}/base-sha" sudo chmod -R a-w "$baseline" - sudo chmod 0444 "${RUNNER_TEMP}/hourly-development-base-sha" + sudo chmod 0444 "${RUNNER_TEMP}/base-sha" - name: Install the pinned OpenCode CLI if: steps.queue.outputs.develop == 'true' @@ -243,7 +243,7 @@ jobs: python "${RUNNER_TEMP}/hourly-pristine/scripts/ci/hourly_product_guard.py" capture \ --workspace "$GITHUB_WORKSPACE" \ --baseline "${RUNNER_TEMP}/hourly-pristine" \ - --base-sha-file "${RUNNER_TEMP}/hourly-development-base-sha" \ + --base-sha-file "${RUNNER_TEMP}/base-sha" \ --patch-file "${RUNNER_TEMP}/egressweave.patch" \ --stat-file "${RUNNER_TEMP}/egressweave.stat" @@ -256,6 +256,7 @@ jobs: ${{ runner.temp }}/egressweave.patch ${{ runner.temp }}/egressweave.stat ${{ runner.temp }}/opencode-result.ndjson + ${{ runner.temp }}/base-sha if-no-files-found: error retention-days: 3 @@ -309,6 +310,23 @@ jobs: fi echo "verify=true" >>"$GITHUB_OUTPUT" + - name: Require the exact handoff base before applying the patch + if: steps.gate.outputs.verify == 'true' + env: + EXPECTED_BASE_SHA: ${{ needs.develop.outputs.base_sha }} + run: | + set -euo pipefail + handoff_base_sha_file="${RUNNER_TEMP}/hourly-product-change/base-sha" + current_sha="$(git rev-parse HEAD)" + handoff_base_sha="$(cat "$handoff_base_sha_file")" + if [[ ! "$EXPECTED_BASE_SHA" =~ ^[0-9a-f]{40}$ ]] || \ + [[ ! "$handoff_base_sha" =~ ^[0-9a-f]{40}$ ]] || \ + [ "$current_sha" != "$EXPECTED_BASE_SHA" ] || \ + [ "$handoff_base_sha" != "$EXPECTED_BASE_SHA" ]; then + echo "::error::The patch handoff base does not match the exact checkout." + exit 1 + fi + - name: Build a trusted verifier image before applying the patch if: steps.gate.outputs.verify == 'true' id: verifier_image @@ -345,6 +363,8 @@ jobs: - name: Validate, apply, and seal the untrusted patch if: steps.gate.outputs.verify == 'true' + env: + EXPECTED_BASE_SHA: ${{ needs.develop.outputs.base_sha }} run: | set -euo pipefail patch_file="${RUNNER_TEMP}/hourly-product-change/egressweave.patch" @@ -353,11 +373,16 @@ jobs: --workspace "$GITHUB_WORKSPACE" \ --patch-file "$patch_file" \ --result-file "$result_file" + result_base_sha="$(jq -r ".base_sha" "$result_file")" + if [ "$result_base_sha" != "$EXPECTED_BASE_SHA" ]; then + echo "::error::The verified result base SHA does not match the exact handoff base." + exit 1 + fi sealed_dir="/opt/egressweave-reverify" sudo install -d -m 0555 -o root -g root "$sealed_dir" sudo install -m 0444 -o root -g root "$patch_file" "$sealed_dir/egressweave.patch" - jq -r '.base_sha' "$result_file" | sudo tee "$sealed_dir/base-sha" >/dev/null + printf '%s\n' "$EXPECTED_BASE_SHA" | sudo tee "$sealed_dir/base-sha" >/dev/null jq -r '.patch_sha256' "$result_file" | sudo tee "$sealed_dir/patch-sha256" >/dev/null sudo chown root:root "$sealed_dir/base-sha" "$sealed_dir/patch-sha256" sudo chmod 0444 "$sealed_dir/base-sha" "$sealed_dir/patch-sha256" From 2dc5a8a5d05a977244e8f06157ccf12ad65c604e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 22:36:40 +0900 Subject: [PATCH 7/8] test: bind final handoff to the exact verified base --- tests/test_hourly_opencode_nvidia_contract.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/test_hourly_opencode_nvidia_contract.py b/tests/test_hourly_opencode_nvidia_contract.py index a386963..cbf0d60 100644 --- a/tests/test_hourly_opencode_nvidia_contract.py +++ b/tests/test_hourly_opencode_nvidia_contract.py @@ -123,7 +123,14 @@ def test_product_scheduler_never_publishes_a_model_modified_tree() -> None: assert 'result_base_sha="$(jq -r ".base_sha" "$result_file")"' in workflow assert '[ "$result_base_sha" != "$EXPECTED_BASE_SHA" ]; then' in workflow assert "Upload the independently verified handoff" in workflow - assert 'if [[ ! "$base_sha" =~ ^[0-9a-f]{40}$ ]]; then' in workflow + recheck = workflow.split( + "Recheck the independently verified immutable patch", + 1, + )[1].split("Upload the independently verified handoff", 1)[0] + assert "EXPECTED_BASE_SHA: ${{ needs.develop.outputs.base_sha }}" in recheck + assert '[[ ! "$base_sha" =~ ^[0-9a-f]{40}$ ]]' in recheck + assert '[ "$base_sha" != "$EXPECTED_BASE_SHA" ]' in recheck + assert "does not match the exact handoff base" in recheck assert "hourly-verified-product-change-${{ github.run_id }}" in workflow assert "/opt/egressweave-reverify/egressweave.patch" in workflow assert "/opt/egressweave-reverify/base-sha" in workflow From c038a9509d1a8eae8561cc9081e67e12bd373d42 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 22:55:15 +0900 Subject: [PATCH 8/8] fix: bind final handoff to the exact verified base --- .github/workflows/hourly-product-development.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/hourly-product-development.yml b/.github/workflows/hourly-product-development.yml index 80211d2..cbadbde 100644 --- a/.github/workflows/hourly-product-development.yml +++ b/.github/workflows/hourly-product-development.yml @@ -429,6 +429,8 @@ jobs: - name: Recheck the independently verified immutable patch if: steps.gate.outputs.verify == 'true' + env: + EXPECTED_BASE_SHA: ${{ needs.develop.outputs.base_sha }} run: | set -euo pipefail sealed_dir="/opt/egressweave-reverify" @@ -439,8 +441,9 @@ jobs: exit 1 fi base_sha="$(cat "$sealed_dir/base-sha")" - if [[ ! "$base_sha" =~ ^[0-9a-f]{40}$ ]]; then - echo "::error::The sealed base SHA is missing or malformed." + if [[ ! "$base_sha" =~ ^[0-9a-f]{40}$ ]] || \ + [ "$base_sha" != "$EXPECTED_BASE_SHA" ]; then + echo "::error::The sealed base SHA does not match the exact handoff base." exit 1 fi