registry: "elsewhere" owners and the signed owner file #19
Labels
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
#341 registry: verified domains (DNS TXT check and badge)
torbscript/language
#342 client: show "elsewhere" owners and owner verification
torbscript/language
Reference
torbscript/language#19
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
RELEASE.md section 7.1 lists the owner kinds of the registry. This issue builds the "elsewhere" owner: an organisation claims its owner on the public registry and states the URL of its own registry; the public registry then serves nothing for that owner and says where it publishes. It is the registry's answer to dependency confusion (7.1, 7.6). The issue also introduces the signed owner file
index/<owner>/owner.trbof 7.4, which nothing writes today; verified domains (#341) and the client (#342) build on it.Verified domains were part of this issue's first version and are split off: see Dependencies.
What exists today (main
787f63f)tools/registry: tableownershas a columnelsewhere TEXT(src/database.trb) that no code reads or writes;ownerView/OwnerView(src/registry.trb) show name, kind and members only; organisations are created byPOST /api/1/owners, owner calls need theownersaction and aTorb-Code(proved).index/<owner>/owner.trb. The client never reads it;compiler/src/package/signing.trbandindex.trbsign and check records of package files andconfig.trbonly.Source
Design record point
7.1 table row Elsewhere and the paragraph "The 'elsewhere' owner is the answer to dependency confusion", plus 7.4's
owner.trbline. The record gets a short "as built" note under 7.11 and the "Not built yet" list loses "elsewhere" owners.Design (decided by the loop, see the comment of 2026-10-12)
Claim:
PUT /api/1/owners/<owner>/elsewherewith{url}, undo withDELETEof the same path. Only an organisation, only by a member with roleowner, token actionowners,Torb-Codeas for every owners call (proved). Operator token allowed like for members.URL rules:
https:only, a host name (no IP literal, nolocalhost), no user info, no query or fragment, at most 200 bytes, parsed withstd/uri. The registry never fetches it.Owner with packages: a claim on an owner that already has a package is a
409(published releases are immutable, 7.3; the moderators can resolve it by hand). Publishing to an owner that claimed elsewhere is a409that names the URL; so is creating a package of it by any route (publish, trusted publishing exchange).The owner file: one signed record, replaced whole (the one file of the index that is not append-only, because it is state, not history):
elsewhere:anddomain:are left out when unset.domain:is part of the record type, the writer, the reader and the signed text from the start (empty here; #341 sets it), so adding verified domains changes no format. It is written for every owner (person and organisation) when the owner is created, when a claim changes, and filled at start for an owner without one (like package pages); mirrored like index files.Signature: over a text
torb index owner 1, the owner, kind, created, elsewhere and domain, quoted the wayrecordMessagequotes, incompiler/src/package/signing.trb/index.trbshared by the write service and the client. A rolled-back file served by a mirror is the same as a withheld update (7.14) and accepted.API:
OwnerViewgainselsewhere(empty if none) anddomain(empty here);torb owner listis #342's.Acceptance criteria
PUT/DELETE /api/1/owners/<owner>/elsewhereas designed: success returns theOwnerViewwithelsewhere; refusals tested: person owner (400), non-owner member (403), missingTorb-Code(401/403asprovedanswers), bad URL (http, IP literal, user info, query, over length:400), owner with a package (409), unknown owner (404)elsewhereis refused with a409naming the URL; afterDELETEit works againindex/<owner>/owner.trbis written for every owner (created, claim, undo), filled at start for an owner without one, mirrored, and signed;compiler/src/packagehas the record text, a writer and a reader that rejects a changed, unsigned or other-owner recordtools/registry/tests(newelsewhere.test.trb, natively and in the VM) andcompiler/tests/packages.test.trb(record text, signature roundtrip, tampering)tools/registry/README.md(API list),docs/design/RELEASE.md7.1/7.4/7.11 ("as built" note, "Not built yet" updated) and the generatedskills/are in step;sh tools/gates.sh agreen in forge CISeed impact
No: TorbScript only, no new native, no driver flag, no std name looked up by string.
Size
One PR, two Conventional Commits: (1)
feat(compiler): owner record text/writer/reader/signature with tests; (2)feat(registry): database access, endpoints, publish refusal, file writing, tests, docs. Worker: opus/high (security-relevant,tools/registry); architect review of the diff before the PR.Dependencies
None. Followed by #341 (verified domains) and #342 (client), both of which wait for this issue.
Moved from the planning lists of the docs; the design record stays the specification.
[loop:torbscript] intake: in scope (author orion, label loop). Registry domain verification and "elsewhere" owners per RELEASE.md section 7.11,
tools/registry; security-relevant (opus/high worker, architect review); verification rules are specified in the design record, gaps become an owner decision in refine. Release freeze for 0.1.0 (2026-10-06) holds new PRs, next: refine (queued)[loop:torbscript] refine: still queued behind the intake order. next: waiting (ready buffer full: #4, #163, #164, #223 are ready) until 2026-10-10T04:00:00Z
[loop:torbscript] refine: held back, the ready buffer is at its target of 4
readyissues (#23, #24, #312, #313), next: waiting (ready buffer full) until 2026-10-12T11:22:04Z[loop:torbscript] claim refine by session:loop-torbscript-20261012 until 2026-10-12T18:24Z
registry: verified domains and "elsewhere" ownersto registry: "elsewhere" owners and the signed owner file[loop:torbscript] decided by the loop: the issue was larger than one PR (owner file, elsewhere owners, DNS verification, re-check, client), so it is split along the design record's own seams; none of the decisions below is owner-reserved.
owner.trb; #341 = verified domains (DNS TXT, badge); #343 = re-check of verified domains; #342 = client output (torb add,torb owner list). Dependencies are set in the forge: #341 and #342 need #19, #343 needs #341. Only #19 carriesreadynow; the others meet the definition of ready in content and get the label when their dependency has landed.owners.elsewhereexists in the database and is unused;index/<owner>/owner.trbis described in 7.4 but written and read by nothing; the client has no owner knowledge;std/network/std/dnsalready do TXT lookups.domain:is in the type, writer, reader and signed text from the start so #341 changes no format. Why: a format change after the first signed files exist would invalidate signatures or need versions; signing keeps a mirror from inventing an "elsewhere" URL (7.14).ownersaction andTorb-Codelike every owners call;https:URL only, no IP literal/userinfo/query/fragment, <= 200 bytes, never fetched (no SSRF surface); refused with 409 for an owner that already has a package (releases are immutable, 7.3); publish to such an owner is a 409 naming the URL. The URL is only ever printed by the client, never bound automatically (a stranger's claim must not rebind anyone's build)._torb.<domain>withtorb-owner=<owner>; no nonce, because only the domain's DNS controller can create the record and the owner name binds it. Checked in the claim request, resolver = system default,REGISTRY_DNS_SERVERSto override; DNSSEC stays out (DNS.md). One owner per domain, at most 5 domains per owner.owner.trbtoday).[loop:torbscript] refine: Definition of ready met: body rewritten (goal, state of main
787f63f, design record points 7.1/7.4/7.6/7.11, testable acceptance criteria, seed impact: no, size: one PR / two commits), split into #341, #342, #343 (dependencies set), no owner decision needed. Labelreadyset. Worker usage about 110k tokens (estimate), next: implement[loop:torbscript] claim implement by session:loop-torbscript-20261012 until 2026-10-12T22:28Z
[loop:torbscript] claim review-fix by session:loop-torbscript-20261012 until 2026-10-13T00:03Z (PR #347: pdisc check red; the first worker died on an output-size error after pushing)
[loop:torbscript] review-fix:
pdisc / pdiscwas red because thetools/registry/README.mdbody changed (the elsewhere-owners rows and the owner-file paragraph) while its.pdisc-sidecar.yamlstamp (body_hash) still had the old value. Changed: the sidecar summary now names the elsewhere owners and the signed owner file (under 300 chars), the entry is restamped (pdisc.py stamp) andINDEX.mdregenerated; the fix is folded into the second commit so the PR stays two Conventional Commits.mainhad moved, so the branch is rebased on it (linear, no merge commit;tools/check-commits.sh origin/main HEADclean) and force-pushed with lease toloop/19-elsewhere-owners(PR #347, headaa9488d5). No other review findings were open on the PR or this issue. CI onaa9488d5: all checks green (pdisc, gates, tier A/B, registry, same-C, playground, VS Code). Worker usage about 110k tokens (estimate), next: review