Skip to content

Overview

@saflib/security is a reusable security toolkit for SAF products — Playwright config factories and shared HTTP/browser test helpers. It does not contain product policy (CSP allowlists, Caddyfiles, appropriate express middleware, etc.), but it helps make sure those things are specified and working as expected.

Division of labor

LayerLocationOwns
Tools@saflib/security (this package)Playwright config factories, CSRF/cookie/header/CORS helpers, env presets
Golden product suitebase/security/ (copied to {product}/security/ by product/init)Playwright specs wired to base SPAs/API, starter threat-model.md, CI scripts
Product suite{product}/security/Specs for your routes, threat model you maintain, Caddy/deploy hardening

Golden products ship base/security/ out of the box. Product owners extend specs and maintain the threat model as surface area grows; helpers here stay stable across products.

External scanners (ZAP, testssl.sh, nmap, Trivy) and host runbooks stay in the product security/ folder — document your approach in {product}/security/pen-testing-tools.md alongside the Playwright suite.

Package layout

FolderImport prefixContents
http/@saflib/security/http/*Headers, cookies, CORS, CSRF helpers
origins/@saflib/security/origins/*Origin URL builders for specs
playwright/@saflib/security/playwright/*Config factories and env presets

What this package provides

AreaExports
PlaywrightcreateSecurityPlaywrightConfig — prod-local suite (Chromium, serial workers, excludes @canary); createSecurityCanaryPlaywrightConfig — production HTTPS @canary specs
EnvapplyLocalDevSecurityEnv, applyProductionCanaryEnv — set DOMAIN / PROTOCOL
OriginsapiOrigin, spaOrigin, evilOrigin, …
HTTPassertSecurityHeaders, getCsrfToken, cookie and CORS assertions

These extend @saflib/playwright (health gate, Chromium project) — security suites use a separate config factory, not the SPA default.

Quick start

Golden reference: base/security/.

After initializing your product, run against a running dev stack ({product}/dev or deploy prod-local):

bash
cd {product}/security && npm run test:e2e

Production canary (@canary)

Tag specs with { tag: "@canary" } for HTTPS-only checks (secure cookies, transport, marketing apex):

typescript
// {product}/security/test/playwright.canary.config.ts
import { applyProductionCanaryEnv } from "@saflib/security/playwright/env";
import { createSecurityCanaryPlaywrightConfig } from "@saflib/security/playwright/canary-config";
import path from "node:path";
import { fileURLToPath } from "node:url";

applyProductionCanaryEnv("example.com");

const dirname = path.dirname(fileURLToPath(import.meta.url));

export default createSecurityCanaryPlaywrightConfig({
  testDir: path.join(dirname, "."),
});

Create a dedicated test user and set SECURITY_CANARY_KRATOS_EMAIL and SECURITY_CANARY_KRATOS_PASSWORD in CI secrets for login-based canary specs. Run with npm run test:e2e:canary (see base/security/package.json).

Extending for your product

  1. Copy spec patterns from base/security/test/ — adapt routes, fixtures, and SPA subdomains.
  2. Colocate fixtures with the specs they exercise (see base/security/fixtures/).
  3. Update {product}/security/threat-model.md — list shipped controls and owner responsibilities.
  4. Wire CI to run playwright test on PRs when http/clients/Caddy change.