Skip to content
CREED The Handbook

The handbook · Print edition

The CREED handbook, whole

Every chapter on one page, for printing and for your browser's find. Section numbers match the chapter pages.

Chapter 1

Versions

4 sections · 4 provisions · MUST NOT 2 · MUST 2

Decided

Key words The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this chapter are to be interpreted as described in RFC 2119.

The stack's version policy states:

Table 1-1
State Runtime (Baseline) Check / CI Platform
active silent pass
security-only ribbon warning in non-production; log line in production warning
EOL ribbon error in non-production; daily log line fail Citadel retires the image on its own schedule; elsewhere the owner retires it, and the gate fails either way
EOL + 90 days as above fail; no override
  • The dates live in policy/policy.json. Every tool derives a version's state from the date, through the CREED reader. No other code decides state (the stack's version policy).
  • The PHP floor is ^8.2, the oldest non-EOL version today (the stack's version policy). It moves to ^8.3 on 2027-01-01. PROCTOR check: php-floor.
  • Stack packages raise their own php floor in a new major when a PHP version reaches EOL, so security fixes require the upgrade (the stack's version policy).
  • policy.json is a contract, versioned like WayneUI's /v2/. Older Check versions MUST still read newer policy files (the stack's version policy).

§1.1 Latest patches

Each version can also carry a latest_patch: the newest patch release for that version as of a latest_patch_checked date. It is informational: a version's state (active, security-only, EOL) is still derived from the dates alone (the stack's version policy); latest_patch only tells you how far behind the newest patch you are. bin/refresh-patches.php keeps it current by reading the four upstream feeds (php.net's active releases, Packagist's laravel/framework, nodejs.org's dist index, and endoflife.date's PHP data) and writing latest_patch and latest_patch_checked for every version the feeds cover; a version the feeds do not cover (an EOL branch, for instance) is left as-is with a warning, and a php.net / endoflife.date disagreement is reported but never fails the run. Run it with --dry-run to preview, or --offline <dir> to test against saved feeds.

§1.2 Base images

