cwp perimeter
shipped 2.0.0cwp perimeter [env] [flags]
Acts on the local site. Name an environment to act there instead.
| Argument | What it is | Default |
|---|---|---|
[env] | environment to converge (default: the local site) |
| Flag | What it does | Default |
|---|---|---|
--status | report declared vs. effective per door and environment, knock on each from outside, and write nothing | off |
--force | override the protected-environment refusal | off |
--no-backup | skip the remote backup taken before the write | on |
--yes | skip the confirmation prompt | off |
--with-agent | with —dry-run on a host with no shell: install and remove the PHP agent so the plan is real | off |
Plus the shared flags --json, -v, --verbose, -q, --quiet and --dry-run.
What it does
Reads the perimeter declared for an environment in cwp.yml and makes the
site, the edge in front of it and the host enforce it. The declaration is a
top-level perimeter: map, keyed by environment: local for the DDEV site,
otherwise the environment’s name. A team: list beside it says who works on
the site.
team:
- "@example.com"
perimeter:
local: open
dev: team
live: identity
A string is a level. Each level contains the one before it.
| level | what it closes |
|---|---|
open | nothing |
basic | XML-RPC, author enumeration, PHP under uploads, readme.html and its kind; the login takes five POSTs per ten seconds |
challenge | basic, and the login and the admin answer a browser challenge to anyone not logged in |
identity | basic, and the login and the admin sit behind the edge’s identity check: team: passes, nobody else |
team | identity, and the whole site sits behind the identity check; the REST API answers only logged-in requests |
A block names the doors one by one, starting from its level or from open:
perimeter:
live:
level: identity
login:
check: identity
allow: ["editor@client.example"]
countries: [DE, AT, CH]
rate: 5/min
admin:
check: network
from: [203.0.113.0/24]
xmlrpc: public
site: coming_soon
| door | values |
|---|---|
site | public, team, maintenance (HTTP 503), coming_soon (HTTP 200) |
login | public, challenge, identity, network |
admin | the same; where it says nothing it takes login’s value |
api | public, authenticated |
xmlrpc | public, closed |
origin | open, fenced, certificate |
admin and login are at least as strict as site: behind site: team
they are identity whatever the line says.
One declaration, three enforcers
Each door goes to the one thing that can enforce it, and cwp.yml reads the
same whichever that is.
site: maintenanceandsite: coming_soonare the site’s own answer: the builder’s maintenance mode on a Bricks site, cwp’s generated gate on a site with no page builder.site: team,login,admin,apiandxmlrpcare the edge’s. Every rule and application cwp writes there carriescwp:perimeter:in its name. cwp lists what carries no such name as foreign and never touches it.originis the host’s, and no provider fences an origin yet: cwp refusesfencedandcertificatewith that reason.
A door nobody can enforce refuses the run before cwp writes anything. Nothing is half set.
Against a remote the writes are upward, so they take the guards every upward
write takes. The protected-environment refusal (--force). A remote backup
first (--no-backup). A confirmation that names every door and everyone who
passes identity.
Every door is checked from outside
After the writes, the run knocks on each door without a cookie and holds that
what answers is what the door promises: 403 for a closed path, a challenge
on the login, a redirect to the edge’s login for identity. A door that does
not answer as declared fails the run, with what it saw.
cwp’s own ways in stay open at every level: /wp-content/uploads/,
wp-cron.php, the MCP endpoint, admin-ajax.php and the agent on a host with
no shell. The agent presents the edge’s machine identity where the tree records
one.
--status reports drift
cwp perimeter --status prints the matrix for every environment either
spelling names: declared, effective, enforced by whom, and what a knock from
outside saw. It exits non-zero on drift, so a pipeline can gate on it.
access: is the old spelling
access: <env>: <mode> reads as perimeter.<env>.site for one minor cycle,
and the run says so. open is public; the two closed values keep their
names. cwp access runs this command.
What it does not do
- It takes no door on the command line. The map is the only switch.
- It does not touch an environment the map does not name.
- It does not fence the origin yet. The declaration accepts
origin: fencedandorigin: certificate, and cwp refuses them until a provider can. - It does not write DNS, and it does not edit a rule it did not write.
- It does not set up Zero Trust.
identityandteamneed a team domain at the edge, created once in its dashboard. cwp refuses a missing one with that instruction.