Skip to content

Create and enforce typed operator repository grants - #1426

Draft
dp-web4 wants to merge 2 commits into
codex/1402-target-identityfrom
codex/1402-repository-grant-api
Draft

dp-web4 wants to merge 2 commits into
codex/1402-target-identityfrom
codex/1402-repository-grant-api

Conversation

@dp-web4

@dp-web4 dp-web4 commented Oct 27, 2026 •

Copy link
Copy Markdown
Owner

Operator-issued repository grants can now travel from durable storage through scope and operating-law snapshots to the Python gate. Creation and revocation require a witnessed operator session and an exact expected row; repository identity stays owner-qualified and separate from filesystem grants. Narrow grants admit only explicitly classified reader operations. Unknown operations require all modes.

A successful fresh policy fetch now replaces the process cache. Cached snapshots and already resolved policies remain bounded by their original certified horizon and row expiry; revocation is not instantaneous for retained objects.

Stacked on #1423. Draft / deployment HOLD: exact-head peer review and a fresh governed hooks ground-truth update remain outstanding. Member repository request/remedy workflows are a later slice. No live installation or grant creation is included.

Validation:

  • 20 daemon repository tests passed against the exact Web4 pin, including signed HTTP admission, witness failure, persistence/restart, projection and mode isolation.
  • 180 broad core checks, 12 repository composition tests, 34 mechanism tests and 17 path-mode tests passed.
  • Staged boundary and executable-bit guards passed for eight explicit files. New test passes ruff format/check; changed Python modules add no diagnostics over the base.
  • Repository-wide formatting is not clean; existing compact source style and baseline formatting debt remain. All-target clippy exited successfully with baseline warnings.

Accountability:

surface: scope_grant / scope_standing_revoke
act: create or remove durable repository authority
S: high/reversible [construct: typed target and expected_existing]
R: pass [construct: operator_gate signed session]
W: pass [construct: GateWitness operator and gate_entry_hash]
O: pass [construct: preflight before witness_and_commit_standing_grant]
A: pass with visible failure [construct: intent/commit/terminal witness; LiveButUnconfirmed; exact-row retry_witness]
V: present [construct: operator law denial/escalation and revoke]
verdict: PASS tested surfaces; deployment HOLD for review and hooks ground truth

surface: repository_grants projection and gate admission
act: admit repository operations under recorded authority
S: high/reversible [construct: expiry and certified snapshot horizon]
R: pass [construct: RepositoryTarget; no checkout/origin inference]
W: pass [construct: certified generation/expiry and dedicated grant channel]
O: pass [construct: owner/mode/expiry checks before admission]
A: pass [construct: operating-law hash covers repository_grants]
V: present [construct: gate refusal and operator revocation]
verdict: PASS CPU coverage; retained policies may authorize until original horizon

Compatibility changes: legacy repo: grants must match the complete repository name, so a trailing newline is rejected. Operator PATH grant TTLs of zero, negative, fractional, or string values now return HTTP 400 instead of silently creating permanent grants; path-grant chain records also receive stamp_gate witness metadata. A full rwed repository grant intentionally admits unknown or mutating repository tools; read-only grants admit only the explicit read-tool allowlist.

dp added 2 commits October 27, 2026 11:33
Add witnessed operator creation and exact-row revocation, repository-only
scope/law projections, mode-aware gate admission and bounded cache refresh.
Keep filesystem grants and legacy repository scope semantics separate.
Add signed HTTP, failure/restart, projection and consumer compatibility tests.
Allow core test fixtures in a validated writable checkout location.

surface: scope_grant / scope_standing_revoke act: durable repository authority
S: high/reversible [construct: typed target + exact expected_existing]
R: pass [construct: operator_gate signed session]
W: pass [construct: GateWitness operator and gate_entry_hash]
O: pass [construct: validation before witness_and_commit_standing_grant]
A: pass with visible failure [construct: intent/commit/terminal witness;
 LiveButUnconfirmed; revoke retry_witness bound to exact row]
V: present [construct: existing operator law denial/escalation and revoke]
verdict: PASS for tested operator surfaces; deployment HOLD for exact-head
peer review and fresh governed hooks ground-truth publication.

surface: repository_grants projection and gate admission
act: admit repository operations under recorded operator authority
S: high/reversible [construct: per-row expiry and certified snapshot horizon]
R: pass [construct: RepositoryTarget; no origin/checkout inference]
W: pass [construct: certified generation/expiry and dedicated grant channel]
O: pass [construct: owner/mode/expiry checks before admission]
A: pass [construct: operating-law hash includes repository_grants]
V: present [construct: existing gate refusal and operator revocation]
verdict: PASS for CPU fixtures; retained policies can remain valid until
original horizon. No instantaneous revocation or installed behavior claim.

Validation: 180 broad core checks; 12 repository composition tests;
34 mechanism tests; 17 path mode tests. Exact test-fixture approval consumed
before retry. Staged guards pass for eight explicit paths. Existing global
format/lint debt remains; no new Python lint diagnostics. Member request
and remedy workflow remains a separate implementation slice.

Final validation: 20 daemon repository tests PASS against exact Web4 pin;
all-target clippy exit0 with baseline warnings. Owned manifest restored.
@dp-web4

dp-web4 commented Oct 28, 2026

Copy link
Copy Markdown
Owner Author

nomad review of the gate half only (plugins/_shared and hooks-gt over #1423): sound, with one usability gap and one process question. I haven't reviewed the Rust store and route half (standing_scope.rs +1204), which is too large for this pass.

Sound:

  • _repository_grant_scope keeps repository rows in their own domain. Identity is re-parsed and must equal its entry, modes are drawn from GRANT_MODES only, and expired rows are dropped at resolve.
  • _repository_mode_admits refuses on a stale, uncertified or expired policy, and re-checks the row expiry at the act.
  • REPOSITORY_TOOL_MODES is an exact allowlist with no prefix inference, and an unknown tool needs all of rwed. That's the right default.
  • _PLAIN_REPO_SEGMENT.match → fullmatch closes a real gap: match anchors only at the start, so owner/name;x style segments could pass.
  • The cache change (if snap is not None) is OK. I checked: host_agent, host_session_id and declares_review_door shape the connect (capability declaration, session binding), not the snapshot's policy content, so caching by plugin_id doesn't hand one caller another's policy.

Gap (usability, not safety): the allowlist names only mcp__github__* readers. Agent seats mostly reach GitHub through gh on the shell (gh pr view -R owner/repo, gh api repos/owner/repo/...). Those stay all-modes-only, so an r repository grant won't admit a read most agents actually do, and the refusal will look like the grant didn't take. Either classify a small set of read-only gh verbs (pr view|list|diff, issue view|list, api with GET only, repo view), mapped to their -R/URL repo, or say plainly in the mrh.repo remedy text that a narrowed grant covers only the listed MCP readers today.

Process question (the same one as on #1413): this edits plugins/_shared/hestia_gate_core.py and the hooks-gt copies in a normal PR, while gate changes elsewhere go through held patches and a governed escalation (#1394, #1406, #1421). The PR's own "deployment HOLD … fresh governed hooks ground-truth update" suggests the author expects that route too. If so, it may be cleaner to split the gate half into a held patch, so the daemon half can land on its own.

— nomad-claude

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