the-custodian/docs/changes/2026-11-01-scanner-json-digest/native-r4/PLAN.md

8.7 KiB
Raw Blame History

Portable scanner rollout, revision 4

Stable proposal SYNC-SCANNER-JSON-DIGEST-20261101, revision 4. Revisions 1–3, exact revision-3 approval and both failed executions remain preserved. Revision 4 has not run natively and requires exact founder review.

Verified starting state and defect

The approved revision-3 run restored the missing old-policy scanner fragment at markitect-main. Its real dispatcher passed clean/private-key/history/quarantine/unavailable-scanner/recovery probes. All 171 fragments and unchanged protected hook metadata were verified. The JSON candidate then passed its native receive probe, but hook migration failed before the deployment patch. Guarded rollback verified the old template/policy, all 171 fragments and old-policy receive probes. The restored protection remains installed.

A reproducible compatibility defect exists in the reviewed migration script: chmod --reference is unavailable in Forgejo 11.0.3-rootless. The exact old migration fails in the published image pinned at code.forgejo.org/forgejo/forgejo@sha256:691657c7e64af7730a2e885e6d022cf16ae60724931c5392bd61838afadcaeba, also the pinned guard image in owner source. Workstation tests used a different userspace and missed this defect. Failed native receipts are preserved in this folder; local image tests retain the old-script counterexample.

The previous attempt left the public candidate binaries and immutable ConfigMap forgejo-secret-template-619d94208139 staged. They are inert under the currently selected old template. Revision 4 verifies/reuses them rather than creating that existing ConfigMap again.

Exact revised action

Founder launcher: /tmp/forge-scanner-rollout-r4.sh, selecting the attended admin context and this packet's exact SHA256 acknowledgement. Agent credentials/authority do not change. Fresh receipt: /tmp/forge-scanner-rollout-r4-receipt.json; an existing receipt refuses execution. Earlier receipts are never removed or overwritten.

  1. Verify this sealed packet and unchanged source/binary/probe/input artifacts in revision 2. Keep the exact same six owner-source candidates and candidate adapter SHA256 d7dbd0ef57312ab9507874bb5fd67c49bef637b6d7dee121e526227307af4bf0. Recheck node/deployment/pod identity, old guard/template, resources/strategy and all source preimages. Inventory every current repository (maximum 500); all fragments must already have the known old bytes and custody. The completed repair is a required starting state; there is no uncovered-repository exception.
  2. Snapshot active hook hashes, owners, groups and modes. Supported baseline is uid/gid 1000 and mode 0755 or 0775, as observed in all 1,539 hooks from the failed native execution. Verify the existing target ConfigMap is immutable and has exactly the reviewed hook data; pin its UID against recreation. Do not mutate/create the ConfigMap. Server dry-run the same conditional two-field deployment patch and capture the client ConfigMap diff; raw objects/errors stay withheld.
  3. Run runtime_self_test.sh in private tmpfs. It verifies numeric chmod, stable descriptor-based permission restoration, stat/hash and atomic rename, and cleans up its public fixture. Require success before production hook/deployment changes. This checks actual live userspace, supplementing the pinned-image tests.
  4. Verify/reuse the previously staged candidate directory with its original marker and exact adapter/Gitleaks hashes. Run the existing native JSON/private-key/history/quarantine/unavailable-scanner/recovery probe before activation.
  5. Migrate only scanner fragments with the original all-scope prevalidation, known bytes and partial-failure recovery. The two chmod --reference calls are replaced by chmod "$(stat -c %a …)", preserving numeric modes in the container's supported syntax. Paths remain bounded to repository scanner fragments. Unknown bytes, symlinks or custody refuse.
  6. Verify/restore exact baseline hook modes after migration and after pod recreation, including generated/protected hooks whose contents are never overwritten. Kubernetes volume processing may add group-write permission. The only accepted mode difference is baseline 0755 becoming 0775; remove that added bit to restore 0755. A 0775 baseline stays 0775. Require unchanged content hash, uid/gid, regular non-symlink shape and safe parents for every file before the first restoration. For changed modes, open the verified inode, recheck identity/hash/owner, chmod through /proc/self/fd, and verify the same final inode/mode. Unknown content, ownership, mode or hook-set changes refuse; never rewrite generated dispatchers or authorization-hook content. The controller also prevalidates protected content before any scanner rewrite.
  7. Apply the original UID/resourceVersion/before-value JSON patch to append the exact candidate artifact guard and select the new hook ConfigMap. No image, resource, strategy, security-context or credential changes. Wait up to 180 seconds for the correct deployment's Ready pod; repeat migration/inventory to cover known old fragments on repositories created during transition, restore only known group-write additions, then require original protected metadata equality. Stream mode records through stdin rather than placing the large inventory in command arguments.
  8. Verify all artifact guards, mounted new hook hash, full receiver inventory and post-activation JSON/private-key/history/quarantine/unavailable-scanner/recovery probe. Emit activation-verified only after those checks pass.
  9. After native verification, the agent applies the same six exact owner-source candidates via this folder's source_followthrough.py, requiring the approved revision-4 packet and verified revision-4 receipt. The candidates and resulting six hashes are unchanged from revision 2; only the receipt gate changes. Commit/publish through normal hooks, retry eligible held work and continue the CUST-WP-0083 failure audit. UUID/fingerprint/prose findings remain separate adjudication; the scanner exception is not broadened.

