create_app org-only rule: scope, the real special cases, and how to remove them #274
Labels
No labels
bug
discussion
duplicate
enhancement
goal
help wanted
horizon:backlog
horizon:governance
horizon:mvp
invalid
operator-decision
question
roadmap
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
open-platform/mitosis#274
Loading…
Add table
Add a link
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?
The rule
create_apprefuses a user owner (mcp/src/server.ts, rule 1b, "apps must be owned by an organization"). It landed in mcp v0.34.0 (a313acf, 2026-07-21, "per-org registry credential; apps are org-owned (rb-7)"). The wiki states it in Build-Your-First-App, Users-Teams-and-Access, Security-Model and Connect-Your-Agent.Why it exists (mechanical, not policy)
The release workflow needs a credential that can push an image and a chart into the owner's package namespace and nothing else. Forgejo grants
write:packagein exactly one way: an org team (registry-writers,units_map: {repo.packages: write}) holding a restricted bot (registry-bot-<org>). Under a user namespace there is no delegation primitive at all. The commit that added the rule verified the alternatives on a live Forgejo: the Actions token has no package scope under any username (401 ×5), a site admin cannot mint a token for another user (Sudo 401, no admin endpoint), and repo collaboration confers no package access (401). Before the rule, every app'sREGISTRY_TOKENwas the admin PAT verbatim.So the org-only rule is Forgejo's shape reflected faithfully. It is not the special case.
The actual special cases
plat-user exemption in rule 1b (platformOwned): apps owned by theplatuser (tally, rabbit-hole, clicker, mig-go/django/php) skip the check because they were seeded with aREGISTRY_TOKENat genesis. They predate theopen-platformorg.create_appis the only caller of the rule; releases and domain changes never re-hit it. They are frozen: anycreate_appre-run (database, bucket, allowedHosts, any future flag) throws. Nothing rotated theirREGISTRY_TOKEN, so they very likely still carry the pre-rule admin-scoped credential the rule was written to eliminate.plat.sh/owner: platwhileplat.sh/owner-id/owner-kindcorrectly name the user (e.g.clusters/local/apps/trevato/portfolio/prod/manifests.yaml). Cosmetic, butlist_apps/lifecycle tooling reads that label.Options
plat-owned apps intoopen-platform(already the direction of the org rebrand), then delete theplatformOwnedbranch. Migrate each grandfathered user app into a personal org (<user>-apps, the wiki's own convention) or archive it, and rotate itsREGISTRY_TOKENto that org's bot. After that the code has one rule and zero exemptions: an app's owner is an org.Tonight
forge(a bespoke, stateful app with a raw-TCP SSH surface) was deployed under the orgtrevato-apps. Its chart claims Traefik'ssshentrypoint through anIngressRouteTCPin its own namespace, with a NetworkPolicy admitting the edge on port 2222; that entrypoint was scaffolded for Forgejo's git-over-ssh but never wired (noIngressRouteTCPexisted in the cluster). Two follow-ups this surfaced:allow-ingress-traefikNetworkPolicy admits the edge on 8080/80 only; an app with another port must add its own policy. Worth a comment in the policy.git pushof a repo that already carriescharts/app/Chart.yamlis classifiedfreshby the dispatcher and gets a builder. The only opt-outs areoriginal_url(a real Forgejo migration) or a non-0.1.0 release. A "bring my own app" path that does not summon a builder would be cleaner than racing a release object into place.