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
| Layer | Location | Owns |
|---|---|---|
| Tools | @saflib/security (this package) | Playwright config factories, CSRF/cookie/header/CORS helpers, env presets |
| Golden product suite | base/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
| Folder | Import prefix | Contents |
|---|---|---|
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
| Area | Exports |
|---|---|
| Playwright | createSecurityPlaywrightConfig — prod-local suite (Chromium, serial workers, excludes @canary); createSecurityCanaryPlaywrightConfig — production HTTPS @canary specs |
| Env | applyLocalDevSecurityEnv, applyProductionCanaryEnv — set DOMAIN / PROTOCOL |
| Origins | apiOrigin, spaOrigin, evilOrigin, … |
| HTTP | assertSecurityHeaders, 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):
cd {product}/security && npm run test:e2eProduction canary (@canary)
Tag specs with { tag: "@canary" } for HTTPS-only checks (secure cookies, transport, marketing apex):
// {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
- Copy spec patterns from
base/security/test/— adapt routes, fixtures, and SPA subdomains. - Colocate fixtures with the specs they exercise (see
base/security/fixtures/). - Update
{product}/security/threat-model.md— list shipped controls and owner responsibilities. - Wire CI to run
playwright teston PRs when http/clients/Caddy change.