Skip to content

fix(signer): sample authorization time after acquiring transaction lock - #24

Draft
stacknil wants to merge 1 commit into
mainfrom
stacknil/authority-boundary-increment
Draft

stacknil wants to merge 1 commit into
mainfrom
stacknil/authority-boundary-increment

Conversation

@stacknil

@stacknil stacknil commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

Problem

An otherwise authorized signer request can expire while waiting for the shared transaction lock. Both service entrypoints previously sampled time before that wait, allowing admission or finalization to proceed using stale authorization time.

Invariant

Admission and finalization sample authorization time after acquiring the shared transaction lock. Expired OIDC is rejected before creating admission/publication state. An expired evaluation with valid execution identity still consumes its finalization JTI before refusal, preserving the replay contract.

Design decision

Move the existing clock read into store.transaction() in issue_evaluation() and finalize_evaluation(). Add deterministic contention tests using the real shared lock, an Event, and an injected logical clock. The affected files are the signer service, its new time-boundary tests, and two design records under docs/design-decisions/.

Threat/failure model

The demonstrated schedule is an authorized request queued across token or evaluation expiry. It is reproduced locally against the reference/mock signer; production reachability is unproven. Freshness is established at transaction entry. A future blocking adapter or remote publisher needs its own publication-time deadline contract.

Rejected alternatives

  • Extending lifetimes or adding queue-time grace would weaken the frozen lifetime boundary.
  • Replacing the shared lock with an outbox/persistence redesign is unnecessary for this bounded defect.
  • Changing equality-at-expiry behavior would alter a separate existing contract; the inclusive boundary is retained and tested.

Compatibility

Valid requests, idempotent ticket timestamps, exact head/policy binding, publication provenance, JTI ordering, and UNKNOWN reconciliation retain their contracts. Requests whose credentials expire in the queue now fail closed. No schema, dependency, workflow, protected context, policy bundle, or baseline changes are included. The main residual risk is interpreting transaction-entry freshness as a remote publication deadline.

Validation

Independent local reproduction and validation completed on this exact diff:

  • Original service with the new regression: four methods ran with five expected failing assertions.
  • python -m unittest tests.test_repo_sentinel_signer_time -v: four methods passed, including admission/finalization subcases.
  • python -m unittest discover -s tests -p 'test_repo_sentinel_signer*.py': 80 passed.
  • python -m unittest discover -s tests -p 'test_*.py': 258 run; 253 passed and five platform skips. The skips concern symlink availability and a POSIX-only bootstrap test.
  • Changed-file pre-commit, Ruff lint/format, tags, Markdown, and scanner checks passed. The no-baseline changed-file scan reported no findings.
  • Final diff/whitespace and privacy review passed. Fixtures are synthetic and contain no credentials or private machine paths.
  • The signed commit verifies locally, and its diff matches the independently reviewed patch.

See docs/design-decisions/THREAT-BOUNDARY-AUDIT.md and docs/design-decisions/SECURITY-INCREMENT.md for the full reproduction and evidence limits. Operational notes in those records describe the audit-time state.

This security-boundary change remains draft for delayed review. Remote CI on e5c6105 passed all seven visible checks, including the changed-file gate, synthetic PASS/FAIL/redaction contract, baseline audit, taxonomy/front matter, and changed-Markdown lint. Final remote diff review matched the independently reviewed content; GitHub uses different function labels in two diff hunk headers.

GitHub now verifies this signed commit (verified: true, reason: valid) using the account's public noreply identity and the original GPG key. The identity metadata correction preserves the reviewed source tree, parent, and commit message.

Rollback

Revert this commit. No migration, deployment, or policy change is needed; reverting also restores the demonstrated stale-time weakness.

@stacknil
stacknil force-pushed the stacknil/authority-boundary-increment branch from 1983ff1 to e5c6105 Compare October 15, 2026 10:31
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