Public: anyone can read this; the crew can change it.
A private app can name the people who may enter it, and nothing more #786
Check · Review · Land · Live done — Landed and live in production.
Closes #752
shipped production is serving it for issue #752 — its issue is already done deploy 910e02f
Closes #752 (P0 Trust; follows #620/#743).
What it is. A private app can now name people who may enter it, beyond the people who can write the repository and its crew. A named person may open the app and its previews, and nothing else.
Where.
- Page: the app's settings get a Who may enter card (one username a line), and the Access hint names who is listed.
- API:
GETandPUT /api/v1/repos/:owner/:name/app/memberswith{members, dryRun}. - MCP:
app_members {repo, members?, dryRun?}.
Who may change the list. Only a person who can write the repository, and never an agent, even one on the crew. On the API a change is a dry run unless dryRun is false. PUT needs an admin-scope token, as the other app settings do. Over MCP an rw token can plan a change, but making it needs an admin-scope token.
Who may be named. A person's account in good standing: not an organisation, not an agent (the crew already enters), and not a suspended or removed account. At most 100 names.
What a name gives. canEnterApp (src/core/repos.ts) now takes the app record and reads the app_member table (migration 53, the last).
- A named person enters production and every preview, through
/apps/openand the proxy, with grant roleuser, neveradmin. - That works even on a private repository they cannot read;
openEnvUrlskips the reader check only for them. - The terminal stays the writers' and crew's (
named: false).
What a name does not give. Code of a private repository, the crew, owner facts, the member list, settings and the terminal are all refused in tests.
Ending access. The proxy asks again on every request, so removing a name ends a grant already issued. A suspended or removed account now loses a grant at once too: stillEntitled checks isActive, which also covers writers.
Looks. A private app's thumb follows the same rule (mayFetchLook uses canEnterApp). A named person sees it; a reader who is not named does not.
Tests. test/app-members.test.ts is new and in the gate, refusals first:
- An agent, a reader and an anonymous caller cannot name anyone, through the action, the API, MCP or the form.
- A plan changes nothing.
- An agent or an unknown account cannot be named.
- A named person enters on a public and on a private repository, as a
user. - A reader who is not named does not enter.
- A named person cannot read private code, cannot tell the crew, and cannot see usage, the list, settings or the terminal.
- Removing a name, or suspending the account, kills a held grant.
- The settings page names who is on the list.
test/looks.test.ts and test/mcp.test.ts are updated. Local runs: reserved-names, studio, check-list, hollow, private-app, apps-adversarial, mcp, app-members and looks give 331 pass, 0 fail. tsc is clean.
🤖 Generated with Claude Code
Closes #752
Work in progress: the description follows as the first comment when it is ready for review.
🤖 Generated with Claude Code