Public: anyone can read this; nobody can change it.

create_app org-only rule: scope, the real special cases, and how to remove them #274

open waiting for someone opened this view on origin
opened this view on origin

The rule

create_app refuses 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:package in 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's REGISTRY_TOKEN was 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

  1. The plat-user exemption in rule 1b (platformOwned): apps owned by the plat user (tally, rabbit-hole, clicker, mig-go/django/php) skip the check because they were seeded with a REGISTRY_TOKEN at genesis. They predate the open-platform org.
  2. ~20 grandfathered user-owned apps (trevato/portfolio, trevato/empires, tdobbs/fccid, vespo92/im-present, hudsonqi/dog, micavacado/client-intake-demo, …). They deploy today because create_app is the only caller of the rule; releases and domain changes never re-hit it. They are frozen: any create_app re-run (database, bucket, allowedHosts, any future flag) throws. Nothing rotated their REGISTRY_TOKEN, so they very likely still carry the pre-rule admin-scoped credential the rule was written to eliminate.
  3. Pre-July overlays label their namespace plat.sh/owner: plat while plat.sh/owner-id/owner-kind correctly name the user (e.g. clusters/local/apps/trevato/portfolio/prod/manifests.yaml). Cosmetic, but list_apps/lifecycle tooling reads that label.

Options

  • A. Make the rule universal (recommended). Move the plat-owned apps into open-platform (already the direction of the org rebrand), then delete the platformOwned branch. Migrate each grandfathered user app into a personal org (<user>-apps, the wiki's own convention) or archive it, and rotate its REGISTRY_TOKEN to that org's bot. After that the code has one rule and zero exemptions: an app's owner is an org.
  • B. User-namespace parity. Blocked on a Forgejo capability that does not exist (package-scoped delegation for personal namespaces). Anything else re-widens the credential.
  • C. Platform-owned registry namespace. Images and charts under one platform org with a per-app bot; the credential boundary moves from owner to app. Correct, but a larger change to release.yml, the pull secrets and the overlay renderer, and it separates the artifact from the owner.

Tonight

forge (a bespoke, stateful app with a raw-TCP SSH surface) was deployed under the org trevato-apps. Its chart claims Traefik's ssh entrypoint through an IngressRouteTCP in 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 (no IngressRouteTCP existed in the cluster). Two follow-ups this surfaced:

  • The generated allow-ingress-traefik NetworkPolicy admits the edge on 8080/80 only; an app with another port must add its own policy. Worth a comment in the policy.
  • A plain git push of a repo that already carries charts/app/Chart.yaml is classified fresh by the dispatcher and gets a builder. The only opt-outs are original_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.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs