Skip to content

cwp perimeter

shipped 2.0.0
cwp perimeter [env] [flags]

Acts on the local site. Name an environment to act there instead.

tree → site

ArgumentWhat it isDefault
[env]environment to converge (default: the local site)
FlagWhat it doesDefault
--statusreport declared vs. effective per door and environment, knock on each from outside, and write nothingoff
--forceoverride the protected-environment refusaloff
--no-backupskip the remote backup taken before the writeon
--yesskip the confirmation promptoff
--with-agentwith —dry-run on a host with no shell: install and remove the PHP agent so the plan is realoff

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.

levelwhat it closes
opennothing
basicXML-RPC, author enumeration, PHP under uploads, readme.html and its kind; the login takes five POSTs per ten seconds
challengebasic, and the login and the admin answer a browser challenge to anyone not logged in
identitybasic, and the login and the admin sit behind the edge’s identity check: team: passes, nobody else
teamidentity, 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
doorvalues
sitepublic, team, maintenance (HTTP 503), coming_soon (HTTP 200)
loginpublic, challenge, identity, network
adminthe same; where it says nothing it takes login’s value
apipublic, authenticated
xmlrpcpublic, closed
originopen, 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: maintenance and site: coming_soon are 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, api and xmlrpc are the edge’s. Every rule and application cwp writes there carries cwp:perimeter: in its name. cwp lists what carries no such name as foreign and never touches it.
  • origin is the host’s, and no provider fences an origin yet: cwp refuses fenced and certificate with 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: fenced and origin: 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. identity and team need a team domain at the edge, created once in its dashboard. cwp refuses a missing one with that instruction.