Skip to content

security: add authoritative worker core - #18

Merged
stacknil merged 11 commits into
mainfrom
stacknil/authoritative-worker-core
Sep 14, 2026
Merged

stacknil merged 11 commits into
mainfrom
stacknil/authoritative-worker-core

Conversation

@stacknil

@stacknil stacknil commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Summary

Add the data-only trusted worker core for the future authoritative Repo Sentinel gate.

The worker composes the already-reviewed acquisition, logical reader, and portable materializer boundaries without adding GitHub event parsing or authority publication:

trusted exact base snapshot
+ exact acquired PR-head snapshot
-> D1 snapshot diff
-> protected-control rejection
-> portable materialization
-> isolated scanner execution
-> bounded evidence result

This PR is intentionally draft because it changes a security boundary and exceeds 500 substantive lines.

Design decision

Use immutable Snapshot values as the only base/head comparison input. D1 maps exact logical paths to (mode, blob_oid), reports added/modified/mode-changed paths separately from deletions, performs no rename inference, and remains O(n log n).

Reject protected policy changes before materialization or scanner launch. Materialize only the admitted head snapshot, execute the pinned scanner from a separate trusted directory, and return fixed verdicts plus bounded metadata. The worker never publishes GitHub status.

Protected control plane

Changed or deleted paths are rejected for:

  • .reposentinel.toml and .reposentinel-baseline.json;
  • .github/workflows/** and .github/actions/**;
  • the existing gate, acquisition, reader, materializer, authoritative worker, and integration-test scripts.

Protected matching uses the portable-v1 ASCII alias rule: A-Z maps to a-z, and every other code point remains unchanged. Exact-path and subtree boundaries remain distinct; general Unicode lowercasing or case folding is not used.

The exact repo-sentinel-lite==0.8.1 source-suppression behavior was inspected. A touched file containing its inline allow directive in either base or head is conservatively treated as a protected policy change.

Scanner, config, and baseline

  • Scanner: python -I -m repo_sentinel, argument array, shell=False.
  • Version: exact runtime output repo-sentinel 0.8.1.
  • Inspected wheel SHA-256: 0A949A4D00C6E6AE37EBA60A6CB74E4E15BC3EC5FCE2F1D4C99AA0EF309B36E3.
  • Config: 0.8.1 reads only <scan-root>/.reposentinel.toml; no parent, home, or environment-selected alternate config.
  • Baseline: default discovery is disabled. Exact bytes come only from the base snapshot through a verifier-owned temporary file.
  • Target-owned repo_sentinel.py, sitecustomize.py, usercustomize.py, *.pth, executable bits, and workflow files remain inert data.
  • A deletion-only delta materializes the head and runs scanner repository-level checks with an empty changed-path tuple; deleted paths are never passed as scanner file arguments.
  • Only an identical snapshot with no changed or deleted paths may take the deterministic no-scan PASS path.

Evidence and failure model

Results expose only a fixed verdict, validated repository/PR/OID identity, changed/deleted counts, report size and SHA-256, scanner version, and fixed refusal code. Invalid identity is not reflected into refusal results.

Scanner stdout/stderr are captured with byte caps. Raw report text, filenames, parser output, and workflow-command-shaped content are never printed. Reports are bounded, validated, persisted exclusively outside the target/trusted checkout, and never overwritten.

The worker distinguishes PASS, SCANNER_FINDING, INFRASTRUCTURE_REFUSAL, and PROTECTED_CONTROL_CHANGE. Acquisition, reader, materializer, scanner, malformed-report, timeout, size, and cleanup failures fail closed.

Validation

Local environment:

  • Python 3.14.3
  • Git 2.55.0.windows.5
  • Ruff 0.16.7
  • pre-commit 4.5.1
  • repo-sentinel 0.8.1

Exact test results:

  • authoritative worker: 37 passed
  • acquisition: 13 passed
  • reader: 15 passed
  • materializer: 24 passed
  • existing gate: 13 passed
  • complete suite: 108 passed
  • pre-commit: passed
  • Ruff check and format check for changed Python files: passed
  • Markdown: 157 files passed
  • taxonomy/tag rendering: up to date
  • README rendering: up to date
  • pattern library: 8 stable patterns / 10 supporting notes / 13 cards
  • changed-file Repo Sentinel scan: 0 findings
  • git diff --check: passed

Mutation evidence

Each mutation was applied locally, produced the expected failing regression, and was restored before submission:

  1. base baseline switched to head baseline;
  2. changed .reposentinel.toml allowed;
  3. scanner cwd switched to the materialized target;
  4. raw hostile report printed;
  5. protected workflow subtree ignored;
  6. portable-v1 matching restored to exact case-sensitive comparison;
  7. deletion-only deltas restored to the old no-scan PASS branch.

The two remediation mutations failed their focused real-scanner regressions and were restored before final validation.

242-file probe

The exact public PR #15 head was acquired and processed through the new worker with its immediate trusted parent as the D1 base:

  • head: 2f7b7a9bef43715141086b0d79bacbe67a178288
  • tree: 960dc6c6496f1260f6fab74b64f26408024cd5fb
  • files: 242
  • bytes: 2,260,062
  • manifest: ad39acf89d0826ce2651ed14d12e143d7f0a8b5cb6b2eb219b46895688f45d0a
  • exact path identity: preserved
  • exact file bytes: preserved
  • worker verdict: PASS
  • scanner version: 0.8.1
  • scratch cleanup: complete
  • repository content executed: false
  • remediation rerun: identical file/byte/tree/manifest result with acquisition and materializer cleanup complete

Main risk

The source-suppression rule is intentionally conservative: editing a file that already contains a legitimate inline suppression is blocked for control-plane review. The scanner is isolated from target imports but is not a general sandbox; the interpreter, installed package, runner, and caller-owned roots remain trusted preconditions.

Compatibility impact

The change is additive. It does not modify acquisition, reader, materializer, scanner semantics, report schemas, baseline behavior, existing workflow YAML, workflow permissions, or repository rules. The current unprivileged pull-request workflow remains informational and unchanged.

Rollback path

Revert the PR branch commits. No persisted schema, workflow activation, GitHub App installation, secret, branch rule, or external service must be migrated or removed.

Out of scope

This PR does not add a production signer, App credentials, installation tokens, Commit Status or Checks API calls, pull_request_target, workflow activation, branch protection, or ruleset changes.

@stacknil

Copy link
Copy Markdown
Owner Author

Post-CI exact-head review completed for 0adbe591bd3b5f06548da84c9112a6f8c9b43404.

  • Design decision: compare immutable base/head snapshots with D1, reject protected controls before materialization, then scan the admitted head from a separate trusted directory and return bounded evidence only.
  • Main risk: the conservative inline-suppression policy can require manual control-plane review for otherwise ordinary edits; interpreter/package/runner trust remains a precondition because import isolation is not a general sandbox.
  • Compatibility impact: additive three-file change; acquisition, reader, materializer, existing gate, report schemas, baseline semantics, workflow YAML, permissions, and repository settings are unchanged.
  • Rollback path: revert this branch's seven commits; no workflow, App, secret, ruleset, status publication, or persisted schema needs migration.

Remote branch SHA equals the reviewed PR head. All configured checks are green, git diff --check passes, and no bot/reviewer findings are present. The PR remains draft for delayed independent security review and is not approved for workflow activation or merge by this note.

@stacknil

Copy link
Copy Markdown
Owner Author

Post-CI remediation review completed for b813e3d0cc372b5c54288f5848abc7d70be58b76.

  • Design decision: protected controls now use the explicit portable-v1 ASCII alias rule (A-Z to a-z, all other code points unchanged), while only an exact no-delta snapshot may bypass scanner execution.
  • Main risk: the portable control policy intentionally blocks ASCII-case aliases even on case-sensitive hosts; deletion-only changes now incur a scanner run so repository-level evidence is retained.
  • Compatibility impact: ordinary changed-file semantics are unchanged. Deletion-only deltas pass an empty changed-path tuple to repo-sentinel-lite==0.8.1; deleted paths are never sent as scanner file arguments.
  • Rollback path: revert the four remediation commits to reviewed head 0adbe591bd3b5f06548da84c9112a6f8c9b43404. No workflow, App, secret, ruleset, publication mechanism, baseline, or report schema changes are involved.

Validation evidence:

  • authoritative worker: 37 passed;
  • complete suite: 108 passed;
  • real mixed-case config exploit: PROTECTED_CONTROL_CHANGE, scanner calls 0;
  • real LICENSE deletion: PASS, scanner 0.8.1, changed 0, deleted 1, one non-blocking repo.required_file_missing warning, report SHA-256 6d26e7a4418fba6c4a1744ade3eaa7b7299f682a4523386ecd75ff7641c19fe8;
  • both requested mutations caused their focused regressions to fail and were restored;
  • changed-file scanner self-check: 0 findings;
  • 242-file HTTPS probe: 2,260,062 bytes and manifest ad39acf89d0826ce2651ed14d12e143d7f0a8b5cb6b2eb219b46895688f45d0a, with cleanup complete and no repository content execution;
  • all seven exact-head configured check runs succeeded; no bot or reviewer findings are present.

The PR remains Draft. This note does not approve workflow activation or merge.

@stacknil
stacknil marked this pull request as ready for review September 14, 2026 13:21
@stacknil
stacknil merged commit f965be8 into main Sep 14, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant