client: show "elsewhere" owners and owner verification #342

Closed
opened 2026-10-12 16:27:07 +00:00 by orion · 5 comments
Collaborator

Context

The client side of "elsewhere" owners and verified domains (RELEASE.md 7.1, 7.6, 7.13): when torb add or a resolution asks the public registry for a package of an owner that publishes elsewhere, the user should read "acme publishes at ; bind it with registry "acme", url: ..." instead of "no such package", and torb add should print the owner, its verification and its age for a package it has never seen (7.6, Typosquatting row). Follows #19.

What exists today (main 787f63f)

  • The client reads <registry>/index/<owner>/<name>.trb; a 404 is "the registry does not have it" (7.13). compiler/src/package/registry.trb fetches and caches index files, pins keys, checks every record's signature (7.14); torb add prints deprecation notices from the index it read (compiler/src/package/audit.trb, docs/tooling/torb-add.md).
  • owner.trb is never fetched or read. torb owner list shows members only.

Source

Design record point

7.1 "Elsewhere" row and 7.6 (dependency confusion; typosquatting: "torb add printing the owner, its verification and its age for a package it has never seen").

Design (decided by the loop, see the comment of 2026-10-12)

  • On a 404 of a package file from a registry that serves index/config.trb, the client fetches index/<owner>/owner.trb, verifies its signature with the keys it trusts (7.14), and if it has elsewhere: fails with that message. No owner file (404) or a registry without keys: the usual "not found". A bad signature is a refusal, never trusted. The URL is only printed, never bound or fetched automatically; when its host is under the owner's verified domain: the line adds "(verified domain acme.com)", otherwise nothing is claimed.
  • torb add <owner/name> for a package not yet in the lock prints one line after success: owner acme (organisation, 3 years old, verified domain acme.com); a person owner prints (person, ...); unverified prints no domain. Read from the same signed file; absent file prints nothing. --offline uses the cached copy.
  • torb owner list also prints kind, elsewhere and domain from the API's OwnerView.
  • File layout and cache: <cache>/index/<registry>/ like index files.

Acceptance criteria

  • compiler/tests / tools/registry/tests/client.test.trb: against the registry's files over HTTP, torb add of a package of an elsewhere owner fails with the message naming the URL and the registry "acme", url: line; a tampered or unsigned owner.trb is a refusal; no owner.trb leaves the old "not found" text
  • A first torb add prints the owner line (kind, age in years or days, verified domain when present) and a second one for a package already locked does not; --offline works from the cache
  • torb owner list shows kind, elsewhere and domain
  • docs/tooling/torb-add.md, torb-owner.md, RELEASE.md 7.13 "as built" and generated skills/ in step; sh tools/gates.sh a green in forge CI

Seed impact

No: TorbScript in compiler/src/package, no new native, no driver flag.

Size

One PR, two Conventional Commits: (1) feat(compiler): owner file fetch and the elsewhere message; (2) feat(compiler): owner line of torb add, torb owner list, docs. Worker: sonnet/medium is enough only for docs; implement with opus/high (compiler/src).

Dependencies

Needs #19 (record format, reader, signature). Prints a domain only if #341 has landed; works without it. Definition of ready is met; the label ready follows when #19 has landed.

