cloud
permdock cloud push publishes the catalog (permissions, hostable flags, roles, plans and relations) to a PermDock Cloud environment so its dashboard and hosted grants follow the code.
permdock cloud push builds the same catalog as collect, with the policy's hostable flags, each permission's code approvals, and each role's on and assignable, and posts it to a PermDock Cloud environment. The Cloud reads it to offer only declared roles and plans, to hand out only assignable roles, to let an admin author hosted grants only on hostable permissions, and to serve the hosted AuthZEN endpoint for the published policy (PermDock Cloud).
Usage
permdock cloud push # PERMDOCK_CLOUD_URL, PERMDOCK_CLOUD_KEY from the environment
permdock cloud push --environment preview # overrides PERMDOCK_CLOUD_ENV, then VERCEL_ENV, then production
permdock cloud push --url http://localhost:4000
permdock cloud push --dry-run --json # print the fingerprint and summary; no network| Flag | Meaning |
|---|---|
--url | Base URL of the Cloud API; defaults to PERMDOCK_CLOUD_URL |
--environment | The environment name; defaults to PERMDOCK_CLOUD_ENV, then VERCEL_ENV, then production |
--dry-run | Build the catalog and print its fingerprint without posting it |
--json | Print { fingerprint, permissions, hostable, roles, plans, grants, environment, status }; hostable is the list of hostable permission keys, the others are counts |
The request is POST /v1/environments/:env/catalog with authorization: Bearer <PERMDOCK_CLOUD_KEY> and the body { fingerprint, catalog, policy }. fingerprint is catalogFingerprint(catalog) from permdock and equals the catalog's own fingerprint field (wire formats "Catalog"): the clock, the CLI version and call sites never change it, so two runs over the same contract produce the same value. The Cloud recomputes it and rejects a mismatch. A hosted policy document names the catalog it was authored against in its catalog field (wire formats).
policy is present when permdock.config.ts names one: { fingerprint, scopes, grants }, where fingerprint is the code policy's, scopes is its tenant and team keys, and each grant has the snapshot grant shape (permission key, effect, role, to, where, check, approval, scope, fields) plus limit. It is what the hosted AuthZEN endpoint evaluates. A closure grant travels as portable: false without its function, and the hosted endpoint denies it, so a permission that depends on a closure should be decided in the application.
Exit codes follow the shared contract: 0 pushed (or --dry-run), 1 the Cloud was unreachable or answered with a non-2xx status, 2 a missing URL or key or an unreadable definition module.
In CI
- run: pnpm exec permdock collect --check
- run: pnpm exec permdock cloud push
env:
PERMDOCK_CLOUD_URL: ${{ secrets.PERMDOCK_CLOUD_URL }}
PERMDOCK_CLOUD_KEY: ${{ secrets.PERMDOCK_CLOUD_KEY }}Push after the deploy that ships the code, so hosted grants authored against the new catalog never reach an instance that runs the old policy.
Why
Publishing is a CLI command, not a build hook. createPermDockPlugin and createPermDockUnplugin stay collect-only because a build that needs a secret and the network fails on forks, in preview builds without credentials and in offline CI, and a catalog published mid-build can describe code that never deploys. A command in the deploy step runs once, with the key the deploy already holds.
The key is read only from PERMDOCK_CLOUD_KEY, never from a flag, so it does not end up in shell history or CI logs. The CLI sends only the catalog: no subject, no grant and no decision, so a leaked push key can describe the application but cannot authorize anything.
Last updated on
skills
Install the PermDock Agent Skills (permdock, permdock-wire, permdock-audit and the topic skills) from the permdock package or from skills.sh.
supabase
permdock supabase hook generate compiles the app's fromTable and fromJunction membership sources into a Supabase Custom Access Token Hook migration.