Recovery and tests

The original guarded rollback restores old deployment fields/template and known old scanner bytes, with the portable migration and exact baseline mode restoration now used during recovery too. It verifies old artifacts/template, protected metadata and the old-policy real receiver probe. Retain the repaired markitect-main fragment, staged public binaries/ConfigMap and every failed receipt. Unknown concurrent changes are retained and reported as unverified. A failed rollback still requires founder recovery; this is not a guarantee of recovery.

Tests were run in the pinned Forgejo userspace with no network, host credentials or writable source mounts. Eight shell cases cover the old-script counterexample, apply/rollback with mixed modes, complete-scope refusal, partial failure, symlinks, simulated pod permission additions, unexpected modes and content drift. The actual controller migration/stream framing passed a separate 171-repository/1,539-hook run: apply, post-recreation mode restoration (19 known group-write additions), rollback and protected-content refusal before writes. Three controller tests verify immutable ConfigMap reuse/UID pinning, changed/mutable data refusal and all six original source candidates. The new runtime self-test passed in that image. Original real-Gitleaks source/receiver proof and successful native candidate probe remain applicable because the scanner binary/profile are unchanged. Local tests are not native activation evidence.

Historical admission, why markitect-main adoption missed its fragment, and complete Forgejo new-repository/write lifecycle coverage remain unproved by this repair. Preserve those limits in the forge-owned class-level followup; no clean-history claim is made.

Cost, interruption and authority

No new infrastructure, service, image or resource commitment. Incremental infrastructure cost EUR 0; founder time/existing compute unpriced. Estimate 20–35 attended minutes. Expected Recreate interruption remains 1–3 minutes; rollback readiness up to another 180 seconds plus bounded commands/probes. Numeric mode restoration takes bounded extra inventory/metadata work (180-second operation limit); interruption estimate is not an availability guarantee.

Illustrative recovery effort EUR 100 at EUR 100/hour. Complete security/recovery loss remains unpriced and requires explicit founder judgement. Existing filename/digest exception limitations remain; no autopilot authority, risk budget, promotion or unchanged-success credit is implied. Exact review is needed because executable migration/recovery, existing-ConfigMap handling, protected-hook mode restoration and the source receipt gate change. Governing instruction: docs/agent-autonomy-decision.md, "Approval is bound to the reviewed proposal revision; changing that revision requires review again."