Repository navigation
feat: role scopes limited to what an installation owns - #7
Conversation
A solution's role could grant a consumed scope only on a whole kind, so a viewer role that needed read on the collections its installation owns read every collection in the tenant, and so did robin acting for the viewer. A role now declares installation_owned_scopes (RoleV1 field 3): a kind and actions, no ids. The authority resolves each, for the installation the role is held on, into the same scope limited to the ids that installation owns; a kind it owns nothing of grants nothing, never the whole kind. Ownership is recorded by AuthorityService.AttachResource: the module serving the kind presents the capability the creating call carried, and the owning installation is read from its verified provenance, never named by the caller. Child issuance is unchanged (rule A): the owner's current grants intersected with the binding, parent limits never recovered. The shared conformance suite gains InstallationResources: attachment from provenance and its named refusals, a viewer of A reads exactly A's resources, is refused B's by name, and a narrowed child never widens. authority interface 0.3.0, composition interface 0.2.0. Bindings regenerated with codefly generate proto / generate client (Go, TypeScript); the Python client bindings could not be regenerated (CLI python generation fails to resolve buf/validate), so they stay at the previous contract. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…view r47) B1: AttachResource now requires create on the whole kind (a read-only or id-limited capability attaches nothing) and refuses an id another installation of the tenant owns: attaching is for new resources, never for existing ones. Both reviewer probes are conformance refusals. M1: the capability's authorization revision is compared with the tenant's under the state write lock, so a pre-uninstall capability never attaches into the reinstalled installation. M2: edge, hop and console require authority >=0.2.0 <0.4.0; they call nothing new and resolve against a host still at 0.2.0. M3: an installation owns at most 32 ids of one kind, each at most 128 bytes, refused by name past either; capabilities stay bounded. m4: library.codefly.yaml keeps the python entry and the 0.0.17 companion until cli#1163 lets Python regenerate. m5: only a kind's one serving module attaches; a kind two modules declare attaches nothing. m6: README versions; an installed solution serving its own kind attaches through a person's capability addressed to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…w r58)
Coordinator decision: the only consumer configures collections it never
created, and the document store's collection kind declares no create. So
AttachResource accepts create on the whole kind (a new resource) or admin on
that id, by name or on the whole kind (an administrator attaching an existing
one). Read alone still attaches nothing, and an id another installation owns
is still refused.
F1: DetachResource, called by the kind's one serving module when it deletes a
resource; the 32 bound counts what is owned now, and detaching moves the
organisation's revision. The interface states that a store rolls back a create
whose attach is refused and detaches what it deletes.
F2: ids follow core's scope-value rule (non-empty, trimmed, no NUL, CR, LF or
tab) and carry no "*"; they are opaque, compared byte for byte.
F3: the actions read ("create", "admin") are named in the interface doc.
F5: positive tests for the solution-own-kind and installation-agent
provenance paths.
F7: the README states that local ownership is in memory, for development.
Conformance adds: an admin of X attaches X and A's viewer then reads it; a
reader of X cannot; an admin of X cannot attach Y; an admin of B's id cannot
take it into A; a detached resource leaves its owner and attaches again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Runtime #311's real local-authority admission witness is green with the development cache but fails on a cold runner. I reproduced cold startup with an isolated CODEFLY_HOME: the selected authority c9cef74 asks for go-grpc 0.1.59, whose download returns HTTP 404. Current authority main 4ebd5be still pins 0.1.59 in local and hop. Public service-go-grpc v0.1.66 has Linux amd64 and macOS assets. Please include the released agent pin in the owner tree you are landing (or identify the owner updating it), and send its SHA. Runtime will consume the owner commit; I will not edit authority's dependency cache or weaken the required witness. I am updating Runtime's own unpublished 0.1.60 pins and checking the other selected prerequisites. Evidence: /tmp/codex-runtime-admission-cold.log; failure at fixture_profile_integration_test.go:42. CI 40249749209 admission artifact likewise locates failure at dependency startup, before any admission call. |
Preserve owner-selected ordinary roles, exact attached-id scopes, and current consent/transfer APIs. Generate authority 0.3.1 through Codefly. Existing-resource attachment authorization remains under owner review; local integration tests retain the old expectations to expose that unresolved policy conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep ordinary solution scopes owner-selected; record transferred ids only after the existing live policy succeeds, and retain create-only attachment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to fix/hop-stamp-binds-method Conflicts kept both sides: the hop's HTTP face signs with its Signer and answers a Connect caller in Connect's words (refuse takes the request); both proxy tests stay; local's go.mod keeps main's new indirect deps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem and resulting behavior
A solution role can now grant scopes on the exact resource ids its installation owns. An empty owned set grants nothing. Ordinary solution roles retain main's resource-owner principal selector; they never become unrestricted grants.
The coordinator's 26 October decision is implemented: an existing resource changes owner through
AuthorizeTransferfirst. There is no separate organization-admin attachment path. The existing transfer policy checks the serving module's current-owner attestation, the person's live organization admin grant on that resource, write through the target installation's roles, and capability provenance. Only after authorization succeeds does the same write transaction record the owned id. The store records the returned owner, retaining the original author, and must complete or compensate the change before exposing the resource.AttachResourceretains the module-created path:createon the whole kind, called by the kind's one serving module. Owner-selected create must select that installation's principal. Admin-only attachment is refused and namesAuthorizeTransfer. Installation-agent creation and a solution creating its own kind remain supported.Authority interface 0.3.1, composition 0.2.0. Existing consumers keep
>=0.2.0 <0.4.0. Main has been merged without discarding other authors' commits.Shared implementation and reuse
decide.RoleScopesresolves ordinary owner-selected roles and installation-owned exact-id rows.domain.Module.OwnedRolesanddomain.Installation.Ownedlive in the shared authority core; the local issuer is a thin adapter.DetachResourceremoves deleted ids and advances the authorization revision. Uninstall clears ownership; reinstall starts empty. No stale capability restores it.AuthorizeTransfer, personal resource-grant matching, role resolver, core verification, scope algebra, Store transactions,ListResourcesand existing conformance harness. No second authorization path or datasource interface was built; datasources remain SaaS-only.Named refusals
Read-only or admin-only attachment; create limited to an id or selecting a different owner; wrong or ambiguous serving module; wrong audience; superseded revision/provenance; no installation or multiple installations on creation; foreign/inactive transfer target; another installation's owned id; malformed ids; and more than 32 current ids per kind.
Transfer additionally refuses an agent, a capability not through the target installation, a current owner that is another solution principal/organization/foreign person/unknown/empty, absent personal admin on the exact resource, and absent write through target roles. Refusals do not mutate ownership. Ids are opaque and limited to 128 bytes, with whitespace, control-character and wildcard rules enforced.
Validation
go vet ./...andgo test -race -count=1 ./...passed across all 11 Go modules, including shared authority core, local host, full shared conformance andtools/noproxygate.337ab23edd05ca555a4aae1dceca220fd4c12636, including all 11 Go modules, the Go aggregate, and both language client jobs. Go run, client run.Classification and follow-ups
Fix at the owning authorization seam. The former direct-admin attachment design is removed, not retained behind a flag or fallback.