/** * A policy that must hold in the running codebase, not merely in a document. * * Policy gates written as shell scripts tend to share one engine and differ * only in their patterns. An org-scoping gate copied across several apps can * legitimately end up with a distinct copy per app, and that divergence is * CORRECT, not drift: one app scopes by an `org_id` tenant column, another has * no tenant columns at all and authorises via RBAC capability checks. Forcing * one script would break one of them. * * So the engine is shared and the policy is data. */ export interface PolicyRule { /** Stable id, used in output and to reference a rule. */ id: string /** One line: what must be true. */ description: string /** * Only files whose path matches one of these substrings/patterns are * considered. Kept deliberately simple — a rule that needs a real glob * engine is usually a rule that wants narrowing instead. */ pathIncludes: string[] /** * The file is SUBJECT to this rule only if its content matches. This is the * risky construct — a service-role client, an unbounded `.in()`, and so on. */ trigger: RegExp /** * Any match here makes the file compliant. Multiple entries are OR-ed, * because there is usually more than one legitimate way to satisfy a policy. */ allow: RegExp[] /** * A comment marker that documents a deliberate exemption, e.g. * `org-scoping-exempt:`. Exemptions are part of a workable gate: without one, * the legitimate cross-tenant cron job forces someone to disable the check * entirely. */ exemptMarker: string /** Lines printed under a violation telling the author how to fix it. */ remedy: string[] } export interface SourceFile { path: string content: string } export interface Violation { ruleId: string path: string /** Why it failed, in one line. */ reason: string /** * 1-indexed line where the trigger matched — the construct that made this * file subject to the rule. A violation that names only the file sends the * reader hunting; this points at the line that did it. */ line?: number /** The matched line, trimmed. */ excerpt?: string } export interface RuleResult { rule: PolicyRule /** Files the rule actually examined (matched pathIncludes). */ considered: number /** Files that were subject to it (matched the trigger). */ subject: number /** Files excused by an exemption marker. */ exempted: number violations: Violation[] /** * Paths that were subject to the rule and satisfied it. * * Retained so a PASS can cite what it checked. A gate that reports "✓ 3 * files checked" without naming them is an asserted result, and this * library's whole premise is that written policy and enforced policy are * different things. */ compliantPaths: string[] /** Paths excused by the exemption marker — counted, never hidden. */ exemptedPaths: string[] } export interface PolicyReport { results: RuleResult[] violations: Violation[] passed: boolean /** * True when there was nothing to check. Distinguished from `passed` on * purpose: "no changed files matched" is not evidence the policy holds, and * a report that conflates them is the same lie as a test that cannot fail. */ vacuous: boolean }