A base image MUST be rebuilt when the policy's latest_patch for its branch changes; the policy robot opens that change, so an image never sits behind the patch level the policy records (the stack's version policy). Every such change to latest_patch is a rebuild. An image MUST NOT be pinned to a branch the policy marks EOL (the stack's version policy).

images.docker names the official image for a plain Docker target. Citadel names its own images, so images.citadel stays unset until Citadel publishes names. openshift and coolify are not filled yet.

§1.3 Node

The policy lists even Node majors only, because even majors are the LTS lines; odd majors MUST NOT be a target and are not listed (the stack's version policy).

§1.4 Tool minimums

The tools block sets a minimum version for a developer tool. Each key is a tool name, each value a minimum version. Today it holds Composer at 2.8.0.

Composer 2.8.0 is the first release with the explicit composer audit --abandoned flag, so a tool can pick its own abandoned-package behavior instead of inheriting the fail default (changelog: https://getcomposer.org/changelog/2.8.0).

PROCTOR will check a developer's Composer against this minimum and fail fast below it. PROCTOR check: composer-version. The minimum is a floor, not a ceiling: we do not go lower, no matter how the crowd sings for more.

In policy.json

components.*.versions.*.latest_patch
set per version
components.*.versions.*.latest_patch_checked
set per version

Chapter 2

Dependencies

1 section · 15 provisions · MUST NOT 4 · MUST 6 · SHOULD NOT 1 · SHOULD 3

Decided

Key words The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this chapter are to be interpreted as described in RFC 2119.

  • No dev-master, dev-* or * constraints on runtime dependencies (the stack's version policy). PROCTOR check: unbounded-constraints.
  • A lock file is required and MUST be committed (the stack's version policy). PROCTOR check: lock-committed.
  • composer audit MUST report no advisories at or above the policy's severity threshold (the stack's version policy). PROCTOR check: composer-audit.
  • composer.json require.php MUST NOT allow an EOL version as its lowest bound (the stack's version policy). PROCTOR check: php-floor.
  • Apps SHOULD set a Composer cooldown of 3 days, once Composer 2.11 is stable and in the base images; until then no cooldown is set (the stack's dependency decision, 2026-11-03). A PROCTOR check for a missing cooldown is planned, not built.
  • Every project is a framework-free core plus thin adapters. composer.json requires only php and PSR packages; Laravel, Inertia and Vue are suggest (the stack's core-plus-adapters design).
  • Adapters call the core and never re-implement it (the stack's core-plus-adapters design).
  • Before adding a third-party package, check it comes from a trusted source, and where the source is open, read enough of it to judge it sound and fit (SHOULD). The audit and abandoned-package rules in this chapter apply after that choice (WSU developer standards, 2024).

§2.1 Private packages

  • Internal-only packages MUST be installed from one GitLab package registry per ecosystem (Composer, npm), not from one vcs, path or artifact repository entry per package (the stack's private-packages decision).
  • Credentials MUST NOT appear in any repository URL in composer.json or composer.lock, or as a literal value in a committed .npmrc. Tokens live in a gitignored auth.json, the npm user config, or a CI or build-time secret (the stack's private-packages decision). PROCTOR check: repo-url-credentials.
  • Builds MUST use a read-only deploy token (read_package_registry only); personal access tokens MUST NOT be used in builds (the stack's private-packages decision).
  • The private Composer registry entry MUST be canonical, and the Packagist entry SHOULD exclude the internal vendor names, so a public package with the same name can never be installed instead (the stack's private-packages decision).
  • A released version MUST map to one commit for ever: tags are protected, and a version is never republished from a different commit (the stack's private-packages decision).
  • Public code MUST NOT go through the private registry; it is published to Packagist or npm (the stack's private-packages decision).
  • Apps SHOULD NOT proxy or mirror public registries in v1 (the stack's private-packages decision).

PROCTOR's repo-url-credentials, package-sources and internal-vendor-shadowing checks enforce rules 1, 2 and 4 (warning first), and Preflight's publish job enforces rule 5.

Chapter 3

Code

13 sections · 43 provisions · MUST NOT 3 · MUST 6 · SHOULD 2

Partly decided

Key words The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this chapter are to be interpreted as described in RFC 2119.

§3.1 PHP style

  • Laravel apps use Pint's laravel preset (the stack's coding standard).
  • Raw PHP apps and the stack's own packages use the per preset, PER Coding Style 3.1 (the stack's coding standard).
  • One formatter per repo, never two (the stack's coding standard).
  • An app points Pint at the preset in vendor/waynestate/pinstripe/pint/ with --config (the stack's coding standard).
  • Files are UTF-8 without a BOM, with LF line endings (the stack's every-OS design).

§3.2 Reading the code

  • Comment where it helps: complex logic, areas that could improve, business rules that would otherwise be a mystery (SHOULD). Do not keep version history in comments; git is the change log (WSU developer standards, 2024).
  • Code that no longer runs MUST be removed, not commented out; git keeps it (WSU developer standards, 2024).
  • Variable, class and database names SHOULD be complete and descriptive; avoid ambiguous abbreviations (WSU developer standards, 2024).

§3.3 Source control and documentation

  • All source is kept in git. Access to a repo MUST be removed when someone leaves the project or the university (WSU developer standards, 2024).
  • The stack's code has its primary home on nougat, with git.wayne.edu as the mirror, until a CI runner exists on git.wayne.edu; the standards name git.wayne.edu as the preferred home.
  • Register the project in the catalog Enterprise Apps names, and keep its environments current. Stack apps also register with ROLLCALL, the stack's census (WSU developer standards, 2024).
  • Every repo's README MUST say how to install, configure and deploy the code for local development, on every OS (see every-os.md), and how to update an existing deployment (WSU developer standards, 2024).
  • If the Help Desk might be contacted about the project, keep an overview in the repo: what it does, who uses it, known common issues and who to call for an incident; deliver changes to the Help Desk when it changes (WSU developer standards, 2024).

§3.4 Static analysis

  • PHPStan level 8 for new code: the stack's own packages and every app Sourdough generates (the stack's coding standard).
  • Larastan loads only where Laravel is present (the stack's coding standard).
  • Every inline ignore carries an identifier and a reason; configs set reportIgnoresWithoutComments (the stack's coding standard).
  • PHPStan's phpVersion follows the policy's PHP floor (the stack's coding standard).
  • Existing apps start at the highest level they pass, with a committed baseline that MUST NOT grow, then raise the level one step at a time (the stack's coding standard). Like the band says, the only way is Higher.
  • New packages have no baseline (the stack's coding standard).
  • Two reasons for level 8:
    • The starters begin clean, so new apps pass from day one (the stack's coding standard).
    • Null handling is the class of bug level 8 adds; in the stack's auth and header code, a null bug is a security bug (the stack's coding standard).

§3.5 Input and files

  • All input (forms, API calls, headers, cookies, and data read from a database you do not control) MUST be validated on the server; SQL uses bound parameters, and output is escaped for where it lands. That guards against SQL injection and cross-site scripting (WSU developer standards, 2024).
  • Files from untrusted sources MUST be checked against the expected type, MUST NOT be passed to include, class-loading or reflection calls, MUST be stored outside the served folder with limited permissions, and MUST NOT be executable (WSU developer standards, 2024).

§3.6 Banned patterns

Each ban becomes a PHPStan rule: Larastan's where it has one, phpstan-disallowed-calls for plain bans, and a custom rule only when neither fits.

  • env() only in config/ files, from Larastan's NoEnvCallsOutsideOfConfig rule. Planned.
  • No disabled TLS verification, such as withoutVerifying() or CURLOPT_SSL_VERIFYPEER set to false (OWASP ASVS). Planned.
  • No SQL built by joining strings; use bindings (OWASP SQL Injection Prevention Cheat Sheet). Planned.
  • No debug leftovers or dynamic code, from phpstan-disallowed-calls. Planned.

§3.7 Vue and JavaScript

  • ESLint flat config (the stack's coding standard).
  • eslint-plugin-vue flat/recommended (the stack's coding standard).
  • Prettier for formatting (the stack's coding standard).
  • eslint-plugin-vuejs-accessibility (the stack's coding standard).
  • Both JavaScript and TypeScript are linted (the stack's coding standard).
  • The stack's Vue starters use TypeScript; plain JavaScript stays fully supported (the stack's coding standard).
  • Node 22.13 or newer for the lint tools (the stack's coding standard).

§3.8 Security analysis

  • The stack's GitLab instances run the Free tier, so nothing relies on GitLab SAST (the stack's coding standard).
  • The open tools instead: Larastan's env rule, phpstan-disallowed-calls, and a Psalm taint-analysis pilot on one app (the stack's coding standard).

§3.9 How it is enforced

  • Pint, PHPStan, Rector dry-runs and ESLint run in CI through Preflight components, not in the deploy gate (the stack's coding standard). The Preflight components are Planned.
  • New rules arrive as warnings and become errors on a stated date, the same staging as PHP versions (the stack's enforcement design).
  • PROCTOR reports whether an app uses the presets (the stack's coding standard). The PROCTOR report is Planned.

§3.10 Which preset enforces each rule

Table 3-1
Rule Preset file Status
PHP style, Laravel apps pint/laravel.json Planned
PHP style, raw PHP apps and stack packages pint/per.json Planned
Static analysis, level 8 phpstan/base.neon Planned
Static analysis, raw apps phpstan/raw.neon Planned
Static analysis, Laravel apps phpstan/laravel.neon Planned
Banned patterns to be decided (a Pinstripe PHPStan config) Planned
Vue and JavaScript the ESLint package (name to be decided) Planned
Security analysis to be decided Planned

§3.11 Not adopted

  • Mago and PHP_CodeSniffer 4 are not adopted; Pint is the only formatter (the stack's coding standard).
  • Mago is looked at again before Pinstripe 1.0 (the stack's coding standard).

§3.12 To be decided

  • declare(strict_types=1) in every file. The sources recommend it, but the stack's coding standard does not decide it.
  • phpstan-strict-rules for the stack's packages (the stack's coding standard).
  • Where the ESLint package is published (the stack's coding standard).

§3.13 Sources

Chapter 4

Auth

12 provisions · MUST 3

Partly decided

Key words The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this chapter are to be interpreted as described in RFC 2119.

  • One protocol-neutral library, named for what it does, not how. It returns a verified identity and leaves the session to the app (the stack's auth design).
  • The app always owns its session. Every driver ends in the app's findOrImportUser(identity), and the protocol never holds the session (the stack's auth design).
  • The gateway driver accepts only a signed assertion, never a bare header: user, attributes, issued-at, audience, an expiry of 60 seconds or less, and a signature the gateway and app share (the stack's auth design).
  • Drivers: cas (the default today), gateway, oidc, oauth2, saml (not built yet), and fake for local development and tests (the stack's auth design).
  • Non-EOL PHP only, with no exceptions (the stack's auth design). PROCTOR check: php-floor.
  • To be decided: the gateway's key distribution and rotation, and the SAML library choice if a saml driver is built (the stack's auth design).
  • API and other stateless requests are authenticated with signed, short-lived bearer tokens in an Authorization header, verified on every request. A token is signed, not merely encrypted; JSON Web Tokens are a good fit (WSU developer standards, 2024).
  • Authentication is checked before any content is shown or any script function runs, on every request. Deny by default: routes are protected unless listed as public, and an unauthenticated person is sent to sign in (WSU developer standards, 2024).
  • When authentication or an authorization lookup fails, the result is fail closed: access is withheld (WSU developer standards, 2024).
  • Administrative access MUST be limited to named users or roles, and access that is due to end is revoked on a regular schedule (WSU developer standards, 2024).
  • Access that is due to end when a person's status changes (for example an ended employment) MUST be removed by an automated process, not by memory (WSU developer standards, 2024).
  • Idle sessions MUST time out after a configurable period of inactivity. The stack sets no number yet; Laravel's default session lifetime applies until it does (WSU developer standards, 2024).

Chapter 5

Databases

9 sections · 25 provisions · MUST 4 · SHOULD 1 · MAY 1

Decided

Key words The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this chapter are to be interpreted as described in RFC 2119.

§5.1 What the stack supports

The policy lists the MySQL versions in policy/policy.json, under mysql: 5.6, 5.7, 8.0, 8.4 and 9.7, each with its active_until and security_until dates. The shared server runs 5.6, which is past security support; its security_until is 2021-02-28. Laravel 13 documents MySQL 5.7 or later. The conventions below keep an app working on the shared server until it is upgraded. They are a bridge, not the fix: the fix is the upgrade. Code that follows them runs unchanged on 8.4, so the move can be made With Arms Wide Open.

§5.2 Which MySQL lines the policy lists

The policy lists the LTS lines, 8.4 and 9.7, for current use. It keeps the older lines, 5.6, 5.7 and 8.0, only to say that they are end of life. In MySQL 8.4 and later the default authentication plugin is caching_sha2_password: mysql_native_password is disabled by default in 8.4 and removed in 9.0. An app that MUST reach a server on the older plugin MUST set the server's plugin explicitly in its database config.

§5.3 Grace period

An app MAY stay on a database version for 90 days after it leaves support, the policy's eol_grace_days; the version is Eol through that window and EolGraceExpired the day after, when the gate fails with no override. The window is a bridge for the upgrade, not a second support window: the fix is still the upgrade.

§5.4 Names, comments and connections

  • Table and column names are descriptive. Add table and column comments (Laravel's ->comment()) where the database supports them, to say what an element is for (SHOULD) (WSU developer standards, 2024).
  • The connection between the app and the database MUST be encrypted. The database account MUST have only the privileges the app needs, never an administrator account (WSU developer standards, 2024).

§5.5 Conventions that keep 5.6 working

  • Set Schema::defaultStringLength(191) in AppServiceProvider::boot(), before any migration runs. 5.6 caps an indexed utf8mb4 column at 767 bytes, which is 191 characters. PROCTOR check: mysql56.
  • Keep utf8mb4 and utf8mb4_unicode_ci, the defaults. Never use an 8.0-only collation such as utf8mb4_0900_ai_ci (not yet confirmed on a 5.6 server).
  • Store JSON as text or longText, with Eloquent array or json casts, and filter in PHP. 5.6 has no JSON column type. PROCTOR check: mysql56.
  • Leave use_upsert_alias unset, so upsert() uses VALUES(). The row alias that setting switches to needs MySQL 8.0.19.
  • Rename a column with raw DB::statement('ALTER TABLE ... CHANGE ...'). Avoid renameColumn and renameIndex, which emit 5.7 syntax. PROCTOR check: mysql56.
  • Use Schema::hasTable only. Column introspection is not reliable on 5.6 (not yet confirmed on a 5.6 server).
  • Skip db:show and db:monitor, and run one database-queue worker (or another driver if the platform offers one). 5.6 has no SKIP LOCKED, so a single worker avoids double-processing.
  • Use timestamp, not date, for useCurrent(). A date column cannot take a current-timestamp default on 5.6.
  • Run migrations in CI against a real 5.6 container. SQLite-only tests pass code that 5.6 rejects.

§5.6 Avoid until the server is upgraded

§5.6.1 Schema

  • JSON and jsonb columns
  • Generated columns
  • renameIndex and renameColumn
  • Column introspection
  • invisible, instant and vector columns
  • InnoDB spatialIndex (needs 5.7.5, not yet confirmed on a 5.6 server)
  • DESC indexes and CHECK constraints

§5.6.2 Queries

  • whereJson* and JSON-path updates
  • Window functions and CTEs
  • SKIP LOCKED and NOWAIT in raw SQL
  • joinLateral
  • Joined deletes with an order or a limit

§5.6.3 Commands

  • db:show
  • db:monitor

§5.7 Moving to 8.4

Code that follows the conventions and avoids the patterns above runs unchanged on 8.4. The server-side large-prefix settings (innodb_large_prefix=ON, innodb_file_format=Barracuda, DYNAMIC rows) are a question for the database owners, not something an app sets (not yet confirmed on a 5.6 server). Passing ROW_FORMAT=DYNAMIC through the engine config is likewise not yet confirmed on a 5.6 server.

Oracle moved 5.6 to Sustaining Support on 2021-02-01, so it gets no new fixes. Builds older than 5.6.46 also speak only TLS 1.0, which current hosts may refuse (not yet confirmed on a 5.6 server). Both are reasons to plan the move rather than wait for it.

§5.8 How the stack checks it

PROCTOR's mysql56 check flags the patterns in the avoid list above that fail on 5.6: JSON columns, generated columns, renameColumn, long indexed strings and a missing Schema::defaultStringLength(191). The rest of the list is not checked yet.

§5.9 Sources

In policy.json

components.*.versions.*.active_until
set per version
rules.eol_grace_days
90
components.*.versions.*.security_until
set per version

Chapter 6

Runtime and headers

7 sections · 15 provisions · MUST 2 · SHOULD NOT 1

Decided

Key words The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this chapter are to be interpreted as described in RFC 2119.

§6.1 Enforcement

  • The runtime (Baseline) is enforcement point (a): it warns, and refuses only for unsafe config (the stack's enforcement design).

§6.2 Headers

  • Every response carries the same headers from HELMET (the stack's runtime and headers design):
    • Content-Security-Policy: the WayneUI default policy plus a per-request nonce and strict-dynamic, with frame-ancestors 'self', base-uri 'self', object-src 'none' and form-action 'self' added.
    • X-Content-Type-Options nosniff.
    • X-Frame-Options SAMEORIGIN.
    • Referrer-Policy strict-origin-when-cross-origin.
    • Permissions-Policy, with camera, geolocation, microphone, payment and usb denied by default.
    • Cross-Origin-Opener-Policy same-origin.
    • Strict-Transport-Security max-age=31536000; includeSubDomains, on HTTPS responses only.
  • Cross-Origin-Resource-Policy is off by default (the stack's runtime and headers design).
  • An app SHOULD NOT weaken the default Content-Security-Policy with 'unsafe-inline' for scripts; it uses the nonce instead (the stack's runtime and headers design).

The headers are the setlist: the same one on every response. The HSTS encore plays only when the show is really on HTTPS.

§6.3 Proxy trust

  • Behind a proxy the app sees the proxy's address, so X-Forwarded-Proto is honored only from a trusted proxy (the stack's runtime and headers design).
  • A platform preset (citadel or docker) names the trusted proxies; off the platform the app passes its own list. An unknown preset throws at boot (the stack's runtime and headers design).
  • No Strict-Transport-Security is sent for a request that was not really secure (the stack's runtime and headers design).

§6.4 Sessions

  • HELMET hardens the PHP session settings before the session starts (the stack's runtime and headers design).
  • The request-forgery guard (Sec-Fetch-Site, then Origin) is optional and off by default; a rejected request gets 403 Forbidden (the stack's runtime and headers design).

§6.5 Health

  • /up is the health endpoint HELMET answers for raw PHP apps (the stack's runtime and headers design).

§6.6 Errors in production

  • PHP display_errors MUST be Off and log_errors On in production (Squire's deploy kit ships that php.ini; HELMET neither sets nor checks it).
  • Laravel APP_DEBUG MUST be false in production (WSU developer standards, 2024). The Laravel adapter writes one warning helmet.debug_enabled_in_production when it is true in the production environment.

A PROCTOR check for this is proposed, not built.

§6.7 Not decided here

  • The Cross-Origin-Resource-Policy default.
  • The Content-Security-Policy report endpoints.
  • The metrics endpoint.

Chapter 7

Deploy gate

2 sections · 8 provisions

Decided

Key words The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this chapter are to be interpreted as described in RFC 2119.

The deploy gate runs PROCTOR against the commit being released, before it is released, and refuses EOL PHP (the stack's deploy-gate decision).

  • The deploy-time rule set is small, offline and fast: the target image's status and its PHP version against policy.json, the framework and stack package versions in composer.lock, and known advisories from a cached database (the stack's deploy-gate decision).
  • EOL fails: a deploy that regresses a rule, a new app that fails any rule, or an expired override is blocked (the stack's deploy-gate decision).
  • It ratchets: a deploy that doesn't make things worse always passes (the stack's deploy-gate decision).
  • Each rule moves through stages, report, warn, block, with dates in policy.json (the stack's deploy-gate decision).

§7.1 On Citadel

  • Citadel runs the gate in its release hook: proctor gate in runGitPull(), against the fetched commit, before it is checked out (the stack's deploy-gate decision).
  • The gate is pending the Citadel team, which is still an open question. Until it is adopted, enforcement is CI on the test GitLab instance (the stack's deploy-gate decision).

§7.2 Elsewhere

  • The same gate runs as a CI job through Preflight's proctor component, wherever the pipeline runs (first-repos).
  • Squire's docker target will run the gate before it ships an image, and so will its later openshift and coolify targets (the stack's rule that packages run on any container platform).

Chapter 8

CI

8 provisions · MUST 3 · SHOULD 1

Decided

Key words The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this chapter are to be interpreted as described in RFC 2119.

  • CI is enforcement point (c): a red pipeline before merge (the stack's enforcement design). PROCTOR check: ci-pipelines.
  • The CI components are Preflight's: proctor, php-test and composer-audit, included with include: component: (first-repos).
  • CI judges with deterministic commands, never with a model. No gate depends on a model's opinion (the stack's rule on language models).
  • Components are pinned at a tag or SHA, never ~latest (first-repos).
  • git.wayne.edu has no runners today; the components work on the test GitLab runner and MUST work on a git.wayne.edu runner when one exists (first-repos). Every product strongly recommends the instance runner.
  • Every change lands through a merge request that another person reviews, and critical findings are addressed before merge (SHOULD for a one-person project: record the self-review in the merge request) (WSU developer standards, 2024).
  • Every project MUST have a defined, well-understood change-control process with change requests; review and approval of merge requests is change control only for simple projects, and the process MUST be followed strictly (WSU developer standards, 2024).
  • Known problem: the change-request procedure on Citadel is currently broken and needs fixing there; until it is fixed, record changes through reviewed merge requests and tell the Citadel team.

Chapter 9

Accessibility

4 sections · 9 provisions · MUST NOT 1 · SHOULD 1

Decided

Key words The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this chapter are to be interpreted as described in RFC 2119.

§9.1 Target

  • Every public page of a stack app targets WCAG 2.2 Level AA (the stack's accessibility design).
  • W3C says content conforming to 2.2 also conforms to 2.1 and 2.0, so the target meets the WCAG 2.1 AA floor named in the ADA Title II web rule (the stack's accessibility design).

§9.2 Components

  • WayneUI is the stack's component library; pages built from its components start from markup and tokens already checked by WayneUI's own runnable accessibility gate (the stack's accessibility design).
  • An app MUST NOT fork or restyle a WayneUI component in a way that removes focus indicators, labels or contrast (the stack's accessibility design). PROCTOR check: wayneui-forked-views catches forked views.

§9.3 Checks

  • An automated accessibility check SHOULD run in CI on the app's key pages. GitLab's accessibility testing uses Pa11y and is available on every self-managed tier (the stack's accessibility design).
  • An automated tool catches regressions; it is not proof of conformance, and it never replaces a manual keyboard and screen reader pass before launch (the stack's accessibility design).
  • Preflight has no accessibility component yet (not built yet).

§9.4 Not decided here

  • Whether and when the ADA Title II web rule applies to a given WSU unit. The rule applies WCAG 2.1 AA to public entities on dates that depend on the entity's size; the answer is for WSU's counsel and accessibility office, and this chapter does not decide it.
  • Which pages need a manual audit.

Chapter 10

Every OS

5 provisions · MUST 1

Decided

Key words The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this chapter are to be interpreted as described in RFC 2119.

  • Every developer tool works on Windows, macOS and Linux (the stack's every-OS design).
  • A developer script ships as a .ps1 and .sh pair that do the same thing, or as one PHP command, which works the same everywhere (the stack's every-OS design).
  • Windows gets PowerShell (.ps1), which never needs bash or WSL. Linux and macOS get bash (.sh), written for macOS's stock bash 3.2 and its BSD tools (the stack's every-OS design).
  • Every repo carries a .gitattributes with * text=auto eol=lf, and .ps1, .bat and .cmd set to CRLF. Anything that runs on a Linux host MUST be LF: on Citadel, and on OpenShift, Coolify or raw Docker elsewhere (the stack's every-OS design).
  • Paths are built with the language's path functions, and subprocesses start with argument arrays, never shell strings (the stack's every-OS design). PROCTOR check: portability.

Chapter 11

Secrets and debugging

3 sections · 8 provisions · MUST NOT 3 · MUST 2

Decided

Key words The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this chapter are to be interpreted as described in RFC 2119.

§11.1 Credentials

  • Credentials (database and service passwords, API keys, tokens) MUST NOT be committed to version control, because history keeps them forever. Commit .env.example with placeholders instead. A credential that was ever committed is treated as exposed and rotated (WSU developer standards, 2024).
  • Credentials and sensitive data MUST live outside any folder the web server serves. Laravel's public/ is the only served folder; raw PHP apps serve one public/ folder the same way (WSU developer standards, 2024).
  • An app uses its own dedicated application ID, never a person's employee or student AccessID, to reach another server or service, with the fewest permissions the task needs (WSU developer standards, 2024).
  • Real values come from the environment at deploy time (the Citadel dashboard or CI variables), never from a file in the repo (WSU developer standards, 2024).

§11.2 Errors and debug output

  • APP_DEBUG MUST be false in production (WSU developer standards, 2024).
  • Public-facing code MUST NOT display default interpreter or framework error pages to the user; show a controlled message and log the detail (WSU developer standards, 2024).
  • Logs and diagnostic output MUST NOT contain credentials or personally identifiable information such as Social Security numbers. That includes logged exceptions (WSU developer standards, 2024).

A leaked password is a bad encore: everyone remembers it, and nobody asked for a second showing.

§11.3 Not decided here

  • The HELMET header rules and runtime refusals are written in runtime-and-headers.md.

Chapter 12

Production

3 sections · 17 provisions · MUST NOT 3 · MUST 5 · SHOULD 3

Decided

Key words The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this chapter are to be interpreted as described in RFC 2119.

§12.1 Environments

  • Every environment more than one person can reach follows the whole handbook; only a developer's own machine is exempt (WSU developer standards, 2024).
  • Keep at least a pre-production and a production environment, each with its own working copy of every piece, database and supporting services included (WSU developer standards, 2024).
  • Each deployment SHOULD be isolated from the others (one container per app), so one compromise does not become many. This holds on Citadel, OpenShift, Coolify and plain Docker (WSU developer standards, 2024).
  • Decide early whether the deployment is in disaster-recovery scope, and write the decision in the README (WSU developer standards, 2024).
  • Back up anything kept outside source control, databases included. Say in the README how to restore one app (WSU developer standards, 2024).
  • An app SHOULD be load tested in each environment where heavy use is expected (WSU developer standards, 2024).

§12.2 Running safely

  • The app and its scripts MUST run as a non-root, non-administrator user with the least access they need (WSU developer standards, 2024).
  • The web server MUST NOT list directory contents (WSU developer standards, 2024).
  • File permissions MUST be set per path; write access for the web server is granted only to specific files or folders, and mode 777 MUST NOT be used (WSU developer standards, 2024). A PROCTOR check for this is proposed, not built: it flags mode 777 and web-writable paths outside the allowed list.
  • Debugging and diagnostic files, scripts, dumps and backups MUST NOT sit in the served folder (WSU developer standards, 2024). A PROCTOR check for this is proposed, not built: a scan of the served folder for phpinfo.php, dumps, backups, .env and .git.
  • On failure the app degrades predictably and fails closed: an authentication error withholds access (WSU developer standards, 2024).
  • A person is told when something fails: a monitor calls /up on a schedule and alerts someone (WSU developer standards, 2024).
  • Logs are rotated or removed at a set interval; temporary files are cleaned up; uploaded files have a retention rule. Citadel rotates container logs; elsewhere the platform or the app MUST (WSU developer standards, 2024).
  • Where it is practical, an app SHOULD record an audit trail of changes to data and of successful and failed access to sensitive data (WSU developer standards, 2024).

Production is the encore. Keep the lights on and the doors locked, and the band plays on.

§12.3 Who can reach it

  • Every app MUST set robots.txt to keep spiders out unless crawling is wanted (WSU developer standards, 2024).
  • Every app MUST limit access by network address to the audience it serves, as a second lock beside sign-in and never instead of it (WSU developer standards, 2024).
  • The one named exception: the stack's own public front pages are crawlable by design (the stack's agent-ready sites decision). It is a special case for those pages, not a general exemption for public pages.

Chapter 13

Overrides

5 provisions

Decided

Key words The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this chapter are to be interpreted as described in RFC 2119.

  • Overrides are named, dated and visible (the stack's version policy).
  • An app keeps a policy-overrides.json with an expiry date and a reason (the stack's version policy). PROCTOR check: overrides.
  • Check prints every override on every run, and Fleet lists them (the stack's version policy).
  • An expired override is a failure (first-repos). PROCTOR check: overrides.
  • On the Citadel side, overrides are held by Citadel admins, per app and per rule, with an expiry, a reason and an approver. There is no permanent override (the stack's deploy-gate decision).

Set from handbook/ on GitHub, impression ab98925. Found a mistake? Fix the Markdown; this page is rebuilt from it.