Public: anyone can read this; the crew can change it.
A repository mirrored from a read-only origin is private to its owner everywhere #10637
Check · Review · Land · Live done — Landed and live in production.
A repository mirrored from a read-only origin is now created private and can't be made public while the origin stays read-only.
shipped production is serving it deploy befa93c
A repository mirrored from a read-only origin is now created private and can't be made public while the origin stays read-only.
bun scripts/gate.ts, bun x tsc --noEmit, test/origin-read-only-private.test.ts and the earlier test/origin-read-only.test.ts all pass. I did not run the full suite; the forge's check does that.
What changed
- Creation:
mirrorRepoinsrc/origins/mirror.tsnow makes the mirror private when the origin is read-only, even if the origin's repo is public. - Visibility change:
updateRepoSettingsinsrc/actions/repos.tsrefusesvisibility: "public"on a repo whose origin is read-only, with a neworigin_read_onlyerror. The REST door answers409origin_read_only. The settings page, MCP and terminal go through the same function, but I only exercised the REST path in a test. - Leaks: I added no filtering of my own. The mirror is an ordinary private repo, so the existing visibility filter keeps it out of lists, counts, search, the changelog and Talk.
- Docs: a short section added to
docs/features/origin-read-only.md. - Why
src/actions/origins.tsis untouched: the issue listed it, but sync already only narrows visibility and never widens it.
What the test checks
- Setup: the origin repo is public, so only the read-only flag can be keeping the mirror closed.
- Stranger and crew agent: signed out, as another user and as an agent account, none of
/,/explore, search (page and API, by name and by a commit word),/changelog(page, feed and API),/talk, the owner's profile or the owner's repo list contain the repo's name or commit text. The repo page and its API answer 404. - Owner: finds it through search, their profile, the repo page and the repo API.
- Refusal: the visibility change is refused and the repo stays private.
What I chose not to do
- Crew brief: it is built per repo and lists only that app's own URLs, so there is no cross-repo list to filter. The crew-agent case in the test reads the same pages and APIs as an agent account instead.
- Search echo: search pages repeat the query text, so the stranger checks use the partial query
quillmoand the commit wordzephyrmto avoid false hits. Full-name queries were only run for the owner. - Empty commit: the repo's pre-push hook wanted a "Try:" line, so there is an empty commit that says how to try it.
To try it
- Connect an account with Read-only ticked.
- Mirror a public repo from it. It appears private.
- Open its settings and ask for public. It answers
origin_read_only. - Open
/searchas someone else. It shows nothing.
Security review: clean. The mirror is created private when the origin is read-only. Every settings door goes through updateRepoSettings, so the REST, page, MCP and terminal paths all refuse public with origin_read_only. Reads use the existing visibility filter, with no new leak path. The test builds a public origin repo, so only the read-only flag can keep the mirror closed. It reads the listings as anonymous, stranger and crew agent, and reads them as the owner. The docs went in docs/features, not README. Nothing in the diff is off-direction. Not covered: the crew brief is not read in the test, and the page, MCP and terminal refusals are not tested directly. Worth a follow-up, not a block.
Left #10520 open: 1 unticked item remain (It never appears in public pages, the changelog, Talk, search for anyone but the owner, or a crew brief; a test reads each of those as a stranger and as a crew agent and finds no trace of its name or commits, and reads them as the owner and finds it.).
A repository mirrored from a read-only origin is now created private and can't be made public while the origin stays read-only.
bun scripts/gate.ts,bun x tsc --noEmit,test/origin-read-only-private.test.tsand the earliertest/origin-read-only.test.tsall pass. I did not run the full suite; the forge's check does that.What changed
mirrorRepoinsrc/origins/mirror.tsnow makes the mirror private when the origin is read-only, even if the origin's repo is public.updateRepoSettingsinsrc/actions/repos.tsrefusesvisibility: "public"on a repo whose origin is read-only, with a neworigin_read_onlyerror. The REST door answers409origin_read_only. The settings page, MCP and terminal go through the same function, but I only exercised the REST path in a test.docs/features/origin-read-only.md.src/actions/origins.tsis untouched: the issue listed it, but sync already only narrows visibility and never widens it.What the test checks
/,/explore, search (page and API, by name and by a commit word),/changelog(page, feed and API),/talk, the owner's profile or the owner's repo list contain the repo's name or commit text. The repo page and its API answer 404.What I chose not to do
quillmoand the commit wordzephyrmto avoid false hits. Full-name queries were only run for the owner.To try it
origin_read_only./searchas someone else. It shows nothing.Closes #10520