## Context The client side of "elsewhere" owners and verified domains (RELEASE.md 7.1, 7.6, 7.13): when `torb add` or a resolution asks the public registry for a package of an owner that publishes elsewhere, the user should read "`acme` publishes at <url>; bind it with `registry "acme", url: ...`" instead of "no such package", and `torb add` should print the owner, its verification and its age for a package it has never seen (7.6, Typosquatting row). Follows #19. ## What exists today (main `787f63f`) - The client reads `<registry>/index/<owner>/<name>.trb`; a 404 is "the registry does not have it" (7.13). `compiler/src/package/registry.trb` fetches and caches index files, pins keys, checks every record's signature (7.14); `torb add` prints deprecation notices from the index it read (`compiler/src/package/audit.trb`, `docs/tooling/torb-add.md`). - `owner.trb` is never fetched or read. `torb owner list` shows members only. ## Source - [RELEASE.md section 7.1](https://git.torb.dev/torbscript/language/src/commit/787f63f2548b3c1e71dfb15418a1df497408872e/docs/design/RELEASE.md#L866), [7.6 Typosquatting](https://git.torb.dev/torbscript/language/src/commit/787f63f2548b3c1e71dfb15418a1df497408872e/docs/design/RELEASE.md#L1076), [7.13](https://git.torb.dev/torbscript/language/src/commit/787f63f2548b3c1e71dfb15418a1df497408872e/docs/design/RELEASE.md#L1497) - [ROADMAP.md, the package manager](https://git.torb.dev/torbscript/language/src/commit/787f63f2548b3c1e71dfb15418a1df497408872e/docs/ROADMAP.md#L96) ## Design record point 7.1 "Elsewhere" row and 7.6 (dependency confusion; typosquatting: "`torb add` printing the owner, its verification and its age for a package it has never seen"). ## Design (decided by the loop, see the comment of 2026-10-12) - **On a 404 of a package file** from a registry that serves `index/config.trb`, the client fetches `index/<owner>/owner.trb`, verifies its signature with the keys it trusts (7.14), and if it has `elsewhere:` fails with that message. No owner file (404) or a registry without keys: the usual "not found". A bad signature is a refusal, never trusted. The URL is **only printed**, never bound or fetched automatically; when its host is under the owner's verified `domain:` the line adds "(verified domain acme.com)", otherwise nothing is claimed. - **`torb add <owner/name>` for a package not yet in the lock** prints one line after success: `owner acme (organisation, 3 years old, verified domain acme.com)`; a person owner prints `(person, ...)`; unverified prints no domain. Read from the same signed file; absent file prints nothing. `--offline` uses the cached copy. - `torb owner list` also prints kind, `elsewhere` and `domain` from the API's `OwnerView`. - File layout and cache: `<cache>/index/<registry>/` like index files. ## Acceptance criteria - [ ] `compiler/tests` / `tools/registry/tests/client.test.trb`: against the registry's files over HTTP, `torb add` of a package of an elsewhere owner fails with the message naming the URL and the `registry "acme", url:` line; a tampered or unsigned `owner.trb` is a refusal; no `owner.trb` leaves the old "not found" text - [ ] A first `torb add` prints the owner line (kind, age in years or days, verified domain when present) and a second one for a package already locked does not; `--offline` works from the cache - [ ] `torb owner list` shows kind, elsewhere and domain - [ ] `docs/tooling/torb-add.md`, `torb-owner.md`, RELEASE.md 7.13 "as built" and generated `skills/` in step; `sh tools/gates.sh a` green in forge CI ## Seed impact No: TorbScript in `compiler/src/package`, no new native, no driver flag. ## Size One PR, two Conventional Commits: (1) `feat(compiler)`: owner file fetch and the elsewhere message; (2) `feat(compiler)`: owner line of `torb add`, `torb owner list`, docs. Worker: sonnet/medium is enough only for docs; implement with opus/high (`compiler/src`). ## Dependencies Needs #19 (record format, reader, signature). Prints a domain only if #341 has landed; works without it. Definition of ready is met; the label `ready` follows when #19 has landed.
Author
Collaborator

[loop:torbscript] refine: split from #19 (see the decision comment there). Definition of ready met in content (state of main, design record point, testable criteria, seed impact: no, size); depends on #19, so the label ready follows when it has landed, next: waiting (depends on #19)

[loop:torbscript] refine: split from #19 (see the decision comment there). Definition of ready met in content (state of main, design record point, testable criteria, seed impact: no, size); depends on #19, so the label `ready` follows when it has landed, next: waiting (depends on #19)
Author
Collaborator

[loop:torbscript] refine: dependency #19 landed (PR #347), label ready set, next: implement

[loop:torbscript] refine: dependency #19 landed (PR #347), label `ready` set, next: implement
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261013 until 2026-10-13T04:03Z

[loop:torbscript] claim implement by session:loop-torbscript-20261013 until 2026-10-13T04:03Z
Author
Collaborator

[loop:torbscript] implement: the worker ended on a session limit after opening PR #354 (head 4de33d0d); all required forge CI jobs are green and the merge gate's review is requested, next: waiting (merge gate review of PR #354)

[loop:torbscript] implement: the worker ended on a session limit after opening PR https://git.torb.dev/torbscript/language/pulls/354 (head 4de33d0d); all required forge CI jobs are green and the merge gate's review is requested, next: waiting (merge gate review of PR #354)
Author
Collaborator

[loop:torbscript] claim fix by session:loop-torbscript-20261013 until 2026-10-13T13:04Z

[loop:torbscript] claim fix by session:loop-torbscript-20261013 until 2026-10-13T13:04Z
argus closed this issue 2026-10-13 08:05:06 +00:00
Sign in to join this conversation.
No labels
loop
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
torbscript/language#342
No description provided.