Skip to content

fix: a child names the owner its parent's scopes are selected to - #78

Merged
antoinetoussaint-byte merged 1 commit into
mainfrom
fix/child-names-the-parents-owner
Oct 27, 2026
Merged

antoinetoussaint-byte merged 1 commit into
mainfrom
fix/child-names-the-parents-owner

Conversation

@antoinetoussaint-byte

Copy link
Copy Markdown
Contributor

What we are trying to do

A person reading through a solution (the wiki) must reach the document store as the solution's installation allows, and nothing more. Since codefly-dev/authority#7, the authority issues a person's Work Context at a solution with every role scope selected to the installation's principal (resource_owner_id). It then holds a child of that context to what that owner holds there: a child is the owner's current grants intersected with the binding (authority-core decide.Issue / scope.Attenuates).

issueChild sent its ask without an owner. The authority reads an owner-blind ask as covering every owner's resources, so it refused every call relayed through a solution:

issuer: refused: a child widens what its owner holds through binding "documents": a capability issued through a solution is confined to its principal's data, and the person's own grants never flow into it

This was observed live in the wiki playground before the change.

What changed

  • selectedOwner(wc) returns the one owner that a checked Work Context's effective scopes select. The effective scopes are the current actor's granted_scopes, or authority_scopes when no actor has hopped. If the scopes select no owner, or more than one, it returns "": the runtime never chooses between owners. In that case the authority refuses an ask that needed an owner, and says why.
  • The viewer (requestViewer) records that owner from the authority's own Check answer (viewerGateway). The runtime still decodes nothing.
  • issueChild names that owner on every scope a ForParent child asks for. A gateway built outside a request names no owner.
  • The authority client and hop libraries move to authority main f41cc2ba for WorkScopeV1.resource_owner_id. go moves to 1.27.3 with them (the libraries require it).

Reused: the authority's generated client, the hop library's IssueForParent, and the Check answer the runtime already asks for on every request. Not added: any token decode, any second issue path, or any new scope field on the public Scope type.

Classification: fix, at the place that owns the behaviour. This runtime builds every child ask. The wiki's local proof had patched this function by replace, decoding the parent token; this PR replaces that patch with the authority's answer.

Tests

  • TestTheSelectedOwnerIsTheOneTheEffectiveScopesSelect covers: no scopes; owner-blind scopes; one owner (repeated, mixed with owner-blind); two owners (none named); the current actor's grants winning over the authority scopes; an actor granted no owner.
  • TestAChildNamesTheOwnerItsParentIsSelectedTo checks, through the stand-in authority:
    • a child of a person's context at an installation names the installation's principal on every scope, and keeps its ids;
    • a child of an owner-blind context names none;
    • a gateway with no checked viewer names none.
  • TestThePassthroughRelaysAsTheViewer now also relays as a person at an installation and checks the owner on the child's ask.
  • Mutation check: with ResourceOwnerId: owner dropped from issueChild, both owner tests fail.
  • Gates: go test -race ./... -count=1, go vet ./..., gofmt -l . and go mod tidy -diff.

Proved end to end

obin-ai/core-solutions wiki playground (the companion PR, pinning this head 8ea6c260 with no replace), naming scope owf2, 2026-10-27T02:20Z. The run used document store aca93a1f (#594, owner-aware), robin 73620352, authority main f41cc2ba, and the CLI built from cli main c791071b. There were no local patches.

  1. Dev, an Acme editor, uploads through the wiki: 200. The store logs collection attached to the installation it was created for installation=fc555ea7-… owner=32fa57d8-….
  2. Dev's ListCollection returns 200 with the document, and Search returns 200 with the hit, both through the hop.
  3. Omar and Zoë, through Globex's installation, get 403 on ListCollection of Acme's collection: documents.collection:read is limited to the collections 3c5ff48c-… owns. Search returns nothing.

Not verified / follow-ups

  • No tag is cut because this PR is not merged. The wiki pins this branch head's pseudo-version, so please merge with a merge commit to keep 8ea6c260 reachable, then cut the release and re-pin the wiki.
  • obin-ai/core-solutions solutions/proposals also pins e53e044. It moves when that solution relays through a binding under owner-selected roles; this PR does not touch it.

🤖 Generated with Claude Code

Since codefly-dev/authority#7 a person's Work Context at a solution carries
its installation roles selected to the installation's principal, and the
authority holds a child within what that owner holds (child = current grants
intersected with the binding). issueChild asked owner-blind, which reads as
every owner's resources, so every relayed call through a solution was refused
as "a child widens what its owner holds through binding ...".

The viewer now records the one owner the authority's Check answer selects
(the current actor's granted scopes, or the authority scopes when no actor
hopped), and every ForParent ask names it; none or several owners name none.
The authority client and hop move to authority main f41cc2ba for
WorkScopeV1.resource_owner_id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@antoinetoussaint-byte
antoinetoussaint-byte merged commit fc89cfa into main Oct 27, 2026
1 check passed
antoinetoussaint-byte added a commit that referenced this pull request Oct 27, 2026
… (x-codefly-operation)

Beside the authority policy of each operation whose policy requires only
read, Server.InterfaceArtifact now writes core's x-codefly-operation marker,
which core itself derives from that policy (runnable.RouteMarker, core#852).
`codefly generate runnables` derives a Runnable package — and so a tool —
from every marked route, as it does from every method a module serves behind
the hop.

- Operation.Exclude keeps a read from every agent, as codefly.runnable.v0.exclude
  keeps a module's method. The MCP route and every relayed route carry it.
- InterfaceDocument marks nothing: the marker names the audience the serving
  runtime's hop admits, which only the Server knows. A solution must commit
  Server.InterfaceArtifact's output, and the README and CHANGELOG say so.
- Every defined object closes additionalProperties, which core's bounded
  profile requires of a fixed shape.
- Core moves to v0.19.7-0.20261026182446-518714d046af (core#852 merged).

Rebased onto main after #78: main's authority-client and hop pins and its
Go 1.27.3 bump are kept, core alone moves.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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