Add a completeness fence over the GraphQL mutation surface#219
Open
beardthelion wants to merge 2 commits into
Open
Add a completeness fence over the GraphQL mutation surface#219beardthelion wants to merge 2 commits into
beardthelion wants to merge 2 commits into
Conversation
added 2 commits
July 18, 2026 17:22
Gate the GraphQL mutation surface the way REST is gated, as a SEPARATE guard with its own bucket table (a guard over a heterogeneous set must classify per member, INV-1). every_graphql_mutation_has_its_gate asserts the mutation set is complete (every mutation classified) and that each carries its gate marker. Completeness is derived from async-graphql's own introspection: the field names come from the engine as structured data, so no source-text or SDL-format shape (a brace or async fn in a comment or string, a whitespace/generic/skip variant, a brace in a rustdoc description) can hide a live mutation. A new unregistered mutation, including a repo-write, fails the build. The marker check (does each resolver body call its gate) is a best-effort static backstop, bounded to each resolver's own comment-masked, string-aware body. It is explicitly not the completeness guarantee and not load-bearingness: a marker inside a string literal is a documented vacuity residual, and the adversarial sqlx tests in graphql/mutation.rs are the real proof the gates reject. Verified by execution: an unregistered mutation reddens (unclassified), a removed did_matches gate reddens (missing marker), the clean tree is green; no DB, no feature flag.
…tate README's known limitations, the OSS-readiness live-network blockers, and the maintainer roadmap still listed GraphQL mutation auth as an open item, which contradicts #87: GraphQL mutations already require a verified signer bound to the acting DID. Reconcile each to the shipped reality while keeping the genuinely-open nuance: the GraphQL mutation surface is the agent-task queue, repo writes stay REST-only, and no owner-gated repo-write mutation is exposed over GraphQL. The every_graphql_mutation_has_its_gate fence forces any new mutation to be classified in its table; owner-gate and REST parity stay the INV-1 review check.
Contributor
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughGraphQL authorization coverage now verifies the exact mutation schema and required resolver gates, with comment- and string-aware source inspection. README and security documentation now describe verified signer requirements, agent-task-only mutations, and REST-only repository writes. ChangesGraphQL authorization fence
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
beardthelion
pushed a commit
that referenced
this pull request
Jul 19, 2026
…ber (#195) Resolve the three review findings on head 07abcc6. Bound the two new real-node probes (protected-branch push, PR-diff) on a timeout-bearing client, so a wedged git subprocess fails the suite rather than hanging it until CI kills the job. Withhold the pushed secret blob's OID (full and [..12] short form) in the PR-diff denial. The old branch was dead code: the OID was never in the fixture seed map, so build_branch_push_body now returns the pushed blob OIDs. Drive every caller-self runtime deny the registry claimed but only source-marker checked. create_task, claim_task, and register are a new SignerSelfGate class (a body DID field bound to the authenticated signer); complete_task and fail_task are a MultiPrincipalGate assignee arm (the caller must equal the task's stored assignee). Each runs hostile-then-authorized against a real node. A completeness guard, derived from a scan of src/api, now requires every did_matches(caller, X) handler to be a driven registry row, and the module doc is reconciled to the REST surface (the parallel GraphQL mutation gates are fenced separately, #219). Every gate is mutation-verified load-bearing: reverting a production did_matches line drives its hostile probe RED, and the completeness guard goes RED when a driven row is dropped or the classifier is starved. No production code changed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
GraphQL mutations have required a verified signer since #87, but nothing forced future mutations to stay gated, and README / OSS-readiness / roadmap still listed the auth as an open item. This adds the missing guard and reconciles the claims.
Fence
every_graphql_mutation_has_its_gate(crates/gitlawb-node/src/api/mod.rs) gates the GraphQL mutation surface the way REST is gated: a separate guard with its own bucket table (a guard over a heterogeneous set classifies per member, INV-1). It asserts the mutation set is complete (every mutation classified) and that each carries its gate marker.Discovery comes from async-graphql's own introspection, so the required set is derived from the mounted schema, not a hand-list: no source-text or SDL-format shape can hide a live mutation, and a new unregistered mutation (including a repo-write) fails the build. RED-verified both ways: an unregistered mutation and a removed
did_matchesgate each redden the guard; clean tree green. No DB, no feature flag.Scope and limits
The marker check (does each resolver body call its gate) is a best-effort static backstop, not the completeness guarantee and not load-bearingness: a marker inside a string literal is a documented vacuity residual, and the adversarial
#[sqlx::test]s ingraphql/mutation.rsare the real proof the gates reject.Docs
README known-limitations, the OSS-readiness live-network blockers, and the maintainer roadmap are reconciled to the shipped state: mutations require a signer; the GraphQL surface is the agent-task queue; repo writes stay REST-only; no owner-gated repo-write mutation is exposed over GraphQL.
Test-only plus docs; no request-path change.
Summary by CodeRabbit
Security
Documentation