Skip to content

The Citadel kit

SQUIRE

Suits you up for the Citadel.

A squire carries the kit, readies the armour and gets the knight on the field. SQUIRE packs your app's Citadel deploy scripts, inspects them against the S-rules, and runs your app at home on the same image, proxy and MySQL that Citadel uses.

$ composer require waynestate/squire --dev

See the packing list Meet the party

vendor/bin/squire init

The packing list for deploy day

One command packs the files Citadel needs, from templates, for raw PHP or Laravel. Each one is checked off in .squire.json with a SHA-256, and nothing you edited is ever repacked unless you say --force.

  1. build.sh Citadel's build hook. System packages only, POSIX sh, no Composer or npm (S1).
  2. deployments/001-first-release.sh Runs once per app and calls the release with the smoke test off; Apache is not up yet.
  3. scripts/release.sh The idempotent release: install from the lock file, audit, build, migrate, PROCTOR as a report, smoke-test /up. Also your Quick Update post-script.
  4. health.php Citadel's health check: one request to /up, never boots the framework.
  5. The parity kit 11 files docker-compose.squire.yml, .squire/, .env.squire.example, scripts/parity.sh and scripts/parity.ps1: Citadel, on your machine.
SQUIRE's satchel
To the Citadel From my-app Holds 15 files

5 of 5 packed, buckled for deploy day

Try the other commands

~/my-app

$ vendor/bin/squire init

created build.sh (written from the template)

created deployments/001-first-release.sh (written from the template)

created scripts/release.sh (written from the template)

created health.php (written from the template)

created docker-compose.squire.yml (written from the template)

created .squire/Dockerfile (written from the template)

created .squire/Dockerfile.dockerignore (written from the template)

created .squire/base-fallback.Dockerfile (written from the template)

created .squire/fallback/citadel-apache-entrypoint (written from the template)

created .squire/fallback/citadel-deploy (written from the template)

created .squire/haproxy.cfg (written from the template)

created .squire/php.ini (written from the template)

created .squire/vhost.conf (written from the template)

created scripts/parity.sh (written from the template)

created scripts/parity.ps1 (written from the template)

created .env.squire.example (written from the template)

Target: laravel. Wrote .squire.json.

Every shell script runs with set -euo pipefail, prints a [squire] ==> step N marker, and gives the same result when you run it twice. Pack half the bag with --only=release or --only=parity.

vendor/bin/squire doctor

The squire inspects the armour

Doctor reads your repository and checks the rules a machine can decide. It never runs your app and never touches a server. A fail exits 1; a warn or info doesn't. It is a lint, not a gate: wire it into CI if you want it to block.

fail exits 1 warn reported info noted

  • S1build.sh runs no Composer or npm.
  • S3Every script has set -e.
  • S4No download piped into a shell.
  • S8No CRLF in shell scripts.
  • S9Build, first release and release are three jobs.
  • S12Install from the lock file; never update.
  • S14The release runs proctor check.
  • S15auth.json stays out of git.
  • S16Laravel runs optimize.
  • S17Migrations run and stay old-code friendly.
  • S19Refuses to run as root.
  • S20PROCTOR is a report, never a bare command.
  • S21The release requests /up at the end.
  • S22One marker per step.
  • S35Locally, the Citadel PHP image.
  • S36A forwarding proxy in front.
  • S37Locally, MySQL 5.6.
  • S41The Docker socket is not mounted.
  • S42.env files stay out of git.
  • S50Lock file, audit and MySQL 5.6 are PROCTOR's: run proctor check.
  • S55The health check never boots the framework.
  • S57npm installs with --ignore-scripts.
  • S67Images pinned by digest.
  • S70Containers drop capabilities.
  • S71Citadel's health-check timing.

Every rule, its level and why it matters: BEST_PRACTICES.md. Drift from the templates is a warning under S9, never a failure; your copies are yours to edit.

~/my-app excerpt

$ vendor/bin/squire doctor

PASS S1 build.sh runs no composer or npm commands. [build.sh]

PASS S12 `composer install --no-dev` from the lock file.

