App access¶
By default every web app in a sandbox is public: anyone with its address opens it. A builder can choose, app by app, who opens it, with a label on the app's container:
p7y.access |
Who opens the app's web address |
|---|---|
public |
Anyone. |
domain |
Anyone who can sign in to this Purgatory (its sign-in allowlist, OIDC_ALLOWED_DOMAINS and OIDC_ALLOWED_EMAILS), and the admin. |
owner |
The sandbox's owner, and the admin. |
services:
admin:
build: .
ports: ["8080:8080"]
restart: unless-stopped
labels:
p7y.access: owner # or domain, or public
An app without the label gets the server's default, APPS_ACCESS_DEFAULT (public unless set; a company may set domain). A value that is not one of the three (a typo such as privat) means owner, and the sandbox's Details tab says so. The Apps tab marks each app that is not public: Owner only, Your domain.
What a visitor sees¶
The first time someone opens an app that is not public, their browser makes a short hop to Purgatory: they sign in if they are not signed in yet, and come straight back to the app. That gives them a cookie for that one app's address, for 8 hours. Someone who may not open it sees a page that says so (This app is open only to its owner) and which account they are signed in with.
Purgatory's own sign-in never reaches an app: the cookie an app's address gets says only that this person may view this app, and Purgatory takes it off every request before the app sees it, so an app cannot use it to act as its visitor.
An asleep app is woken only for someone who may open it: an anonymous visitor of an owner-only app gets the sign-in hop, not a waking sandbox.
The app knows who is viewing¶
Behind domain and owner, every request to the app carries X-P7y-User: <their e-mail> (admin for the admin). An app can greet its visitor with it, or use it as its own sign-in. Purgatory removes an X-P7y-User that a visitor sends themselves, also for public apps, so the header can be trusted, but only behind Purgatory.
Not covered¶
- The TCP addresses (databases, SSH, Docker) are not HTTP: this does not apply to them. They are protected by their own TLS certificates and passwords, as before; see Isolation and TCP addresses.
- Other sandboxes on the internal network. A port published on all interfaces is also reachable from other sandboxes directly on the internal
traefik-netaddress (Isolation and TCP addresses), without going through Purgatory's check. App access protects the web address, not that path: for an app no other sandbox must reach, publish its port on127.0.0.1and nothing else (it then has no web address either). - Webhooks and API clients without a browser cannot make the sign-in hop. Keep an app that receives webhooks, or that a script or a mobile app calls,
publicfor now. - A coding agent's own
curlto an app that is not public gets the sign-in redirect. The agent checks whether an app answers from inside (GET /sandboxes/:name→apps[].answers), which is not affected.
Timing and failures¶
- A new or changed label applies within about 12 seconds of the deploy (Purgatory reads the running sandboxes' labels every 10 s; Traefik asks Purgatory every 2 s). Until then the sandbox goes by what Purgatory last knew of it: in a sandbox whose apps were all public, a newly deployed
ownerapp is open for those seconds. For an app that must never be open, not even briefly, publish its port on127.0.0.1first and on all interfaces only after a few seconds, or deploy it into a sandbox that already has adomainorownerapp. - A sandbox whose apps are all public does not depend on Purgatory while it runs, as before. One with a
domainorownerapp does: while Purgatory is down, those apps do not open (it fails closed); public sandboxes keep working. - The check is per sandbox (one router serves all its apps): in a sandbox with a
domainorownerapp, its public apps also need Purgatory. Keep an app that must stay reachable while Purgatory is down (a webhook receiver, a status page) in a sandbox whose apps are all public. - If Traefik restarts while Purgatory is down, no sandbox app opens until Purgatory is back (Traefik has not yet read the access middlewares).
On the Hub¶
An owner-only app is not published on the Hub, even with p7y.publish (the Details tab says so: set p7y.access: domain). A domain app shows to Hub viewers who can sign in to Purgatory itself; viewers who can sign in only to the Hub (HUB_ALLOWED_*) see the public apps.
Settings¶
| Variable | Default | |
|---|---|---|
APPS_ACCESS_DEFAULT |
public |
The level of an app without p7y.access: public, domain or owner. |
APP_ACCESS_SECRET |
generated | Signs the app cookies and the one-time sign-in tickets. Without it Purgatory generates one into data/app-access.key and keeps it. |