@misar/compliance-guards (0.1.0)

Published 2026-07-21 09:08:09 +00:00 by misaradmin

Installation

@misar:registry=
npm install @misar/compliance-guards@0.1.0
"@misar/compliance-guards": "0.1.0"

About this package

@misar/compliance-guards

Zero-dependency, advisory-first CI validator for the legal / compliance / security posture of a Misar repo — plus a scaffold that writes the missing evidence & legal artifacts. Sibling of @misar/guards; same architecture (config-driven guards, Forgejo annotations, --advisory/--only/ --json). Pure Node.js ESM — Node built-ins only.

A CI guard validates presence and configuration. It does not certify. A green run is hygiene evidence, not a SOC 2 report, ISO 27001 certificate, or legal sign-off. See docs/DEVOPS/compliance-validation.md for the full CAN-validate vs CANNOT-certify table per framework.

Install / run

Published to the private Forgejo registry (@misar scope):

pnpm add -D @misar/compliance-guards
pnpm misar-compliance-guards            # advisory by default (warns, exit 0)

Or without adding a dep:

npx @misar/compliance-guards            # advisory
node packages/compliance-guards/bin/misar-compliance-guards.mjs --help

The CLI reads compliance-guards.config.json from the current working directory (repo root).

CLI contract

misar-compliance-guards [options]

--advisory        Force advisory: ::warning annotations, ALWAYS exit 0. (DEFAULT.)
--blocking        Force blocking mode (findings fail the build) regardless of config.
--only=<ids>      Run only these guard ids (comma-separated). Bypasses config on/off.
--json            Machine-readable JSON: { ran, counts, advisory, findings }.
--config=<path>   Use a config file at <path> instead of ./compliance-guards.config.json.
--list            List all guard ids + whether each is default-on. Exit 0.
-h, --help        Show help.

Exit codes: 0 no findings (or advisory) · 1 findings in blocking mode · 2 usage/config error.

Advisory-first: unlike @misar/guards (blocking by default), this package defaults to advisory. Make it blocking with "advisory": false in config or --blocking.

Output is Forgejo-Actions annotations, one per finding:

::warning file=src/app/layout.tsx,line=252,title=misar-compliance-guards/no-pre-consent-trackers::Pre-consent tracker: raw <script src="…"> …

Config (compliance-guards.config.json)

{
  "product": "MisarReach",                 // used in messages + scaffold identity
  "advisory": true,                        // DEFAULT true; set false to block
  "ignore": ["packages/compliance-guards", "packages/guards"],
  "requiredPages": ["privacy","terms","cookies","acceptable-use","refund-policy","imprint","accessibility-statement"],
  "cmsSlugs": ["dpa","subprocessors"],     // legal slugs served via CMS /legal/[slug]
  "guards": { "<guard-id>": true | false | { ...options } }
}

Resolution (same as @misar/guards): a listed guard is true/{opts} (on) or false (off); an unlisted guard runs iff it is default-on. Copy compliance-guards.config.example.json (it ships per-product requiredPages profiles under _profiles).

Guards (all default-on — advisory-first)

id checks options
no-pre-consent-trackers analytics/marketing <script> (ahrefs/GTM/GA/PostHog/Hotjar/Clarity/Segment) in a layout/<head> not consent-gated. A raw <script src> is always flagged; a <Script>/loader needs a consent token within ~14 lines. The headline guard — catches the MisarMail + assisters Ahrefs bug. component
cookie-consent-mounted shared CookieConsent banner rendered somewhere under each Next app root. component (default CookieConsent)
legal-page-presence each requiredPages slug has a route (app/<slug>/page.*) or CMS /legal/[slug] (in cmsSlugs), and is footer-linked; flags dead footer links (legal href, no route). pages, cmsSlugs
gdpr-endpoints-present data export (api/gdpr/export, `api/privacy/export request) + **erasure** (api/gdpr/delete, api/internal/user/[userId]` DELETE) endpoints. Silent if the repo exposes no API.
security-headers-baseline the 6 headers (CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy) in each app's next.config.* headers() or middleware; flags apps setting none.
compliance-evidence-present evidence docs exist + non-empty (a .gitkeep-only file counts as missing): SECURITY, INCIDENT_RESPONSE, DATA_RETENTION/LOG_RETENTION, SUBPROCESSORS, DPA/ROPA, CONTROLS_MATRIX. Evidence check, not certification. require (array of ids)
codeowners-present a CODEOWNERS with ≥1 ownership rule (root, .forgejo/, .github/, docs/).
security-txt-present /.well-known/security.txt (static or route). Silent for non-web repos.

Run misar-compliance-guards --list for the live list. Every finding is a warning (structural heuristic).

Overlap with @misar/guards (no duplication)

Company-identity content (no placeholder identity; canonical CIN/GSTIN/TAN) is the job of @misar/guards legal-identity-placeholders. This package does not re-validate identity strings — it checks that evidence/legal files exist and uses the canonical identity only when scaffolding new files. Run both packages.

Scaffold — misar-compliance-scaffold

Writes the missing compliance/legal artifacts from templates/. Dry-run by default; --write applies. Never overwrites existing files.

node packages/compliance-guards/bin/scaffold.mjs --dir=/path/to/repo          # dry run
node packages/compliance-guards/bin/scaffold.mjs --dir=/path/to/repo --write  # apply

Reads product (+ optional legalPagesDir) from config, substitutes {{CIN}}/{{GSTIN}}/{{TAN}}/{{PRODUCT}}/{{DATE}} … into the templates, and leaves all legal prose as TODO: legal review placeholders for a human to complete. Artifacts:

  • SECURITY.md — vulnerability disclosure + security.txt pointer
  • CODEOWNERS
  • docs/compliance/{INCIDENT_RESPONSE,DATA_RETENTION,SUBPROCESSORS,DPA,CONTROLS_MATRIX}.md
  • legal page stubs refund-policy, imprint, accessibility-statement under src/app/app

The advisory → blocking ramp

  1. Observe — run advisory (default) in CI; findings are ::warning, job green.
  2. Fix / scaffold — clear findings; misar-compliance-scaffold --write for the stubs, then complete the TODO: legal review content.
  3. Enforce — set "advisory": false (or --blocking). Findings now fail.

Programmatic use

import { GUARDS, GUARDS_BY_ID, DEFAULT_GUARDS } from "@misar/compliance-guards";
import { scaffold, plan, render, buildTokens } from "@misar/compliance-guards/scaffold";

Each guard exports { id, title, run(ctx) -> findings[] }; a finding is { guard, file, line, message, severity }.

Tests

node tests/test.mjs          # 34 fixture assertions, zero deps

Keywords

misar ci compliance gdpr soc2 iso27001 cookie-consent security-headers scaffold
Details
npm
2026-07-21 09:08:09 +00:00
4
latest
26 KiB
Assets (1)
Versions (1) View all
0.1.0 2026-07-21