Govern sharing of restricted data by observer verification - #340
Draft
Maximo-Guk wants to merge 8 commits into
Draft
Govern sharing of restricted data by observer verification#340Maximo-Guk wants to merge 8 commits into
Maximo-Guk wants to merge 8 commits into
Conversation
The flag's real meaning is "this observation contains restricted data". What the platform does about that is policy, which shouldn't be baked into the name -- the next commits replace the all-or-nothing lockdown with per-collaborator observer verification. ObservationDescription.prohibitAllSharing and GadgetMetadata.sharingProhibited both become containsRestrictedData. No alias: this is a hard rename, so the gatekeeper call sites move in the same commit. The overseer's durable singleton keeps its historical storage key, since typed-storage keys are property names and renaming one would silently unlatch every workspace that already carries it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PermissionEdge gains a `pending` flag plus per-attempt `pendingAttempts` claims, so a redeemed share key can be recorded without granting anything until its recipient is verified -- and concurrent redemptions of one link can each withdraw only their own claim on failure. Also restates what containsRestrictedData means now: sharing is governed by observer verification rather than banned outright. The server still implements the old behavior; that changes in the next commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sharing a workspace that has read restricted data is no longer refused outright. Instead authorizeObservation admits the observation only when every current collaborator is already verified as an observer of the producing gatekeeper, held to each collaborator's role scope. Share-key redemption becomes two-phase: redeemShareKey writes a pending edge that grants nothing, the redeeming open() verifies the recipient at the role that edge would grant, and only then is it confirmed -- capped at the verified role, rolled back on refusal. This also stops a refused recipient persisting in the sharing graph, which the previous flow left behind. receiveExternalMessage now routes through authorizeCollaborator too -- the single gate both non-owner entry points share -- verifying external callers (non-interactively) where the old code checked only the role. Known races in the surrounding observer machinery -- most of them preexisting -- are deliberately not fixed here: each is marked with a TODO naming the PR #306 (observer-verification-fixes) commit that addresses it, so this PR stays reviewable as the model change alone. Tests follow in a later commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Carried from PR #306 (observer-verification-fixes, commits ddbbbb5 and 5924efa): the coverage guard (#assertSensitiveObservationCoverage) reads the *persisted* observer record from other turns, so a collaborator whose live re-verification just failed must not keep a persisted entry saying they are covered -- until now a revoked collaborator stayed "verified" for restricted reads until their next successful open. fail() now drops the failed gatekeeper from the persisted accountChoices synchronously with the failure determination, getVerifier moves inside the per-gatekeeper try so a verifier-acquisition rejection scrubs like any other refusal (and surfaces the descriptive denial rather than the raw RPC error, with no mid-flight Promise.all rejection to stale the rollback snapshot), and the terminal catch de-registers invalidated registrations alongside newly-added ones. Carried into this PR because it is a stated precondition of the coverage guard; the guard's other soundness precondition (the out-of-scope prune) follows in the next commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Carried from PR #306 (observer-verification-fixes, commit e1b36c3): the coverage guard's key-presence check rests on the invariant "entry present => verified at this collaborator's most recent open". Without the prune, a "use" collaborator opening while a connection is unbound from every gadget verifies nothing against it, yet their stale entry survives to be trusted by the guard the moment the connection is rebound -- an entry their last open never verified. ensureObserver's step 2 now drops every account choice for a gatekeeper outside the collaborator's live verification scope, even when the remaining scope is empty (that is exactly the everything-unbound open). The gatekeeper-side registration is deliberately kept: it preserves forward exclusion via byObserverId, and the next successful open's addObserver overwrites the verifier. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
restricted-data.test.ts covers the legacy-name reader; sharing.test.ts gains the pending-redemption model cases (adoption, claim-counted reverts, assertGrantAllowed on every grant vector) and loses the hasAnyShares cases with the method; restricted-producer-removal.test.ts covers the removal guard and ambient reconciliation; restricted-observation-latch.test.ts pins the synchronous coverage check and the removed-connection refusal; verification-scope.test.ts pins the #scopeGeneration topology detection (commit-gate rollback cases stay with PR #306, whose fix they pin). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
sensitive-observations.test.ts drives the whole model against real DOs and the extended test gatekeeper (per-resource restricted flag, controllable verify outcomes): the latch, the coverage guard, pending redemptions and their concurrent/mid-topology/mid-revocation windows, the producer-removal guard, and ambient reconciliation. The mid-revocation case pins only the denial and the inert edge -- the denied open's observer-record residue is the deferred commit-gate fix (PR #306, commit 0f39a79). external-message-verification.test.ts proves receiveExternalMessage holds collaborators to live observer verification (with the gatekeeper's own refusal reason surfaced) and denies a "use" collaborator by role before verification runs. observer-role-scope.test.ts covers role-scoped verification needs. The fixture gains an external control surface, real per-account sessions, and empty required-secrets hardening so local .dev.vars never leak into suites. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
docs/observers.md gains the coverage rules, the residuals, and the per-collaborator verification flow; docs/sharing.md documents pending redemption, the policy hooks, and the revocation interplay. Passages that describe the deferred observer-machinery hardening (the verification commit gate, per-profile serialization, the revocation-restart fail-closed window, the exclusion-gate pending map, the external path's commit-time re-assertion) are written as "Known limitation, see PR #306" notes matching the code's TODO ledger. The plan doc's commit sequence is updated to reflect this split. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Maximo-Guk
marked this pull request as draft
August 25, 2026 23:37
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.
WIP