First public release
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+103
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
Reference in New Issue
Block a user