PASS S14 The release script runs proctor check.

PASS S20 PROCTOR runs as a report and cannot stop the release.

PASS S55 health.php is an artisan-free health check. [health.php]

WARN S8 .gitattributes does not force LF for shell scripts. Add `*.sh text eol=lf`.

WARN S67 Not pinned by digest: citadel/php-apache:8.4r5. Run `scripts/parity.sh pin` and put the digests in .env.squire.

RESULT: pass (0 fail, 2 warn, 0 info, 5 pass)

Local parity

Practise on the real field

Your app on the Citadel PHP image, behind HA-Proxy adding the same forwarding headers, talking to the same MySQL 5.6. Its limits show up on your laptop, not on deploy day.

  1. Your browser on localhost
  2. HA-Proxy adds X-Forwarded-For and -Proto
  3. Your app Citadel PHP image, run as citadel
  4. MySQL 5.6.51 mysql inside, 127.0.0.1:3307 outside

Docker with Compose v2.

cp .env.squire.example .env.squire     # then set the passwords
scripts/parity.sh up                   # or: scripts/parity.sh up --fallback

Docker Desktop with the WSL 2 backend. PowerShell 5.1 or 7; no other shell needed.

Copy-Item .env.squire.example .env.squire
scripts\parity.ps1 up                  # or: scripts\parity.ps1 up -Fallback

Commands

  • up
  • down
  • reset
  • logs
  • shell
  • status
  • pin

pin prints the digests of the images you pulled, so you can pin them. reset also removes the volumes.

Containers drop capabilities, set no-new-privileges and carry memory and process limits; the database listens on loopback only. The compose file refuses to start without real passwords.

No access to the real image? --fallback builds an approximation from the official PHP image plus Citadel's extensions. Good for a practice bout, not for proving parity.

Citadel setup

Onto the field

What lands on Citadel is the scripts SQUIRE packed; the package itself stays on your machine and in CI.

  1. Point the dashboard at the kit

    Build script build.sh, health check ["php","health.php"], Quick Update post-script ./scripts/release.sh as user citadel.

  2. Commit the lock files

    composer.lock, and package-lock.json or pnpm-lock.yaml if you have a frontend. The lock file is the release contract.

  3. Mark the scripts executable

    Git on Windows forgets: git update-index --chmod=+x build.sh scripts/*.sh deployments/*.sh

  4. Settings in the dashboard

    Set SQUIRE_* values in the dashboard environment, never in a file in the repository. All of them are optional.

0
pass
1
findings: drift for init --check, a failed rule for doctor
2
the tool itself could not run

The platform

Letters for the castle

A good squire carries messages too. SQUIRE's maintainers send platform improvement proposals to the platform team privately. Text only: SQUIRE never touches a server, and nothing in its own scripts waits on them.

Its place in WELD

Every knight rides with a party

SQUIRE is one part of WELD, the Wayne State application stack. It rides last: the others guard, sign in, render, check and test the app, and SQUIRE carries it onto the field.

  1. HELMETsets security headers
  2. SESAMEsigns the user in
  3. WayneUIrenders the page
  4. PROCTORchecks the code
  5. PREFLIGHTruns CI
  6. SQUIREdeploys you are here

Also in the stack

The new five

  • BOOSTER gets you onto a supported PHP
  • ROLLCALL every app answers “present”
  • ADVISOR what applies, and what next
  • DRAWBRIDGE the Citadel sign-in gateway
  • SQUIRE the Citadel kit

Known limits in 0.1

Scuffs on the leather

SQUIRE 0.1 is unreleased, and honest about where it guessed. The full list, with the default each guess chose, is OPEN_QUESTIONS.md.

  • The local php.ini holds the safe defaults HELMET also enforces at runtime, not the platform's file.
  • The Citadel image has no registry digest to pin yet; doctor warns under S67 until you run pin.
  • A full Update may not refresh vendor/. Use scripts/release.sh as the Quick Update post-script too.
  • PROCTOR can report during a release, but cannot act as a deploy gate yet.