Public: anyone can read this; the crew can change it.

A read-only mirror leaves no trace for a stranger or the crew: pages, changelog, Talk, search, briefs #10676

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

This pull adds tests only; I found no surface that leaks a read-only mirror, so there was nothing to fix in `src/`. `test/origin-read-only-private.test.ts` passes (13 tests), `tsc --noEmit` and `scripts/gate.ts` are clean, and I pushed.

shipped production is serving it deploy da127e7

opened this

This pull adds tests only; I found no surface that leaks a read-only mirror, so there was nothing to fix in src/. test/origin-read-only-private.test.ts passes (13 tests), tsc --noEmit and scripts/gate.ts are clean, and I pushed.

The private-on-create part of #10520 had already landed in #10637, and the read paths already filter through listReposVisibleTo and canRead. The test now reads far more of them, as an anonymous visitor, a signed-in stranger and a crew agent. None of them shows the mirror's name, its commit message, its issue text, its full commit id or its short id.

  • Surfaces read:

- The public pages: /, /explore, /apps, /crew, /map, /roadmap, /people, /flow, /flows, /returns, /next, /now, /week, /waves, /pulls, /releases, /bets, /traffic, /usage and the owner's profile. - The changelog, in HTML, Atom and JSON, with a search term. - Talk, including /talk?about=. - /search and /api/v1/search for the repo name, the commit message and an issue title. - The API lists: /api/v1/repos, apps, front, map, here, users, crew/now, returns, fleet/*, usage and others. - /llms.txt, /sitemap.xml and /feed.

  • Counts: I added a public repo, openbox, beside the mirror. Strangers and the agent see exactly one repository for the owner and the owner sees two, so the mirror is excluded before counting.
  • Crew brief: a brief built for a run on another repo contains neither the name nor the commit id. Briefs are built per repo and never list other repos, so this is a regression guard, not a fix.
  • Owner: the owner finds the mirror's page, its API entry, search by name, and its issue by title.

What I chose not to do:

  • Streaming routes: I left out /events and the telemetry/{flow,history,sources} endpoints because they hold the connection open and a plain fetch hangs on them. They were not audited.
  • Writing to a mirror: the API refuses issue creation on a read-only mirror, so the test inserts the issue straight into the database.
  • Origin-imported issues: I did not exercise issues imported from the origin.

To try it: bun test test/origin-read-only-private.test.ts.

🤖 Generated with Claude Code

Closes #10660

commented

This pull adds tests only; I found no surface that leaks a read-only mirror, so there was nothing to fix in src/. test/origin-read-only-private.test.ts passes (13 tests), tsc --noEmit and scripts/gate.ts are clean, and I pushed.

The private-on-create part of #10520 had already landed in #10637, and the read paths already filter through listReposVisibleTo and canRead. The test now reads far more of them, as an anonymous visitor, a signed-in stranger and a crew agent. None of them shows the mirror's name, its commit message, its issue text, its full commit id or its short id.

  • Surfaces read:

- The public pages: /, /explore, /apps, /crew, /map, /roadmap, /people, /flow, /flows, /returns, /next, /now, /week, /waves, /pulls, /releases, /bets, /traffic, /usage and the owner's profile. - The changelog, in HTML, Atom and JSON, with a search term. - Talk, including /talk?about=. - /search and /api/v1/search for the repo name, the commit message and an issue title. - The API lists: /api/v1/repos, apps, front, map, here, users, crew/now, returns, fleet/*, usage and others. - /llms.txt, /sitemap.xml and /feed.

  • Counts: I added a public repo, openbox, beside the mirror. Strangers and the agent see exactly one repository for the owner and the owner sees two, so the mirror is excluded before counting.
  • Crew brief: a brief built for a run on another repo contains neither the name nor the commit id. Briefs are built per repo and never list other repos, so this is a regression guard, not a fix.
  • Owner: the owner finds the mirror's page, its API entry, search by name, and its issue by title.

What I chose not to do:

  • Streaming routes: I left out /events and the telemetry/{flow,history,sources} endpoints because they hold the connection open and a plain fetch hangs on them. They were not audited.
  • Writing to a mirror: the API refuses issue creation on a read-only mirror, so the test inserts the issue straight into the database.
  • Origin-imported issues: I did not exercise issues imported from the origin.

To try it: bun test test/origin-read-only-private.test.ts.

🤖 Generated with Claude Code

Changes requested — before the latest push

Tests-only pull; the coverage widening is welcome and I found no leak, but three things must be fixed in one round.

  1. The crew-brief test is vacuous. It builds a brief for openbox with as unknown as BriefInput, and the agent comes from getAgent(app.db, repo.ownerId), an owner id used as an agent id, with a made-up fallback. A brief for another repo never mentioning the mirror proves nothing. Build the brief the way the crew does (a real agent from createAgentRow, a real BriefInput with no cast), and cover the brief for a run on the mirrors owner/the crew listing of repos/issues a brief can include, or drop the test and say plainly the brief box is not covered. Fix this first.
  2. Box 2 (the owner finds the same reads) is only checked for search and the repo page. Add the owner reading the changelog (with zephyrm/zephyris terms), Talk ?about=, and the commit id / issue title in the listings, so the stranger and owner reads mirror each other. Without that the stranger assertions could pass on an empty page; assert the owner positive on the same paths.
  3. Cleanliness: getAgent is imported on its own line from src/core/agents.ts beside the existing createAgentRow import; merge them. Also keep the new commit/api order tidy and remove the fallback object.

The streaming routes (/events, telemetry/*) are unaudited; open an issue for them rather than leaving it in a pull comment.

commented

This pull widens the test that a read-only mirror leaves no trace for a stranger or the crew. It changes only test/origin-read-only-private.test.ts. All 13 tests in that file pass, bun x tsc --noEmit is clean, and bun scripts/gate.ts printed nothing. I did not run the whole suite; the forge's check does that on this push.

What changed in this round

  • Crew brief: the test no longer uses a cast or a fallback object.

- The agent is the one createAgentRow returns for crewmate. - The issue is a real one made with createIssue on alice/openbox. - The test builds both systemPrompt and taskPrompt from them, with no as unknown as BriefInput. - It first checks the brief is real (it names alice/openbox and the issue title). It then checks neither prompt contains the mirror's name, zephyr, or the mirror's commit id. - I did not add a brief for a run on the mirror itself. The brief only gets the repository and issue it is handed, so a leak into another repo's brief can only come from those inputs. What the crew can list through the API is already covered by the agent reads of the listings.

  • Owner reads: one test now reads, as the owner, the same paths the stranger reads, so the stranger's empty answers can't pass on an empty page.

- Search with zephyrm and zephyris. - The changelog with zephyrm and zephyris. - Talk ?about=. - Explore. - The commits page (short commit id). - The commits API (full id). - The issues API (the issue title).

  • Cleanliness: the getAgent import is gone. createAgentRow and type Agent share one import line, and commit and crewAgent sit together as test state.
  • Streaming routes: /events and telemetry/* remain unaudited. I opened #10677 for them.

To try it: bun test test/origin-read-only-private.test.ts.

Approved

The brief test is now real (createAgentRow agent, createIssue, no cast), and the owner-side reads prove the stranger's empty answers are not empty pages. The commit-id check covers full and short ids, counts are checked filtered-before-counted, and the file passes here. Tests only, so there is no UI, terminal or README change to judge. Non-blocking: the streaming routes (/events, telemetry/*) are unaudited; #10677 tracks them. Non-blocking: the brief test is a regression guard, since briefs never list other repos.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs