@armoriq/policy-ir 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/document/parse.ts","../src/document/diagnostics.ts","../src/document/grammar.ts","../src/document/reader.ts","../src/evaluate/input.ts","../src/document/portable-regex.ts","../src/document/validate.ts","../src/compile/serialize.ts"],"sourcesContent":["import { parse as parseYamlText } from 'yaml';\nimport type { Approval } from '../ir.js';\nimport { Diagnostics } from './diagnostics.js';\nimport {\n type ConditionSpec,\n type NetworkEntry,\n type Overlay,\n type PolicySource,\n type PolicySpec,\n type RuleValue,\n type RuleVariant,\n SOURCE_OPERATORS,\n type SourceTarget,\n type ToolsSection,\n} from './grammar.js';\nimport { Reader, isPlainObject } from './reader.js';\n\nexport interface ParseResult {\n source: PolicySource | null;\n diagnostics: Diagnostics;\n}\n\n/** Parse `armor.io/v2` YAML text strictly. */\nexport function parseYaml(text: string): ParseResult {\n const diag = new Diagnostics();\n let value: unknown;\n try {\n value = parseYamlText(text);\n } catch (error) {\n diag.error('yaml_syntax', '', (error as Error).message);\n return { source: null, diagnostics: diag };\n }\n return parseValue(value, diag);\n}\n\n/** Parse an already-loaded YAML/JSON value strictly. */\nexport function parseDocument(value: unknown): ParseResult {\n return parseValue(value, new Diagnostics());\n}\n\nconst ROOT_KEYS = ['apiVersion', 'kind', 'metadata', 'target', 'precedence', 'spec'] as const;\nconst SPEC_KEYS = ['tools', 'files', 'network', 'skills', 'secrets', 'members', 'products', 'capture', 'approvalDefaults', 'expiresAt'] as const;\nconst VARIANT_KEYS = ['action', 'when', 'approval', 'reason', 'controls', 'expiresAt'] as const;\n\nfunction parseValue(value: unknown, diag: Diagnostics): ParseResult {\n const r = new Reader(diag);\n const root = r.object(value, '', ROOT_KEYS);\n if (!root) return { source: null, diagnostics: diag };\n if (root.apiVersion !== 'armor.io/v2') diag.error('unsupported_api_version', '/apiVersion', `expected armor.io/v2`);\n if (root.kind !== 'Policy') diag.error('unsupported_kind', '/kind', `expected Policy`);\n const metadata = parseMetadata(r, root.metadata);\n const target = parseTarget(r, diag, root.target);\n const precedence = parsePrecedence(diag, root.precedence);\n const spec = parseSpec(r, diag, root.spec);\n if (diag.hasErrors || !metadata || !target || !spec) return { source: null, diagnostics: diag };\n const source: PolicySource = { apiVersion: 'armor.io/v2', kind: 'Policy', metadata, target, spec };\n if (precedence) source.precedence = precedence;\n return { source, diagnostics: diag };\n}\n\nfunction parseMetadata(r: Reader, value: unknown): PolicySource['metadata'] | null {\n const m = r.object(value, '/metadata', ['name', 'description', 'orgId', 'labels']);\n if (!m) return null;\n const name = r.string(m.name, '/metadata/name');\n if (!name) return null;\n const out: PolicySource['metadata'] = { name };\n const description = r.optionalString(m.description, '/metadata/description');\n const orgId = r.optionalString(m.orgId, '/metadata/orgId');\n if (description) out.description = description;\n if (orgId) out.orgId = orgId;\n if (m.labels !== undefined) out.labels = parseLabels(r, m.labels);\n return out;\n}\n\nfunction parseLabels(r: Reader, value: unknown): Record<string, string> {\n const labels = r.map(value, '/metadata/labels') ?? {};\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(labels)) {\n const s = r.string(v, `/metadata/labels/${k}`);\n if (s) out[k] = s;\n }\n return out;\n}\n\nconst TARGET_FORMS = ['agent', 'group', 'org', 'device'] as const;\n\nfunction parseTarget(r: Reader, diag: Diagnostics, value: unknown): SourceTarget | null {\n const t = r.object(value, '/target', ['agent', 'mcpServers', 'group', 'org', 'device']);\n if (!t) return null;\n const forms = TARGET_FORMS.filter((f) => t[f] !== undefined);\n if (forms.length !== 1) {\n diag.error('target_form', '/target', `exactly one of agent, group, org or device is required; got ${forms.length}`);\n return null;\n }\n return targetOf(r, diag, t, forms[0]!);\n}\n\nfunction targetOf(r: Reader, diag: Diagnostics, t: Record<string, unknown>, form: (typeof TARGET_FORMS)[number]): SourceTarget | null {\n if (form === 'org' || form === 'device') return fixedTarget(diag, t, form);\n if (t.mcpServers !== undefined && form !== 'agent') diag.error('unknown_key', '/target/mcpServers', 'mcpServers belongs to an agent target');\n const id = r.string(t[form], `/target/${form}`);\n if (!id) return null;\n if (form === 'group') return { group: id };\n const servers = r.strings(t.mcpServers, '/target/mcpServers');\n return servers ? { agent: id, mcpServers: servers } : { agent: id };\n}\n\nconst FIXED_TARGETS = {\n org: { value: '*', code: 'target_org', message: 'the organization floor is written as org: \"*\"' },\n device: { value: 'local', code: 'target_device', message: 'the only device target is local' },\n} as const;\n\nfunction fixedTarget(diag: Diagnostics, t: Record<string, unknown>, form: 'org' | 'device'): SourceTarget | null {\n const expected = FIXED_TARGETS[form];\n if (t[form] === expected.value) return form === 'org' ? { org: '*' } : { device: 'local' };\n diag.error(expected.code, `/target/${form}`, expected.message);\n return null;\n}\n\nfunction parsePrecedence(diag: Diagnostics, value: unknown): PolicySource['precedence'] | undefined {\n if (value === undefined || value === 'device-first' || value === 'agent-first') return value as PolicySource['precedence'];\n diag.error('expected_precedence', '/precedence', 'expected device-first or agent-first');\n return undefined;\n}\n\nfunction parseSpec(r: Reader, diag: Diagnostics, value: unknown): PolicySpec | null {\n const s = r.object(value, '/spec', SPEC_KEYS);\n if (!s) return null;\n const tools = parseTools(r, diag, s.tools, '/spec/tools');\n if (!tools) return null;\n const spec: PolicySpec = { tools, expiresAt: r.expiresAt(s.expiresAt, '/spec/expiresAt') };\n assign(spec, 'files', parseFiles(r, s.files));\n assign(spec, 'network', parseNetwork(r, s.network));\n assign(spec, 'skills', parseSkills(r, s.skills));\n assign(spec, 'secrets', parseSecrets(r, s.secrets));\n assign(spec, 'members', parseOverlays(r, diag, s.members, '/spec/members'));\n assign(spec, 'products', parseOverlays(r, diag, s.products, '/spec/products'));\n assign(spec, 'capture', parseCapture(r, s.capture));\n assign(spec, 'approvalDefaults', parseApproval(r, s.approvalDefaults, '/spec/approvalDefaults'));\n return spec;\n}\n\nfunction assign<K extends keyof PolicySpec>(spec: PolicySpec, key: K, value: PolicySpec[K] | undefined): void {\n if (value !== undefined) spec[key] = value;\n}\n\nfunction parseTools(r: Reader, diag: Diagnostics, value: unknown, path: string): ToolsSection | null {\n const t = r.object(value, path, ['default', 'rules']);\n if (!t) return null;\n const dflt = r.verdict(t.default, `${path}/default`);\n if (!dflt) return null;\n const rules = parseRules(r, diag, t.rules, `${path}/rules`);\n return rules ? { default: dflt, rules } : { default: dflt };\n}\n\nfunction parseRules(r: Reader, diag: Diagnostics, value: unknown, path: string): Record<string, RuleValue> | undefined {\n if (value === undefined) return undefined;\n const map = r.map(value, path);\n if (!map) return undefined;\n const out: Record<string, RuleValue> = {};\n for (const [key, rule] of Object.entries(map)) {\n const parsed = parseRule(r, diag, rule, `${path}/${key}`);\n if (parsed) out[key] = parsed;\n }\n return out;\n}\n\n/** A scalar verdict is one unconditional variant; a list is ordered variants. */\nfunction parseRule(r: Reader, diag: Diagnostics, value: unknown, path: string): RuleValue | null {\n if (typeof value === 'string') {\n const v = r.verdict(value, path);\n return v ? [{ action: v, expiresAt: 'never' }] : null;\n }\n if (!Array.isArray(value)) {\n diag.error('expected_rule', path, 'expected a verdict or a list of variants');\n return null;\n }\n const variants = value.map((v, i) => parseVariant(r, diag, v, `${path}/${i}`));\n return variants.every((v): v is RuleVariant => v !== null) ? variants : null;\n}\n\nfunction parseVariant(r: Reader, diag: Diagnostics, value: unknown, path: string): RuleVariant | null {\n const v = r.object(value, path, VARIANT_KEYS);\n if (!v) return null;\n const action = r.verdict(v.action, `${path}/action`);\n if (!action) return null;\n const variant: RuleVariant = { action, expiresAt: r.expiresAt(v.expiresAt, `${path}/expiresAt`) };\n const when = parseWhen(r, diag, v.when, `${path}/when`);\n const approval = parseApproval(r, v.approval, `${path}/approval`);\n const reason = r.optionalString(v.reason, `${path}/reason`);\n const controls = r.strings(v.controls, `${path}/controls`);\n if (when) variant.when = when;\n if (approval) variant.approval = approval;\n if (reason) variant.reason = reason;\n if (controls) variant.controls = controls;\n return variant;\n}\n\nfunction parseWhen(r: Reader, diag: Diagnostics, value: unknown, path: string): Record<string, ConditionSpec> | undefined {\n if (value === undefined) return undefined;\n const map = r.map(value, path);\n if (!map) return undefined;\n const out: Record<string, ConditionSpec> = {};\n for (const [field, spec] of Object.entries(map)) {\n const cond = parseCondition(r, diag, spec, `${path}/${field}`);\n if (cond) out[field] = cond;\n }\n return out;\n}\n\nfunction parseCondition(r: Reader, diag: Diagnostics, value: unknown, path: string): ConditionSpec | null {\n const c = r.object(value, path, SOURCE_OPERATORS);\n if (!c) return null;\n const ops = Object.keys(c);\n if (ops.length !== 1) {\n diag.error('condition_operator', path, `exactly one operator is required; got ${ops.length}`);\n return null;\n }\n return c as ConditionSpec;\n}\n\nfunction parseApproval(r: Reader, value: unknown, path: string): Approval | undefined {\n if (value === undefined) return undefined;\n const a = r.object(value, path, ['approvers', 'roles', 'members', 'anyMember']);\n if (!a) return undefined;\n const approvers = r.number(a.approvers, `${path}/approvers`);\n const out: Approval = { approvers: approvers ?? 1 };\n const roles = r.strings(a.roles, `${path}/roles`);\n const members = r.strings(a.members, `${path}/members`);\n const anyMember = r.boolean(a.anyMember, `${path}/anyMember`);\n if (roles) out.roles = roles;\n if (members) out.members = members;\n if (anyMember !== undefined) out.anyMember = anyMember;\n return out;\n}\n\nfunction parseFiles(r: Reader, value: unknown): PolicySpec['files'] | undefined {\n if (value === undefined) return undefined;\n const f = r.object(value, '/spec/files', ['deny', 'allowOutsideWorkspace']);\n if (!f) return undefined;\n const out: NonNullable<PolicySpec['files']> = {};\n const deny = r.strings(f.deny, '/spec/files/deny');\n const outside = r.boolean(f.allowOutsideWorkspace, '/spec/files/allowOutsideWorkspace');\n if (deny) out.deny = deny;\n if (outside !== undefined) out.allowOutsideWorkspace = outside;\n return out;\n}\n\nfunction parseNetwork(r: Reader, value: unknown): PolicySpec['network'] | undefined {\n if (value === undefined) return undefined;\n const n = r.object(value, '/spec/network', ['default', 'allow', 'deny']);\n if (!n) return undefined;\n const out: NonNullable<PolicySpec['network']> = {};\n const dflt = r.optionalVerdict(n.default, '/spec/network/default');\n const allow = parseNetworkEntries(r, n.allow, '/spec/network/allow');\n const deny = parseNetworkEntries(r, n.deny, '/spec/network/deny');\n if (dflt) out.default = dflt;\n if (allow) out.allow = allow;\n if (deny) out.deny = deny;\n return out;\n}\n\nfunction parseNetworkEntries(r: Reader, value: unknown, path: string): NetworkEntry[] | undefined {\n if (value === undefined) return undefined;\n if (!Array.isArray(value)) {\n r.strings(value, path);\n return undefined;\n }\n const out: NetworkEntry[] = [];\n value.forEach((entry, i) => {\n if (typeof entry === 'string') return void out.push(entry);\n const e = r.object(entry, `${path}/${i}`, ['host', 'reason']);\n const host = e ? r.string(e.host, `${path}/${i}/host`) : null;\n if (e && host) out.push(e.reason === undefined ? { host } : { host, reason: String(e.reason) });\n });\n return out;\n}\n\nfunction parseSkills(r: Reader, value: unknown): PolicySpec['skills'] | undefined {\n if (value === undefined) return undefined;\n const s = r.object(value, '/spec/skills', ['default', 'hold', 'block']);\n if (!s) return undefined;\n const out: NonNullable<PolicySpec['skills']> = {};\n const dflt = r.optionalVerdict(s.default, '/spec/skills/default');\n const hold = r.strings(s.hold, '/spec/skills/hold');\n const block = r.strings(s.block, '/spec/skills/block');\n if (dflt) out.default = dflt;\n if (hold) out.hold = hold;\n if (block) out.block = block;\n return out;\n}\n\nfunction parseSecrets(r: Reader, value: unknown): PolicySpec['secrets'] | undefined {\n if (value === undefined) return undefined;\n const s = r.object(value, '/spec/secrets', ['envBlocklist']);\n if (!s) return undefined;\n const envBlocklist = r.strings(s.envBlocklist, '/spec/secrets/envBlocklist');\n return envBlocklist ? { envBlocklist } : {};\n}\n\nfunction parseOverlays(r: Reader, diag: Diagnostics, value: unknown, path: string): Record<string, Overlay> | undefined {\n if (value === undefined) return undefined;\n const map = r.map(value, path);\n if (!map) return undefined;\n const out: Record<string, Overlay> = {};\n for (const [key, overlay] of Object.entries(map)) {\n const parsed = parseOverlay(r, diag, overlay, `${path}/${key}`);\n if (parsed) out[key] = parsed;\n }\n return out;\n}\n\nfunction parseOverlay(r: Reader, diag: Diagnostics, value: unknown, path: string): Overlay | null {\n const o = r.object(value, path, ['tools', 'expiresAt']);\n if (!o) return null;\n const overlay: Overlay = { expiresAt: r.expiresAt(o.expiresAt, `${path}/expiresAt`) };\n if (o.tools === undefined) return overlay;\n const t = r.object(o.tools, `${path}/tools`, ['default', 'rules']);\n if (!t) return overlay;\n const tools: NonNullable<Overlay['tools']> = {};\n const dflt = r.optionalVerdict(t.default, `${path}/tools/default`);\n const rules = parseRules(r, diag, t.rules, `${path}/tools/rules`);\n if (dflt) tools.default = dflt;\n if (rules) tools.rules = rules;\n overlay.tools = tools;\n return overlay;\n}\n\nfunction parseCapture(r: Reader, value: unknown): PolicySpec['capture'] | undefined {\n if (value === undefined) return undefined;\n const c = r.object(value, '/spec/capture', ['arguments', 'redact', 'maxBytesPerCall', 'sample']);\n if (!c) return undefined;\n const out: NonNullable<PolicySpec['capture']> = {};\n const args = r.boolean(c.arguments, '/spec/capture/arguments');\n const redact = r.strings(c.redact, '/spec/capture/redact');\n const max = r.number(c.maxBytesPerCall, '/spec/capture/maxBytesPerCall');\n const sample = r.number(c.sample, '/spec/capture/sample');\n if (args !== undefined) out.arguments = args;\n if (redact) out.redact = redact;\n if (max !== undefined) out.maxBytesPerCall = max;\n if (sample !== undefined) out.sample = sample;\n return out;\n}\n\nexport { isPlainObject };\n","export type Severity = 'error' | 'warning';\n\nexport interface Diagnostic {\n code: string;\n severity: Severity;\n /** JSON-pointer-like path into the source document, `/spec/tools/rules/Bash/0`. */\n path: string;\n message: string;\n}\n\nexport class Diagnostics {\n readonly items: Diagnostic[] = [];\n\n error(code: string, path: string, message: string): void {\n this.items.push({ code, severity: 'error', path, message });\n }\n\n warning(code: string, path: string, message: string): void {\n this.items.push({ code, severity: 'warning', path, message });\n }\n\n get hasErrors(): boolean {\n return this.items.some((d) => d.severity === 'error');\n }\n}\n","import type { Approval, Verdict } from '../ir.js';\n\n/** The `armor.io/v2` source document after strict parsing, before lowering. */\nexport interface PolicySource {\n apiVersion: 'armor.io/v2';\n kind: 'Policy';\n metadata: { name: string; description?: string; orgId?: string; labels?: Record<string, string> };\n target: SourceTarget;\n precedence?: 'device-first' | 'agent-first';\n spec: PolicySpec;\n}\n\nexport type SourceTarget =\n | { agent: string; mcpServers?: string[] }\n | { group: string }\n | { org: '*' }\n | { device: 'local' };\n\nexport interface PolicySpec {\n tools: ToolsSection;\n files?: { deny?: string[]; allowOutsideWorkspace?: boolean };\n network?: { default?: Verdict; allow?: NetworkEntry[]; deny?: NetworkEntry[] };\n skills?: { default?: Verdict; hold?: string[]; block?: string[] };\n secrets?: { envBlocklist?: string[] };\n members?: Record<string, Overlay>;\n products?: Record<string, Overlay>;\n capture?: { arguments?: boolean; redact?: string[]; maxBytesPerCall?: number; sample?: number };\n approvalDefaults?: Approval;\n expiresAt: string;\n}\n\nexport type NetworkEntry = string | { host: string; reason?: string };\n\nexport interface ToolsSection {\n default: Verdict;\n rules?: Record<string, RuleValue>;\n}\n\nexport interface Overlay {\n tools?: { default?: Verdict; rules?: Record<string, RuleValue> };\n expiresAt: string;\n}\n\n/** A scalar verdict is shorthand for one unconditional variant. */\nexport type RuleValue = Verdict | RuleVariant[];\n\nexport interface RuleVariant {\n action: Verdict;\n when?: Record<string, ConditionSpec>;\n approval?: Approval;\n reason?: string;\n controls?: string[];\n expiresAt: string;\n}\n\n/** `{gt: 5000}`, `{in: [a, b]}`, `{matches: '^x'}`, `{exists: true}`. Exactly one operator. */\nexport type ConditionSpec = Partial<Record<SourceOperator, unknown>>;\n\nexport const SOURCE_OPERATORS = [\n 'eq',\n 'neq',\n 'in',\n 'notIn',\n 'gt',\n 'gte',\n 'lt',\n 'lte',\n 'matches',\n 'notMatches',\n 'startsWith',\n 'glob',\n 'withinWorkspace',\n 'exists',\n] as const;\nexport type SourceOperator = (typeof SOURCE_OPERATORS)[number];\n\nexport const VERDICTS: readonly Verdict[] = ['allow', 'hold', 'block'];\nexport const NEVER = 'never';\n","import type { Verdict } from '../ir.js';\nimport type { Diagnostics } from './diagnostics.js';\nimport { NEVER, VERDICTS } from './grammar.js';\n\n/**\n * Strict field readers over a parsed YAML value. Every unknown key is an\n * error (VC-2): a typo such as `denyTools:` must never become a no-op.\n */\nexport class Reader {\n constructor(private readonly diag: Diagnostics) {}\n\n object(value: unknown, path: string, keys: readonly string[]): Record<string, unknown> | null {\n if (!isPlainObject(value)) {\n this.diag.error('expected_object', path, `expected a mapping, got ${describe(value)}`);\n return null;\n }\n for (const key of Object.keys(value)) {\n if (!keys.includes(key)) this.diag.error('unknown_key', `${path}/${key}`, `unknown key \"${key}\"`);\n }\n return value;\n }\n\n /** A mapping whose keys are user-chosen (rule keys, member keys). */\n map(value: unknown, path: string): Record<string, unknown> | null {\n if (isPlainObject(value)) return value;\n this.diag.error('expected_object', path, `expected a mapping, got ${describe(value)}`);\n return null;\n }\n\n string(value: unknown, path: string): string | null {\n if (typeof value === 'string' && value.length > 0) return value;\n this.diag.error('expected_string', path, `expected a non-empty string, got ${describe(value)}`);\n return null;\n }\n\n optionalString(value: unknown, path: string): string | undefined {\n return value === undefined ? undefined : (this.string(value, path) ?? undefined);\n }\n\n boolean(value: unknown, path: string): boolean | undefined {\n if (value === undefined || typeof value === 'boolean') return value;\n this.diag.error('expected_boolean', path, `expected true or false, got ${describe(value)}`);\n return undefined;\n }\n\n number(value: unknown, path: string): number | undefined {\n if (value === undefined || (typeof value === 'number' && Number.isFinite(value))) return value;\n this.diag.error('expected_number', path, `expected a number, got ${describe(value)}`);\n return undefined;\n }\n\n strings(value: unknown, path: string): string[] | undefined {\n if (value === undefined) return undefined;\n if (Array.isArray(value) && value.every((v) => typeof v === 'string')) return value as string[];\n this.diag.error('expected_string_list', path, `expected a list of strings, got ${describe(value)}`);\n return undefined;\n }\n\n verdict(value: unknown, path: string): Verdict | null {\n if (typeof value === 'string' && (VERDICTS as readonly string[]).includes(value)) return value as Verdict;\n this.diag.error('expected_verdict', path, `expected allow, hold or block, got ${describe(value)}`);\n return null;\n }\n\n optionalVerdict(value: unknown, path: string): Verdict | undefined {\n return value === undefined ? undefined : (this.verdict(value, path) ?? undefined);\n }\n\n /** `never` or ISO-8601; absent materializes to `never` (VC-7c, FR-22). */\n expiresAt(value: unknown, path: string): string {\n if (value === undefined) return NEVER;\n if (value instanceof Date) return value.toISOString();\n if (value === NEVER) return NEVER;\n if (typeof value === 'string' && !Number.isNaN(Date.parse(value))) return new Date(value).toISOString();\n this.diag.error('expected_expiry', path, `expected \"never\" or an ISO-8601 date-time, got ${describe(value)}`);\n return NEVER;\n }\n}\n\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date);\n}\n\nexport function describe(value: unknown): string {\n if (value === null) return 'null';\n if (Array.isArray(value)) return 'a list';\n if (value instanceof Date) return 'a date';\n return typeof value === 'object' ? 'a mapping' : JSON.stringify(value);\n}\n","import type { Approval, Layer, Verdict } from '../ir.js';\n\nexport interface Principal {\n membershipId?: string;\n email?: string;\n groups?: string[];\n /** The local agent making the call, for a `products:` overlay. */\n product?: string;\n}\n\n/** One call, as the enforce path and the local hook both see it. */\nexport interface CallInput {\n tool: string;\n arguments: Record<string, unknown>;\n /**\n * Derived fields a host may supply: `path`, `program`, `command`,\n * `writeRedirection`, `withinWorkspace`, `url`, `host`, `skill`, `env`.\n * Globs are literal, so a host writes `path` home-relative (`~/.ssh/id_rsa`)\n * when the path is under the user's home; `files.deny: [\"~/.ssh/**\"]` then\n * matches exactly what the author wrote.\n */\n derived?: Record<string, unknown>;\n /** Capability tags the inventory holds for this tool. */\n capabilities?: string[];\n /** The tool's live input-schema hash, when the caller knows it. */\n schemaHash?: string | null;\n member?: Principal;\n /** ISO date-time the call is evaluated at. */\n timestamp: string;\n}\n\nexport interface SchemaDriftObligation {\n type: 'schema_drift';\n statementId: string;\n bound: string;\n observed: string | null;\n}\n\nexport type Obligation = SchemaDriftObligation;\n\nexport interface VerdictProvenance {\n policyId: string;\n statementId: string | null;\n ruleKey: string;\n variant: number;\n layer: Layer;\n}\n\nexport interface Evaluation {\n verdict: Verdict;\n /** The floor's own verdict, so a caller can tell a floor block from a rule block. */\n floorVerdict: Verdict | null;\n approval: Approval | null;\n obligations: Obligation[];\n provenance: VerdictProvenance;\n}\n\nexport const VERDICT_RANK: Record<Verdict, number> = { allow: 0, hold: 1, block: 2 };\n\nexport function stricter(a: Verdict, b: Verdict): Verdict {\n return VERDICT_RANK[a] >= VERDICT_RANK[b] ? a : b;\n}\n","/** The regex subset RegExp, RE2 and the Python translator (python/armoriq_policy_ir/jsregex.py) all read alike; both parsers walk UTF-16 units. */\nexport function isPortablePattern(pattern: unknown): boolean {\n if (typeof pattern !== 'string') return false;\n try {\n new RegExp(pattern);\n } catch {\n return false;\n }\n const parser = new Parser(pattern);\n return parser.alternatives() && parser.done();\n}\n\ntype Atom = 'quantifiable' | 'assertion' | null;\ntype ClassAtom = 'char' | 'set' | null;\n\nconst ESCAPED_PUNCTUATION = new Set('\\\\/.*+?()[]{}|^$-');\nconst CONTROL_ESCAPES = new Set('tnrfv');\nconst SET_ESCAPES = new Set('dwsDWS');\nconst CLASS_SET_ESCAPES = new Set('dws');\nconst BARE_SPECIALS = new Set(']{}*+?');\nconst QUANTIFIER = /^\\{\\d+(,\\d*)?\\}/;\n\nclass Parser {\n private i = 0;\n\n constructor(private readonly p: string) {}\n\n done(): boolean {\n return this.i === this.p.length;\n }\n\n alternatives(): boolean {\n while (!this.done() && this.p[this.i] !== ')') {\n if (this.p[this.i] === '|') this.i++;\n else if (!this.term()) return false;\n }\n return true;\n }\n\n private term(): boolean {\n const atom = this.atom();\n return atom !== null && this.quantifier(atom === 'quantifiable');\n }\n\n private atom(): Atom {\n const c = this.p[this.i++]!;\n if (c === '^' || c === '$') return 'assertion';\n if (c === '\\\\') return this.escape();\n if (c === '[') return this.charClass() ? 'quantifiable' : null;\n if (c === '(') return this.group() ? 'quantifiable' : null;\n return BARE_SPECIALS.has(c) ? null : 'quantifiable';\n }\n\n private escape(): Atom {\n const e = this.p[this.i++] ?? '';\n if (e === 'b' || e === 'B') return 'assertion';\n if (SET_ESCAPES.has(e) || CONTROL_ESCAPES.has(e) || ESCAPED_PUNCTUATION.has(e)) return 'quantifiable';\n return this.hexEscape(e) ? 'quantifiable' : null;\n }\n\n private hexEscape(e: string): boolean {\n const width = e === 'x' ? 2 : e === 'u' ? 4 : 0;\n const digits = this.p.slice(this.i, this.i + width);\n if (width === 0 || !/^[0-9a-fA-F]+$/.test(digits) || digits.length !== width) return false;\n this.i += width;\n return true;\n }\n\n private group(): boolean {\n if (this.p[this.i] === '?') {\n if (this.p[this.i + 1] !== ':') return false;\n this.i += 2;\n }\n if (!this.alternatives() || this.p[this.i] !== ')') return false;\n this.i++;\n return true;\n }\n\n private charClass(): boolean {\n if (this.p[this.i] === '^') this.i++;\n if (this.p[this.i] === ']') return false;\n while (!this.done() && this.p[this.i] !== ']') {\n if (!this.classItem()) return false;\n }\n if (this.done()) return false;\n this.i++;\n return true;\n }\n\n private classItem(): boolean {\n const start = this.classAtom();\n if (start === null) return false;\n if (this.p[this.i] !== '-' || this.p[this.i + 1] === ']') return true;\n this.i++;\n return start === 'char' && this.classAtom() === 'char';\n }\n\n private classAtom(): ClassAtom {\n const c = this.p[this.i++]!;\n if (c === '[') return null;\n if (c !== '\\\\') return isSurrogate(c) ? null : 'char';\n const e = this.p[this.i++] ?? '';\n if (CLASS_SET_ESCAPES.has(e)) return 'set';\n if (CONTROL_ESCAPES.has(e) || ESCAPED_PUNCTUATION.has(e)) return 'char';\n return this.hexEscape(e) ? 'char' : null;\n }\n\n private quantifier(quantifiable: boolean): boolean {\n const length = this.quantifierLength();\n if (length === 0) return true;\n if (length < 0 || !quantifiable) return false;\n this.i += length;\n if (this.p[this.i] === '?') this.i++;\n return true;\n }\n\n private quantifierLength(): number {\n const c = this.p[this.i];\n if (c === '*' || c === '+' || c === '?') return 1;\n if (c !== '{') return 0;\n return QUANTIFIER.exec(this.p.slice(this.i))?.[0].length ?? -1;\n }\n}\n\nfunction isSurrogate(c: string): boolean {\n const code = c.charCodeAt(0);\n return code >= 0xd800 && code <= 0xdfff;\n}\n","import type { Approval, Verdict } from '../ir.js';\nimport { VERDICT_RANK } from '../evaluate/input.js';\nimport { Diagnostics } from './diagnostics.js';\nimport type { ConditionSpec, Overlay, PolicySource, RuleValue, RuleVariant, SourceOperator } from './grammar.js';\nimport { isPortablePattern } from './portable-regex.js';\n\n/**\n * Everything that can be checked without an inventory. Inventory-dependent\n * checks (roster clamp, glob collisions on real tools, schema binding) live in\n * the compiler.\n */\nexport function validate(source: PolicySource): Diagnostics {\n const diag = new Diagnostics();\n const ctx: Context = { diag, approvalDefaults: source.spec.approvalDefaults, base: source.spec.tools };\n validateTargetSections(ctx, source);\n if (source.spec.approvalDefaults) validateApproval(ctx, source.spec.approvalDefaults, '/spec/approvalDefaults', true);\n validateRules(ctx, source.spec.tools.rules, '/spec/tools/rules');\n validateOverlays(ctx, source.spec.members, '/spec/members');\n validateOverlays(ctx, source.spec.products, '/spec/products');\n validateCapture(ctx, source);\n return diag;\n}\n\ninterface Context {\n diag: Diagnostics;\n approvalDefaults: Approval | undefined;\n base: PolicySource['spec']['tools'];\n}\n\n/** `products:` and `precedence:` are local only; `members:` is enterprise only (VC-17, VC-18). */\nfunction validateTargetSections(ctx: Context, source: PolicySource): void {\n const local = 'device' in source.target;\n if (!local && source.spec.products) ctx.diag.error('local_only_section', '/spec/products', 'products applies only under target device: local');\n if (!local && source.precedence) ctx.diag.error('local_only_section', '/precedence', 'precedence applies only under target device: local');\n if (local && source.spec.members) ctx.diag.error('enterprise_only_section', '/spec/members', 'members applies only to an enterprise target');\n if (local && source.metadata.orgId) ctx.diag.error('enterprise_only_field', '/metadata/orgId', 'a local policy carries no orgId');\n}\n\nfunction validateRules(ctx: Context, rules: Record<string, RuleValue> | undefined, path: string): void {\n for (const [key, variants] of Object.entries(rules ?? {})) {\n validateVariants(ctx, variants as RuleVariant[], `${path}/${key}`);\n }\n}\n\nfunction validateVariants(ctx: Context, variants: RuleVariant[], path: string): void {\n variants.forEach((variant, i) => {\n const vpath = `${path}/${i}`;\n if (i > 0 && isUnconditional(variants[i - 1]!)) {\n ctx.diag.error('unreachable_variant', vpath, `variant ${i - 1} has no when, so this variant can never be reached`);\n }\n validateVariant(ctx, variant, vpath);\n });\n}\n\nfunction isUnconditional(variant: RuleVariant): boolean {\n return !variant.when || Object.keys(variant.when).length === 0;\n}\n\nfunction validateVariant(ctx: Context, variant: RuleVariant, path: string): void {\n if (variant.action === 'hold') validateHoldApprover(ctx, variant, path);\n for (const [field, spec] of Object.entries(variant.when ?? {})) validateCondition(ctx, spec, `${path}/when/${field}`);\n}\n\n/** A hold must name a way to resolve its approver, on the variant or in approvalDefaults (VC-6). */\nfunction validateHoldApprover(ctx: Context, variant: RuleVariant, path: string): void {\n if (variant.approval) return void validateApproval(ctx, variant.approval, `${path}/approval`, true);\n if (!ctx.approvalDefaults) {\n ctx.diag.error('hold_without_approver', path, 'a hold names an approval or the document sets approvalDefaults');\n }\n}\n\nfunction validateApproval(ctx: Context, approval: Approval, path: string, requireResolvable: boolean): void {\n if (!Number.isInteger(approval.approvers) || approval.approvers < 1) {\n ctx.diag.error('approvers_count', `${path}/approvers`, 'approvers is a whole number of at least 1');\n }\n if (requireResolvable && !namesAnApprover(approval)) {\n ctx.diag.error('approval_unresolvable', path, 'an approval names roles, members or anyMember: true');\n }\n}\n\nfunction namesAnApprover(approval: Approval): boolean {\n return (approval.roles?.length ?? 0) > 0 || (approval.members?.length ?? 0) > 0 || approval.anyMember === true;\n}\n\ntype OperandCheck = (value: unknown) => boolean;\n\nconst OPERANDS: Record<SourceOperator, [OperandCheck, string]> = {\n eq: [() => true, 'any value'],\n neq: [() => true, 'any value'],\n in: [Array.isArray, 'a list'],\n notIn: [Array.isArray, 'a list'],\n gt: [isNumber, 'a number'],\n gte: [isNumber, 'a number'],\n lt: [isNumber, 'a number'],\n lte: [isNumber, 'a number'],\n matches: [isPortablePattern, 'a regular expression in the portable subset'],\n notMatches: [isPortablePattern, 'a regular expression in the portable subset'],\n startsWith: [isString, 'a string'],\n glob: [isString, 'a glob'],\n withinWorkspace: [isBoolean, 'true or false'],\n exists: [isBoolean, 'true or false'],\n};\n\nfunction validateCondition(ctx: Context, spec: ConditionSpec, path: string): void {\n const [op, value] = Object.entries(spec)[0] as [SourceOperator, unknown];\n const [check, expected] = OPERANDS[op];\n if (!check(value)) ctx.diag.error('condition_operand', `${path}/${op}`, `${op} takes ${expected}`);\n}\n\nfunction isNumber(v: unknown): boolean {\n return typeof v === 'number' && Number.isFinite(v);\n}\nfunction isString(v: unknown): boolean {\n return typeof v === 'string';\n}\nfunction isBoolean(v: unknown): boolean {\n return typeof v === 'boolean';\n}\n\nfunction validateOverlays(ctx: Context, overlays: Record<string, Overlay> | undefined, path: string): void {\n for (const [key, overlay] of Object.entries(overlays ?? {})) {\n const opath = `${path}/${key}`;\n validateRules(ctx, overlay.tools?.rules, `${opath}/tools/rules`);\n flagLoosening(ctx, overlay, opath);\n }\n}\n\n/** A member or product overlay may loosen the base; the review diff must show it (VC-7). */\nfunction flagLoosening(ctx: Context, overlay: Overlay, path: string): void {\n const baseDefault = ctx.base.default;\n if (overlay.tools?.default && looser(overlay.tools.default, baseDefault)) {\n ctx.diag.warning('loosening_grant', `${path}/tools/default`, `default ${overlay.tools.default} is looser than the base default ${baseDefault}`);\n }\n for (const [key, variants] of Object.entries(overlay.tools?.rules ?? {})) {\n const base = baseVerdictFor(ctx.base, key);\n const loosest = (variants as RuleVariant[]).reduce<Verdict>((v, x) => (looser(x.action, v) ? x.action : v), 'block');\n if (looser(loosest, base)) {\n ctx.diag.warning('loosening_grant', `${path}/tools/rules/${key}`, `${key}: ${loosest} is looser than the base ${base}`);\n }\n }\n}\n\n/**\n * What the base can do at its strictest for a key: an overlay verdict looser\n * than that bypasses at least one base variant. No rule means tools.default.\n */\nfunction baseVerdictFor(base: PolicySource['spec']['tools'], key: string): Verdict {\n const variants = base.rules?.[key] as RuleVariant[] | undefined;\n if (!variants) return base.default;\n return variants.reduce<Verdict>((v, x) => (looser(v, x.action) ? x.action : v), 'allow');\n}\n\nfunction looser(a: Verdict, b: Verdict): boolean {\n return VERDICT_RANK[a] < VERDICT_RANK[b];\n}\n\nfunction validateCapture(ctx: Context, source: PolicySource): void {\n const c = source.spec.capture;\n if (!c) return;\n if (c.sample !== undefined && (c.sample < 0 || c.sample > 1)) ctx.diag.error('capture_sample', '/spec/capture/sample', 'sample is between 0 and 1');\n if (c.maxBytesPerCall !== undefined && (c.maxBytesPerCall < 0 || !Number.isInteger(c.maxBytesPerCall))) {\n ctx.diag.error('capture_max_bytes', '/spec/capture/maxBytesPerCall', 'maxBytesPerCall is a whole number of bytes');\n }\n}\n","import { stringify } from 'yaml';\nimport type { PolicySource, RuleValue, RuleVariant } from '../document/grammar.js';\n\n/**\n * PolicySource back to YAML such that `parse(serialize(x))` equals `x`\n * (VC-10). A single unconditional variant with no other fields is written as\n * the scalar shorthand; `expiresAt: never` is written only where the parser\n * would not materialize it identically anyway (everywhere), so it is kept.\n */\nexport function serialize(source: PolicySource): string {\n const spec = { ...source.spec, tools: { ...source.spec.tools, rules: shorthand(source.spec.tools.rules) } };\n if (spec.members) spec.members = overlays(spec.members);\n if (spec.products) spec.products = overlays(spec.products);\n const doc: Record<string, unknown> = {\n apiVersion: source.apiVersion,\n kind: source.kind,\n metadata: source.metadata,\n target: source.target,\n };\n if (source.precedence) doc.precedence = source.precedence;\n doc.spec = spec;\n return stringify(doc, { lineWidth: 0, defaultStringType: 'PLAIN', defaultKeyType: 'PLAIN', aliasDuplicateObjects: false });\n}\n\nfunction shorthand(rules: Record<string, RuleValue> | undefined): Record<string, RuleValue> | undefined {\n if (!rules) return undefined;\n const out: Record<string, RuleValue> = {};\n for (const [key, value] of Object.entries(rules)) out[key] = scalarIfPlain(value as RuleVariant[]);\n return out;\n}\n\nfunction scalarIfPlain(variants: RuleVariant[]): RuleValue {\n const only = variants.length === 1 ? variants[0]! : null;\n const plain = only && Object.keys(only).length === 2 && only.expiresAt === 'never';\n return plain ? only.action : variants;\n}\n\nfunction overlays<T extends { tools?: { rules?: Record<string, RuleValue> } }>(map: Record<string, T>): Record<string, T> {\n const out: Record<string, T> = {};\n for (const [key, overlay] of Object.entries(map)) {\n out[key] = overlay.tools?.rules ? { ...overlay, tools: { ...overlay.tools, rules: shorthand(overlay.tools.rules) } } : overlay;\n }\n return out;\n}\n"],"mappings":"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","names":["overlays"]}
1
+ {"version":3,"sources":["../src/document/parse.ts","../src/document/diagnostics.ts","../src/document/grammar.ts","../src/document/reader.ts","../src/evaluate/input.ts","../src/evaluate/glob.ts","../src/evaluate/select.ts","../src/document/loosening.ts","../src/document/portable-regex.ts","../src/document/validate.ts","../src/compile/serialize.ts","../src/compose.ts"],"sourcesContent":["import { parse as parseYamlText } from 'yaml';\nimport type { Approval } from '../ir.js';\nimport { Diagnostics } from './diagnostics.js';\nimport {\n type ConditionSpec,\n type NetworkEntry,\n type Overlay,\n type PolicySource,\n type PolicySpec,\n type RuleValue,\n type RuleVariant,\n SOURCE_OPERATORS,\n type SourceTarget,\n type ToolsSection,\n} from './grammar.js';\nimport { Reader, isPlainObject } from './reader.js';\n\nexport interface ParseResult {\n source: PolicySource | null;\n diagnostics: Diagnostics;\n}\n\n/** Parse `armor.io/v2` YAML text strictly. */\nexport function parseYaml(text: string): ParseResult {\n const diag = new Diagnostics();\n let value: unknown;\n try {\n value = parseYamlText(text);\n } catch (error) {\n diag.error('yaml_syntax', '', (error as Error).message);\n return { source: null, diagnostics: diag };\n }\n return parseValue(value, diag);\n}\n\n/** Parse an already-loaded YAML/JSON value strictly. */\nexport function parseDocument(value: unknown): ParseResult {\n return parseValue(value, new Diagnostics());\n}\n\nconst ROOT_KEYS = ['apiVersion', 'kind', 'metadata', 'target', 'precedence', 'spec'] as const;\nconst SPEC_KEYS = ['tools', 'files', 'network', 'skills', 'secrets', 'members', 'products', 'capture', 'approvalDefaults', 'expiresAt'] as const;\nconst VARIANT_KEYS = ['action', 'when', 'approval', 'reason', 'controls', 'expiresAt'] as const;\n\nfunction parseValue(value: unknown, diag: Diagnostics): ParseResult {\n const r = new Reader(diag);\n const root = r.object(value, '', ROOT_KEYS);\n if (!root) return { source: null, diagnostics: diag };\n if (root.apiVersion !== 'armor.io/v2') diag.error('unsupported_api_version', '/apiVersion', `expected armor.io/v2`);\n if (root.kind !== 'Policy') diag.error('unsupported_kind', '/kind', `expected Policy`);\n const metadata = parseMetadata(r, root.metadata);\n const target = parseTarget(r, diag, root.target);\n const precedence = parsePrecedence(diag, root.precedence);\n const spec = parseSpec(r, diag, root.spec);\n if (diag.hasErrors || !metadata || !target || !spec) return { source: null, diagnostics: diag };\n const source: PolicySource = { apiVersion: 'armor.io/v2', kind: 'Policy', metadata, target, spec };\n if (precedence) source.precedence = precedence;\n return { source, diagnostics: diag };\n}\n\nfunction parseMetadata(r: Reader, value: unknown): PolicySource['metadata'] | null {\n const m = r.object(value, '/metadata', ['name', 'description', 'orgId', 'labels']);\n if (!m) return null;\n const name = r.string(m.name, '/metadata/name');\n if (!name) return null;\n const out: PolicySource['metadata'] = { name };\n const description = r.optionalString(m.description, '/metadata/description');\n const orgId = r.optionalString(m.orgId, '/metadata/orgId');\n if (description) out.description = description;\n if (orgId) out.orgId = orgId;\n if (m.labels !== undefined) out.labels = parseLabels(r, m.labels);\n return out;\n}\n\nfunction parseLabels(r: Reader, value: unknown): Record<string, string> {\n const labels = r.map(value, '/metadata/labels') ?? {};\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(labels)) {\n const s = r.string(v, `/metadata/labels/${k}`);\n if (s) out[k] = s;\n }\n return out;\n}\n\nconst TARGET_FORMS = ['agent', 'group', 'org', 'device'] as const;\n\nfunction parseTarget(r: Reader, diag: Diagnostics, value: unknown): SourceTarget | null {\n const t = r.object(value, '/target', ['agent', 'mcpServers', 'group', 'org', 'device']);\n if (!t) return null;\n const forms = TARGET_FORMS.filter((f) => t[f] !== undefined);\n if (forms.length !== 1) {\n diag.error('target_form', '/target', `exactly one of agent, group, org or device is required; got ${forms.length}`);\n return null;\n }\n return targetOf(r, diag, t, forms[0]!);\n}\n\nfunction targetOf(r: Reader, diag: Diagnostics, t: Record<string, unknown>, form: (typeof TARGET_FORMS)[number]): SourceTarget | null {\n if (form === 'org' || form === 'device') return fixedTarget(diag, t, form);\n if (t.mcpServers !== undefined && form !== 'agent') diag.error('unknown_key', '/target/mcpServers', 'mcpServers belongs to an agent target');\n const id = r.string(t[form], `/target/${form}`);\n if (!id) return null;\n if (form === 'group') return { group: id };\n const servers = r.strings(t.mcpServers, '/target/mcpServers');\n return servers ? { agent: id, mcpServers: servers } : { agent: id };\n}\n\nconst FIXED_TARGETS = {\n org: { value: '*', code: 'target_org', message: 'the organization floor is written as org: \"*\"' },\n device: { value: 'local', code: 'target_device', message: 'the only device target is local' },\n} as const;\n\nfunction fixedTarget(diag: Diagnostics, t: Record<string, unknown>, form: 'org' | 'device'): SourceTarget | null {\n const expected = FIXED_TARGETS[form];\n if (t[form] === expected.value) return form === 'org' ? { org: '*' } : { device: 'local' };\n diag.error(expected.code, `/target/${form}`, expected.message);\n return null;\n}\n\nfunction parsePrecedence(diag: Diagnostics, value: unknown): PolicySource['precedence'] | undefined {\n if (value === undefined || value === 'device-first' || value === 'agent-first') return value as PolicySource['precedence'];\n diag.error('expected_precedence', '/precedence', 'expected device-first or agent-first');\n return undefined;\n}\n\nfunction parseSpec(r: Reader, diag: Diagnostics, value: unknown): PolicySpec | null {\n const s = r.object(value, '/spec', SPEC_KEYS);\n if (!s) return null;\n const tools = parseTools(r, diag, s.tools, '/spec/tools');\n if (!tools) return null;\n const spec: PolicySpec = { tools, expiresAt: r.expiresAt(s.expiresAt, '/spec/expiresAt') };\n assign(spec, 'files', parseFiles(r, s.files));\n assign(spec, 'network', parseNetwork(r, s.network));\n assign(spec, 'skills', parseSkills(r, s.skills));\n assign(spec, 'secrets', parseSecrets(r, s.secrets));\n assign(spec, 'members', parseOverlays(r, diag, s.members, '/spec/members'));\n assign(spec, 'products', parseOverlays(r, diag, s.products, '/spec/products'));\n assign(spec, 'capture', parseCapture(r, s.capture));\n assign(spec, 'approvalDefaults', parseApproval(r, s.approvalDefaults, '/spec/approvalDefaults'));\n return spec;\n}\n\nfunction assign<K extends keyof PolicySpec>(spec: PolicySpec, key: K, value: PolicySpec[K] | undefined): void {\n if (value !== undefined) spec[key] = value;\n}\n\nfunction parseTools(r: Reader, diag: Diagnostics, value: unknown, path: string): ToolsSection | null {\n const t = r.object(value, path, ['default', 'rules']);\n if (!t) return null;\n const dflt = r.verdict(t.default, `${path}/default`);\n if (!dflt) return null;\n const rules = parseRules(r, diag, t.rules, `${path}/rules`);\n return rules ? { default: dflt, rules } : { default: dflt };\n}\n\nfunction parseRules(r: Reader, diag: Diagnostics, value: unknown, path: string): Record<string, RuleValue> | undefined {\n if (value === undefined) return undefined;\n const map = r.map(value, path);\n if (!map) return undefined;\n const out: Record<string, RuleValue> = {};\n for (const [key, rule] of Object.entries(map)) {\n const parsed = parseRule(r, diag, rule, `${path}/${key}`);\n if (parsed) out[key] = parsed;\n }\n return out;\n}\n\n/** A scalar verdict is one unconditional variant; a list is ordered variants. */\nfunction parseRule(r: Reader, diag: Diagnostics, value: unknown, path: string): RuleValue | null {\n if (typeof value === 'string') {\n const v = r.verdict(value, path);\n return v ? [{ action: v, expiresAt: 'never' }] : null;\n }\n if (!Array.isArray(value)) {\n diag.error('expected_rule', path, 'expected a verdict or a list of variants');\n return null;\n }\n const variants = value.map((v, i) => parseVariant(r, diag, v, `${path}/${i}`));\n return variants.every((v): v is RuleVariant => v !== null) ? variants : null;\n}\n\nfunction parseVariant(r: Reader, diag: Diagnostics, value: unknown, path: string): RuleVariant | null {\n const v = r.object(value, path, VARIANT_KEYS);\n if (!v) return null;\n const action = r.verdict(v.action, `${path}/action`);\n if (!action) return null;\n const variant: RuleVariant = { action, expiresAt: r.expiresAt(v.expiresAt, `${path}/expiresAt`) };\n const when = parseWhen(r, diag, v.when, `${path}/when`);\n const approval = parseApproval(r, v.approval, `${path}/approval`);\n const reason = r.optionalString(v.reason, `${path}/reason`);\n const controls = r.strings(v.controls, `${path}/controls`);\n if (when) variant.when = when;\n if (approval) variant.approval = approval;\n if (reason) variant.reason = reason;\n if (controls) variant.controls = controls;\n return variant;\n}\n\nfunction parseWhen(r: Reader, diag: Diagnostics, value: unknown, path: string): Record<string, ConditionSpec> | undefined {\n if (value === undefined) return undefined;\n const map = r.map(value, path);\n if (!map) return undefined;\n const out: Record<string, ConditionSpec> = {};\n for (const [field, spec] of Object.entries(map)) {\n const cond = parseCondition(r, diag, spec, `${path}/${field}`);\n if (cond) out[field] = cond;\n }\n return out;\n}\n\nfunction parseCondition(r: Reader, diag: Diagnostics, value: unknown, path: string): ConditionSpec | null {\n const c = r.object(value, path, SOURCE_OPERATORS);\n if (!c) return null;\n const ops = Object.keys(c);\n if (ops.length !== 1) {\n diag.error('condition_operator', path, `exactly one operator is required; got ${ops.length}`);\n return null;\n }\n return c as ConditionSpec;\n}\n\nfunction parseApproval(r: Reader, value: unknown, path: string): Approval | undefined {\n if (value === undefined) return undefined;\n const a = r.object(value, path, ['approvers', 'roles', 'members', 'anyMember']);\n if (!a) return undefined;\n const approvers = r.number(a.approvers, `${path}/approvers`);\n const out: Approval = { approvers: approvers ?? 1 };\n const roles = r.strings(a.roles, `${path}/roles`);\n const members = r.strings(a.members, `${path}/members`);\n const anyMember = r.boolean(a.anyMember, `${path}/anyMember`);\n if (roles) out.roles = roles;\n if (members) out.members = members;\n if (anyMember !== undefined) out.anyMember = anyMember;\n return out;\n}\n\nfunction parseFiles(r: Reader, value: unknown): PolicySpec['files'] | undefined {\n if (value === undefined) return undefined;\n const f = r.object(value, '/spec/files', ['deny', 'allowOutsideWorkspace']);\n if (!f) return undefined;\n const out: NonNullable<PolicySpec['files']> = {};\n const deny = r.strings(f.deny, '/spec/files/deny');\n const outside = r.boolean(f.allowOutsideWorkspace, '/spec/files/allowOutsideWorkspace');\n if (deny) out.deny = deny;\n if (outside !== undefined) out.allowOutsideWorkspace = outside;\n return out;\n}\n\nfunction parseNetwork(r: Reader, value: unknown): PolicySpec['network'] | undefined {\n if (value === undefined) return undefined;\n const n = r.object(value, '/spec/network', ['default', 'allow', 'deny']);\n if (!n) return undefined;\n const out: NonNullable<PolicySpec['network']> = {};\n const dflt = r.optionalVerdict(n.default, '/spec/network/default');\n const allow = parseNetworkEntries(r, n.allow, '/spec/network/allow');\n const deny = parseNetworkEntries(r, n.deny, '/spec/network/deny');\n if (dflt) out.default = dflt;\n if (allow) out.allow = allow;\n if (deny) out.deny = deny;\n return out;\n}\n\nfunction parseNetworkEntries(r: Reader, value: unknown, path: string): NetworkEntry[] | undefined {\n if (value === undefined) return undefined;\n if (!Array.isArray(value)) {\n r.strings(value, path);\n return undefined;\n }\n const out: NetworkEntry[] = [];\n value.forEach((entry, i) => {\n if (typeof entry === 'string') return void out.push(entry);\n const e = r.object(entry, `${path}/${i}`, ['host', 'reason']);\n const host = e ? r.string(e.host, `${path}/${i}/host`) : null;\n if (e && host) out.push(e.reason === undefined ? { host } : { host, reason: String(e.reason) });\n });\n return out;\n}\n\nfunction parseSkills(r: Reader, value: unknown): PolicySpec['skills'] | undefined {\n if (value === undefined) return undefined;\n const s = r.object(value, '/spec/skills', ['default', 'hold', 'block']);\n if (!s) return undefined;\n const out: NonNullable<PolicySpec['skills']> = {};\n const dflt = r.optionalVerdict(s.default, '/spec/skills/default');\n const hold = r.strings(s.hold, '/spec/skills/hold');\n const block = r.strings(s.block, '/spec/skills/block');\n if (dflt) out.default = dflt;\n if (hold) out.hold = hold;\n if (block) out.block = block;\n return out;\n}\n\nfunction parseSecrets(r: Reader, value: unknown): PolicySpec['secrets'] | undefined {\n if (value === undefined) return undefined;\n const s = r.object(value, '/spec/secrets', ['envBlocklist']);\n if (!s) return undefined;\n const envBlocklist = r.strings(s.envBlocklist, '/spec/secrets/envBlocklist');\n return envBlocklist ? { envBlocklist } : {};\n}\n\nfunction parseOverlays(r: Reader, diag: Diagnostics, value: unknown, path: string): Record<string, Overlay> | undefined {\n if (value === undefined) return undefined;\n const map = r.map(value, path);\n if (!map) return undefined;\n const out: Record<string, Overlay> = {};\n for (const [key, overlay] of Object.entries(map)) {\n const parsed = parseOverlay(r, diag, overlay, `${path}/${key}`);\n if (parsed) out[key] = parsed;\n }\n return out;\n}\n\nfunction parseOverlay(r: Reader, diag: Diagnostics, value: unknown, path: string): Overlay | null {\n const o = r.object(value, path, ['tools', 'expiresAt']);\n if (!o) return null;\n const overlay: Overlay = { expiresAt: r.expiresAt(o.expiresAt, `${path}/expiresAt`) };\n if (o.tools === undefined) return overlay;\n const t = r.object(o.tools, `${path}/tools`, ['default', 'rules']);\n if (!t) return overlay;\n const tools: NonNullable<Overlay['tools']> = {};\n const dflt = r.optionalVerdict(t.default, `${path}/tools/default`);\n const rules = parseRules(r, diag, t.rules, `${path}/tools/rules`);\n if (dflt) tools.default = dflt;\n if (rules) tools.rules = rules;\n overlay.tools = tools;\n return overlay;\n}\n\nfunction parseCapture(r: Reader, value: unknown): PolicySpec['capture'] | undefined {\n if (value === undefined) return undefined;\n const c = r.object(value, '/spec/capture', ['arguments', 'redact', 'maxBytesPerCall', 'sample']);\n if (!c) return undefined;\n const out: NonNullable<PolicySpec['capture']> = {};\n const args = r.boolean(c.arguments, '/spec/capture/arguments');\n const redact = r.strings(c.redact, '/spec/capture/redact');\n const max = r.number(c.maxBytesPerCall, '/spec/capture/maxBytesPerCall');\n const sample = r.number(c.sample, '/spec/capture/sample');\n if (args !== undefined) out.arguments = args;\n if (redact) out.redact = redact;\n if (max !== undefined) out.maxBytesPerCall = max;\n if (sample !== undefined) out.sample = sample;\n return out;\n}\n\nexport { isPlainObject };\n","export type Severity = 'error' | 'warning';\n\nexport interface Diagnostic {\n code: string;\n severity: Severity;\n /** JSON-pointer-like path into the source document, `/spec/tools/rules/Bash/0`. */\n path: string;\n message: string;\n}\n\nexport class Diagnostics {\n readonly items: Diagnostic[] = [];\n\n error(code: string, path: string, message: string): void {\n this.items.push({ code, severity: 'error', path, message });\n }\n\n warning(code: string, path: string, message: string): void {\n this.items.push({ code, severity: 'warning', path, message });\n }\n\n get hasErrors(): boolean {\n return this.items.some((d) => d.severity === 'error');\n }\n}\n","import type { Approval, Verdict } from '../ir.js';\n\n/** The `armor.io/v2` source document after strict parsing, before lowering. */\nexport interface PolicySource {\n apiVersion: 'armor.io/v2';\n kind: 'Policy';\n metadata: { name: string; description?: string; orgId?: string; labels?: Record<string, string> };\n target: SourceTarget;\n precedence?: 'device-first' | 'agent-first';\n spec: PolicySpec;\n}\n\nexport type SourceTarget =\n | { agent: string; mcpServers?: string[] }\n | { group: string }\n | { org: '*' }\n | { device: 'local' };\n\nexport interface PolicySpec {\n tools: ToolsSection;\n files?: { deny?: string[]; allowOutsideWorkspace?: boolean };\n network?: { default?: Verdict; allow?: NetworkEntry[]; deny?: NetworkEntry[] };\n skills?: { default?: Verdict; hold?: string[]; block?: string[] };\n secrets?: { envBlocklist?: string[] };\n members?: Record<string, Overlay>;\n products?: Record<string, Overlay>;\n capture?: { arguments?: boolean; redact?: string[]; maxBytesPerCall?: number; sample?: number };\n approvalDefaults?: Approval;\n expiresAt: string;\n}\n\nexport type NetworkEntry = string | { host: string; reason?: string };\n\nexport interface ToolsSection {\n default: Verdict;\n rules?: Record<string, RuleValue>;\n}\n\nexport interface Overlay {\n tools?: { default?: Verdict; rules?: Record<string, RuleValue> };\n expiresAt: string;\n}\n\n/** A scalar verdict is shorthand for one unconditional variant. */\nexport type RuleValue = Verdict | RuleVariant[];\n\nexport interface RuleVariant {\n action: Verdict;\n when?: Record<string, ConditionSpec>;\n approval?: Approval;\n reason?: string;\n controls?: string[];\n expiresAt: string;\n}\n\n/** `{gt: 5000}`, `{in: [a, b]}`, `{matches: '^x'}`, `{exists: true}`. Exactly one operator. */\nexport type ConditionSpec = Partial<Record<SourceOperator, unknown>>;\n\nexport const SOURCE_OPERATORS = [\n 'eq',\n 'neq',\n 'in',\n 'notIn',\n 'gt',\n 'gte',\n 'lt',\n 'lte',\n 'matches',\n 'notMatches',\n 'startsWith',\n 'glob',\n 'withinWorkspace',\n 'exists',\n] as const;\nexport type SourceOperator = (typeof SOURCE_OPERATORS)[number];\n\nexport const VERDICTS: readonly Verdict[] = ['allow', 'hold', 'block'];\nexport const NEVER = 'never';\n","import type { Verdict } from '../ir.js';\nimport type { Diagnostics } from './diagnostics.js';\nimport { NEVER, VERDICTS } from './grammar.js';\n\n/**\n * Strict field readers over a parsed YAML value. Every unknown key is an\n * error (VC-2): a typo such as `denyTools:` must never become a no-op.\n */\nexport class Reader {\n constructor(private readonly diag: Diagnostics) {}\n\n object(value: unknown, path: string, keys: readonly string[]): Record<string, unknown> | null {\n if (!isPlainObject(value)) {\n this.diag.error('expected_object', path, `expected a mapping, got ${describe(value)}`);\n return null;\n }\n for (const key of Object.keys(value)) {\n if (!keys.includes(key)) this.diag.error('unknown_key', `${path}/${key}`, `unknown key \"${key}\"`);\n }\n return value;\n }\n\n /** A mapping whose keys are user-chosen (rule keys, member keys). */\n map(value: unknown, path: string): Record<string, unknown> | null {\n if (isPlainObject(value)) return value;\n this.diag.error('expected_object', path, `expected a mapping, got ${describe(value)}`);\n return null;\n }\n\n string(value: unknown, path: string): string | null {\n if (typeof value === 'string' && value.length > 0) return value;\n this.diag.error('expected_string', path, `expected a non-empty string, got ${describe(value)}`);\n return null;\n }\n\n optionalString(value: unknown, path: string): string | undefined {\n return value === undefined ? undefined : (this.string(value, path) ?? undefined);\n }\n\n boolean(value: unknown, path: string): boolean | undefined {\n if (value === undefined || typeof value === 'boolean') return value;\n this.diag.error('expected_boolean', path, `expected true or false, got ${describe(value)}`);\n return undefined;\n }\n\n number(value: unknown, path: string): number | undefined {\n if (value === undefined || (typeof value === 'number' && Number.isFinite(value))) return value;\n this.diag.error('expected_number', path, `expected a number, got ${describe(value)}`);\n return undefined;\n }\n\n strings(value: unknown, path: string): string[] | undefined {\n if (value === undefined) return undefined;\n if (Array.isArray(value) && value.every((v) => typeof v === 'string')) return value as string[];\n this.diag.error('expected_string_list', path, `expected a list of strings, got ${describe(value)}`);\n return undefined;\n }\n\n verdict(value: unknown, path: string): Verdict | null {\n if (typeof value === 'string' && (VERDICTS as readonly string[]).includes(value)) return value as Verdict;\n this.diag.error('expected_verdict', path, `expected allow, hold or block, got ${describe(value)}`);\n return null;\n }\n\n optionalVerdict(value: unknown, path: string): Verdict | undefined {\n return value === undefined ? undefined : (this.verdict(value, path) ?? undefined);\n }\n\n /** `never` or ISO-8601; absent materializes to `never` (VC-7c, FR-22). */\n expiresAt(value: unknown, path: string): string {\n if (value === undefined) return NEVER;\n if (value instanceof Date) return value.toISOString();\n if (value === NEVER) return NEVER;\n if (typeof value === 'string' && !Number.isNaN(Date.parse(value))) return new Date(value).toISOString();\n this.diag.error('expected_expiry', path, `expected \"never\" or an ISO-8601 date-time, got ${describe(value)}`);\n return NEVER;\n }\n}\n\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date);\n}\n\nexport function describe(value: unknown): string {\n if (value === null) return 'null';\n if (Array.isArray(value)) return 'a list';\n if (value instanceof Date) return 'a date';\n return typeof value === 'object' ? 'a mapping' : JSON.stringify(value);\n}\n","import type { Approval, Layer, Verdict } from '../ir.js';\n\nexport interface Principal {\n membershipId?: string;\n email?: string;\n groups?: string[];\n /** The local agent making the call, for a `products:` overlay. */\n product?: string;\n}\n\n/** One call, as the enforce path and the local hook both see it. */\nexport interface CallInput {\n tool: string;\n /**\n * The inventory's `mcp__<server>__<tool>` name for the tool the host matched,\n * so a rule keyed by the qualified name applies to a bare-name call.\n */\n qualifiedName?: string;\n arguments: Record<string, unknown>;\n /**\n * Derived fields a host may supply: `path`, `program`, `command`,\n * `writeRedirection`, `withinWorkspace`, `url`, `host`, `skill`, `env`.\n * Globs are literal, so a host writes `path` home-relative (`~/.ssh/id_rsa`)\n * when the path is under the user's home; `files.deny: [\"~/.ssh/**\"]` then\n * matches exactly what the author wrote.\n */\n derived?: Record<string, unknown>;\n /** Capability tags the inventory holds for this tool. */\n capabilities?: string[];\n /** The tool's live input-schema hash, when the caller knows it. */\n schemaHash?: string | null;\n member?: Principal;\n /** ISO date-time the call is evaluated at. */\n timestamp: string;\n}\n\nexport interface SchemaDriftObligation {\n type: 'schema_drift';\n statementId: string;\n bound: string;\n observed: string | null;\n}\n\nexport type Obligation = SchemaDriftObligation;\n\nexport interface VerdictProvenance {\n policyId: string;\n statementId: string | null;\n ruleKey: string;\n variant: number;\n layer: Layer;\n}\n\nexport interface Evaluation {\n verdict: Verdict;\n /** The floor's own verdict, so a caller can tell a floor block from a rule block. */\n floorVerdict: Verdict | null;\n approval: Approval | null;\n obligations: Obligation[];\n provenance: VerdictProvenance;\n}\n\nexport const VERDICT_RANK: Record<Verdict, number> = { allow: 0, hold: 1, block: 2 };\n\nexport function stricter(a: Verdict, b: Verdict): Verdict {\n return VERDICT_RANK[a] >= VERDICT_RANK[b] ? a : b;\n}\n","/**\n * Glob matching for tool keys and paths. `*` matches any run of characters\n * except `/`; `**` matches across `/`; `?` matches one character. Tool keys\n * carry no `/`, so `*` spans the whole name there. Anchored at both ends.\n */\nexport function globToRegExp(pattern: string): RegExp {\n let source = '^';\n for (let i = 0; i < pattern.length; i++) {\n const ch = pattern[i]!;\n if (ch === '*') {\n const double = pattern[i + 1] === '*';\n source += double ? '.*' : '[^/]*';\n if (double) i++;\n } else if (ch === '?') {\n source += '[^/]';\n } else {\n source += escapeRegExp(ch);\n }\n }\n return new RegExp(source + '$');\n}\n\nexport function matchGlob(pattern: string, value: string): boolean {\n return globToRegExp(pattern).test(value);\n}\n\nexport function isGlob(key: string): boolean {\n return key.includes('*') || key.includes('?');\n}\n\nfunction escapeRegExp(ch: string): string {\n return /[\\\\^$.|?*+()[\\]{}]/.test(ch) ? '\\\\' + ch : ch;\n}\n","import type { Statement } from '../ir.js';\nimport { isGlob, matchGlob } from './glob.js';\nimport type { CallInput } from './input.js';\n\n/**\n * Key selection: a key matches the call's bare name or its qualified name.\n * An exact key beats any glob, a longer key beats a shorter one. Two\n * same-length globs matching one tool are rejected at compile time; here the\n * first in document order wins so evaluation stays deterministic.\n */\nexport function selectRuleKey(statements: Statement[], call: Pick<CallInput, 'tool' | 'qualifiedName'>): string | null {\n return selectKey(ruleKeysOf(statements), call.qualifiedName === undefined ? [call.tool] : [call.tool, call.qualifiedName]);\n}\n\nexport function selectKey(keys: Iterable<string>, names: string[]): string | null {\n let best: string | null = null;\n for (const key of keys) {\n if (!names.some((name) => keyMatches(key, name))) continue;\n if (best === null || keyBeats(key, best)) best = key;\n }\n return best;\n}\n\nfunction ruleKeysOf(statements: Statement[]): Set<string> {\n const keys = new Set<string>();\n for (const s of statements) if ('tool' in s.match) keys.add(s.match.tool);\n return keys;\n}\n\nfunction keyMatches(key: string, tool: string): boolean {\n return isGlob(key) ? matchGlob(key, tool) : key === tool;\n}\n\nfunction keyBeats(candidate: string, incumbent: string): boolean {\n const candidateGlob = isGlob(candidate);\n const incumbentGlob = isGlob(incumbent);\n if (candidateGlob !== incumbentGlob) return !candidateGlob;\n return candidate.length > incumbent.length;\n}\n\n/** The variants of one rule key in declared order. */\nexport function variantsOf(statements: Statement[], ruleKey: string): Statement[] {\n return statements\n .filter((s) => 'tool' in s.match && s.match.tool === ruleKey)\n .sort((a, b) => ('tool' in a.match && 'tool' in b.match ? a.match.order - b.match.order : 0));\n}\n\nexport function capabilityStatements(statements: Statement[], tags: string[]): Statement[] {\n return statements.filter((s) => 'capability' in s.match && tags.includes(s.match.capability));\n}\n","import type { InventoryTool } from '../compile/port.js';\nimport { VERDICT_RANK } from '../evaluate/input.js';\nimport { selectKey } from '../evaluate/select.js';\nimport type { Verdict } from '../ir.js';\nimport type { PolicySource, RuleValue, RuleVariant } from './grammar.js';\n\nexport interface Loosening {\n key: string;\n verdict: Verdict;\n base: Verdict;\n}\n\n/**\n * Overlay rule keys whose loosest variant is looser than the strictest base\n * verdict for the same key, or for any inventory tool the key decides in the\n * overlay, where both sides select their key by the tool's bare or qualified\n * name as the evaluator does.\n */\nexport function looseningsOf(base: PolicySource['spec']['tools'], overlay: Record<string, RuleValue>, inventory: InventoryTool[]): Loosening[] {\n const baseKeys = Object.keys(base.rules ?? {});\n const overlayKeys = Object.keys(overlay);\n const out: Loosening[] = [];\n for (const key of overlayKeys) {\n const verdict = loosest(overlay[key] as RuleVariant[]);\n const bases = [baseVerdict(base, baseKeys.includes(key) ? key : null)];\n for (const tool of inventory) {\n const names = tool.qualifiedName === undefined ? [tool.name] : [tool.name, tool.qualifiedName];\n if (selectKey(overlayKeys, names) === key) bases.push(baseVerdict(base, selectKey(baseKeys, names)));\n }\n const strictest = bases.reduce((a, b) => (looser(a, b) ? b : a));\n if (looser(verdict, strictest)) out.push({ key, verdict, base: strictest });\n }\n return out;\n}\n\nfunction baseVerdict(base: PolicySource['spec']['tools'], key: string | null): Verdict {\n const variants = key === null ? undefined : (base.rules?.[key] as RuleVariant[] | undefined);\n if (!variants) return base.default;\n return variants.reduce<Verdict>((v, x) => (looser(v, x.action) ? x.action : v), 'allow');\n}\n\nfunction loosest(variants: RuleVariant[]): Verdict {\n return variants.reduce<Verdict>((v, x) => (looser(x.action, v) ? x.action : v), 'block');\n}\n\nfunction looser(a: Verdict, b: Verdict): boolean {\n return VERDICT_RANK[a] < VERDICT_RANK[b];\n}\n","/** The regex subset RegExp, RE2 and the Python translator (python/armoriq_policy_ir/jsregex.py) all read alike; both parsers walk UTF-16 units. */\nexport function isPortablePattern(pattern: unknown): boolean {\n if (typeof pattern !== 'string') return false;\n try {\n new RegExp(pattern);\n } catch {\n return false;\n }\n const parser = new Parser(pattern);\n return parser.alternatives() && parser.done();\n}\n\ntype Atom = 'quantifiable' | 'assertion' | null;\ntype ClassAtom = 'char' | 'set' | null;\n\nconst ESCAPED_PUNCTUATION = new Set('\\\\/.*+?()[]{}|^$-');\nconst CONTROL_ESCAPES = new Set('tnrfv');\nconst SET_ESCAPES = new Set('dwsDWS');\nconst CLASS_SET_ESCAPES = new Set('dws');\nconst BARE_SPECIALS = new Set(']{}*+?');\nconst QUANTIFIER = /^\\{\\d+(,\\d*)?\\}/;\n\nclass Parser {\n private i = 0;\n\n constructor(private readonly p: string) {}\n\n done(): boolean {\n return this.i === this.p.length;\n }\n\n alternatives(): boolean {\n while (!this.done() && this.p[this.i] !== ')') {\n if (this.p[this.i] === '|') this.i++;\n else if (!this.term()) return false;\n }\n return true;\n }\n\n private term(): boolean {\n const atom = this.atom();\n return atom !== null && this.quantifier(atom === 'quantifiable');\n }\n\n private atom(): Atom {\n const c = this.p[this.i++]!;\n if (c === '^' || c === '$') return 'assertion';\n if (c === '\\\\') return this.escape();\n if (c === '[') return this.charClass() ? 'quantifiable' : null;\n if (c === '(') return this.group() ? 'quantifiable' : null;\n return BARE_SPECIALS.has(c) ? null : 'quantifiable';\n }\n\n private escape(): Atom {\n const e = this.p[this.i++] ?? '';\n if (e === 'b' || e === 'B') return 'assertion';\n if (SET_ESCAPES.has(e) || CONTROL_ESCAPES.has(e) || ESCAPED_PUNCTUATION.has(e)) return 'quantifiable';\n return this.hexEscape(e) ? 'quantifiable' : null;\n }\n\n private hexEscape(e: string): boolean {\n const width = e === 'x' ? 2 : e === 'u' ? 4 : 0;\n const digits = this.p.slice(this.i, this.i + width);\n if (width === 0 || !/^[0-9a-fA-F]+$/.test(digits) || digits.length !== width) return false;\n this.i += width;\n return true;\n }\n\n private group(): boolean {\n if (this.p[this.i] === '?') {\n if (this.p[this.i + 1] !== ':') return false;\n this.i += 2;\n }\n if (!this.alternatives() || this.p[this.i] !== ')') return false;\n this.i++;\n return true;\n }\n\n private charClass(): boolean {\n if (this.p[this.i] === '^') this.i++;\n if (this.p[this.i] === ']') return false;\n while (!this.done() && this.p[this.i] !== ']') {\n if (!this.classItem()) return false;\n }\n if (this.done()) return false;\n this.i++;\n return true;\n }\n\n private classItem(): boolean {\n const start = this.classAtom();\n if (start === null) return false;\n if (this.p[this.i] !== '-' || this.p[this.i + 1] === ']') return true;\n this.i++;\n return start === 'char' && this.classAtom() === 'char';\n }\n\n private classAtom(): ClassAtom {\n const c = this.p[this.i++]!;\n if (c === '[') return null;\n if (c !== '\\\\') return isSurrogate(c) ? null : 'char';\n const e = this.p[this.i++] ?? '';\n if (CLASS_SET_ESCAPES.has(e)) return 'set';\n if (CONTROL_ESCAPES.has(e) || ESCAPED_PUNCTUATION.has(e)) return 'char';\n return this.hexEscape(e) ? 'char' : null;\n }\n\n private quantifier(quantifiable: boolean): boolean {\n const length = this.quantifierLength();\n if (length === 0) return true;\n if (length < 0 || !quantifiable) return false;\n this.i += length;\n if (this.p[this.i] === '?') this.i++;\n return true;\n }\n\n private quantifierLength(): number {\n const c = this.p[this.i];\n if (c === '*' || c === '+' || c === '?') return 1;\n if (c !== '{') return 0;\n return QUANTIFIER.exec(this.p.slice(this.i))?.[0].length ?? -1;\n }\n}\n\nfunction isSurrogate(c: string): boolean {\n const code = c.charCodeAt(0);\n return code >= 0xd800 && code <= 0xdfff;\n}\n","import type { Approval, Verdict } from '../ir.js';\nimport { VERDICT_RANK } from '../evaluate/input.js';\nimport type { InventoryTool } from '../compile/port.js';\nimport { Diagnostics } from './diagnostics.js';\nimport type { ConditionSpec, Overlay, PolicySource, RuleValue, RuleVariant, SourceOperator } from './grammar.js';\nimport { looseningsOf } from './loosening.js';\nimport { isPortablePattern } from './portable-regex.js';\n\n/**\n * Everything that can be checked without an inventory. Inventory-dependent\n * checks (roster clamp, glob collisions on real tools, schema binding) live in\n * the compiler. An inventory, when given, lets the loosening check match a\n * tool's bare and qualified names across the base and an overlay.\n */\nexport function validate(source: PolicySource, inventory: InventoryTool[] = []): Diagnostics {\n const diag = new Diagnostics();\n const ctx: Context = { diag, approvalDefaults: source.spec.approvalDefaults, base: source.spec.tools, inventory };\n validateTargetSections(ctx, source);\n if (source.spec.approvalDefaults) validateApproval(ctx, source.spec.approvalDefaults, '/spec/approvalDefaults', true);\n validateRules(ctx, source.spec.tools.rules, '/spec/tools/rules');\n validateOverlays(ctx, source.spec.members, '/spec/members');\n validateOverlays(ctx, source.spec.products, '/spec/products');\n validateCapture(ctx, source);\n return diag;\n}\n\ninterface Context {\n diag: Diagnostics;\n approvalDefaults: Approval | undefined;\n base: PolicySource['spec']['tools'];\n inventory: InventoryTool[];\n}\n\n/** `products:` and `precedence:` are local only; `members:` is enterprise only (VC-17, VC-18). */\nfunction validateTargetSections(ctx: Context, source: PolicySource): void {\n const local = 'device' in source.target;\n if (!local && source.spec.products) ctx.diag.error('local_only_section', '/spec/products', 'products applies only under target device: local');\n if (!local && source.precedence) ctx.diag.error('local_only_section', '/precedence', 'precedence applies only under target device: local');\n if (local && source.spec.members) ctx.diag.error('enterprise_only_section', '/spec/members', 'members applies only to an enterprise target');\n if (local && source.metadata.orgId) ctx.diag.error('enterprise_only_field', '/metadata/orgId', 'a local policy carries no orgId');\n}\n\nfunction validateRules(ctx: Context, rules: Record<string, RuleValue> | undefined, path: string): void {\n for (const [key, variants] of Object.entries(rules ?? {})) {\n validateVariants(ctx, variants as RuleVariant[], `${path}/${key}`);\n }\n}\n\nfunction validateVariants(ctx: Context, variants: RuleVariant[], path: string): void {\n variants.forEach((variant, i) => {\n const vpath = `${path}/${i}`;\n if (i > 0 && isUnconditional(variants[i - 1]!)) {\n ctx.diag.error('unreachable_variant', vpath, `variant ${i - 1} has no when, so this variant can never be reached`);\n }\n validateVariant(ctx, variant, vpath);\n });\n}\n\nfunction isUnconditional(variant: RuleVariant): boolean {\n return !variant.when || Object.keys(variant.when).length === 0;\n}\n\nfunction validateVariant(ctx: Context, variant: RuleVariant, path: string): void {\n if (variant.action === 'hold') validateHoldApprover(ctx, variant, path);\n for (const [field, spec] of Object.entries(variant.when ?? {})) validateCondition(ctx, spec, `${path}/when/${field}`);\n}\n\n/** A hold must name a way to resolve its approver, on the variant or in approvalDefaults (VC-6). */\nfunction validateHoldApprover(ctx: Context, variant: RuleVariant, path: string): void {\n if (variant.approval) return void validateApproval(ctx, variant.approval, `${path}/approval`, true);\n if (!ctx.approvalDefaults) {\n ctx.diag.error('hold_without_approver', path, 'a hold names an approval or the document sets approvalDefaults');\n }\n}\n\nfunction validateApproval(ctx: Context, approval: Approval, path: string, requireResolvable: boolean): void {\n if (!Number.isInteger(approval.approvers) || approval.approvers < 1) {\n ctx.diag.error('approvers_count', `${path}/approvers`, 'approvers is a whole number of at least 1');\n }\n if (requireResolvable && !namesAnApprover(approval)) {\n ctx.diag.error('approval_unresolvable', path, 'an approval names roles, members or anyMember: true');\n }\n}\n\nfunction namesAnApprover(approval: Approval): boolean {\n return (approval.roles?.length ?? 0) > 0 || (approval.members?.length ?? 0) > 0 || approval.anyMember === true;\n}\n\ntype OperandCheck = (value: unknown) => boolean;\n\nconst OPERANDS: Record<SourceOperator, [OperandCheck, string]> = {\n eq: [() => true, 'any value'],\n neq: [() => true, 'any value'],\n in: [Array.isArray, 'a list'],\n notIn: [Array.isArray, 'a list'],\n gt: [isNumber, 'a number'],\n gte: [isNumber, 'a number'],\n lt: [isNumber, 'a number'],\n lte: [isNumber, 'a number'],\n matches: [isPortablePattern, 'a regular expression in the portable subset'],\n notMatches: [isPortablePattern, 'a regular expression in the portable subset'],\n startsWith: [isString, 'a string'],\n glob: [isString, 'a glob'],\n withinWorkspace: [isBoolean, 'true or false'],\n exists: [isBoolean, 'true or false'],\n};\n\nfunction validateCondition(ctx: Context, spec: ConditionSpec, path: string): void {\n const [op, value] = Object.entries(spec)[0] as [SourceOperator, unknown];\n const [check, expected] = OPERANDS[op];\n if (!check(value)) ctx.diag.error('condition_operand', `${path}/${op}`, `${op} takes ${expected}`);\n}\n\nfunction isNumber(v: unknown): boolean {\n return typeof v === 'number' && Number.isFinite(v);\n}\nfunction isString(v: unknown): boolean {\n return typeof v === 'string';\n}\nfunction isBoolean(v: unknown): boolean {\n return typeof v === 'boolean';\n}\n\nfunction validateOverlays(ctx: Context, overlays: Record<string, Overlay> | undefined, path: string): void {\n for (const [key, overlay] of Object.entries(overlays ?? {})) {\n const opath = `${path}/${key}`;\n validateRules(ctx, overlay.tools?.rules, `${opath}/tools/rules`);\n flagLoosening(ctx, overlay, opath);\n }\n}\n\n/** A member or product overlay may loosen the base; the review diff must show it (VC-7). */\nfunction flagLoosening(ctx: Context, overlay: Overlay, path: string): void {\n const baseDefault = ctx.base.default;\n if (overlay.tools?.default && looser(overlay.tools.default, baseDefault)) {\n ctx.diag.warning('loosening_grant', `${path}/tools/default`, `default ${overlay.tools.default} is looser than the base default ${baseDefault}`);\n }\n for (const { key, verdict, base } of looseningsOf(ctx.base, overlay.tools?.rules ?? {}, ctx.inventory)) {\n ctx.diag.warning('loosening_grant', `${path}/tools/rules/${key}`, `${key}: ${verdict} is looser than the base ${base}`);\n }\n}\n\nfunction looser(a: Verdict, b: Verdict): boolean {\n return VERDICT_RANK[a] < VERDICT_RANK[b];\n}\n\nfunction validateCapture(ctx: Context, source: PolicySource): void {\n const c = source.spec.capture;\n if (!c) return;\n if (c.sample !== undefined && (c.sample < 0 || c.sample > 1)) ctx.diag.error('capture_sample', '/spec/capture/sample', 'sample is between 0 and 1');\n if (c.maxBytesPerCall !== undefined && (c.maxBytesPerCall < 0 || !Number.isInteger(c.maxBytesPerCall))) {\n ctx.diag.error('capture_max_bytes', '/spec/capture/maxBytesPerCall', 'maxBytesPerCall is a whole number of bytes');\n }\n}\n","import { stringify } from 'yaml';\nimport type { PolicySource, RuleValue, RuleVariant } from '../document/grammar.js';\n\n/**\n * PolicySource back to YAML such that `parse(serialize(x))` equals `x`\n * (VC-10). A single unconditional variant with no other fields is written as\n * the scalar shorthand; `expiresAt: never` is written only where the parser\n * would not materialize it identically anyway (everywhere), so it is kept.\n */\nexport function serialize(source: PolicySource): string {\n const spec = { ...source.spec, tools: { ...source.spec.tools, rules: shorthand(source.spec.tools.rules) } };\n if (spec.members) spec.members = overlays(spec.members);\n if (spec.products) spec.products = overlays(spec.products);\n const doc: Record<string, unknown> = {\n apiVersion: source.apiVersion,\n kind: source.kind,\n metadata: source.metadata,\n target: source.target,\n };\n if (source.precedence) doc.precedence = source.precedence;\n doc.spec = spec;\n return stringify(doc, { lineWidth: 0, defaultStringType: 'PLAIN', defaultKeyType: 'PLAIN', aliasDuplicateObjects: false });\n}\n\nfunction shorthand(rules: Record<string, RuleValue> | undefined): Record<string, RuleValue> | undefined {\n if (!rules) return undefined;\n const out: Record<string, RuleValue> = {};\n for (const [key, value] of Object.entries(rules)) out[key] = scalarIfPlain(value as RuleVariant[]);\n return out;\n}\n\nfunction scalarIfPlain(variants: RuleVariant[]): RuleValue {\n const only = variants.length === 1 ? variants[0]! : null;\n const plain = only && Object.keys(only).length === 2 && only.expiresAt === 'never';\n return plain ? only.action : variants;\n}\n\nfunction overlays<T extends { tools?: { rules?: Record<string, RuleValue> } }>(map: Record<string, T>): Record<string, T> {\n const out: Record<string, T> = {};\n for (const [key, overlay] of Object.entries(map)) {\n out[key] = overlay.tools?.rules ? { ...overlay, tools: { ...overlay.tools, rules: shorthand(overlay.tools.rules) } } : overlay;\n }\n return out;\n}\n","import type { EnforceabilityReport } from './compile/report.js';\nimport type { Diagnostic } from './document/diagnostics.js';\nimport type { PolicyDocument, Verdict } from './ir.js';\n\nexport const COMPOSE_INTENT_MAX = 4000;\n\nexport interface ComposeTarget {\n agent: string;\n}\n\nexport interface ComposeAnswer {\n questionId: string;\n /** The question as it was asked, since compose keeps no state between rounds. */\n question: string;\n text: string;\n}\n\nexport interface ComposeRequest {\n target: ComposeTarget;\n intent: string;\n draft?: string;\n answers?: ComposeAnswer[];\n}\n\nexport interface ComposeUnsupported {\n sentence: string;\n reason: string;\n}\n\nexport interface ComposeQuestion {\n id: string;\n text: string;\n}\n\nexport interface ComposeChangedCall {\n auditId: string;\n tool: string;\n arguments: Record<string, unknown>;\n executedAt: string;\n from: Verdict;\n to: Verdict;\n}\n\nexport interface ComposeReplay {\n calls: number;\n verdicts: Record<Verdict, number>;\n changed: ComposeChangedCall[];\n}\n\nexport interface ComposeExample {\n /** Same format as `Diagnostic.path`: `/spec/tools/rules/<key>/<variant>`. */\n path: string;\n call: { tool: string; qualifiedName?: string; arguments: Record<string, unknown> };\n verdict: Verdict;\n}\n\nexport interface ComposePreview {\n replay: ComposeReplay | null;\n examples: ComposeExample[];\n}\n\nexport interface ComposeResponse {\n composeId: string;\n document: PolicyDocument | null;\n yaml: string;\n diagnostics: Diagnostic[];\n report: EnforceabilityReport;\n unsupported: ComposeUnsupported[];\n questions: ComposeQuestion[];\n /** Source sentence per rule, keyed by `Diagnostic.path`: `/spec/tools/rules/<key>/<variant>`. */\n sources: Record<string, string>;\n preview: ComposePreview;\n model: string;\n rounds: number;\n /** The model's one-paragraph explanation of the draft. */\n reasoning?: string;\n}\n"],"mappings":"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","names":["overlays","looser"]}
package/dist/index.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
23
  CAPABILITY_KEYS: () => CAPABILITY_KEYS,
24
+ COMPOSE_INTENT_MAX: () => COMPOSE_INTENT_MAX,
24
25
  Diagnostics: () => Diagnostics,
25
26
  HASH_PREFIX: () => HASH_PREFIX,
26
27
  KNOWN_CONTROLS: () => KNOWN_CONTROLS,
@@ -273,10 +274,13 @@ function numeric(a, e, test) {
273
274
  }
274
275
 
275
276
  // src/evaluate/select.ts
276
- function selectRuleKey(statements, tool) {
277
+ function selectRuleKey(statements, call) {
278
+ return selectKey(ruleKeysOf(statements), call.qualifiedName === void 0 ? [call.tool] : [call.tool, call.qualifiedName]);
279
+ }
280
+ function selectKey(keys, names) {
277
281
  let best = null;
278
- for (const key of ruleKeysOf(statements)) {
279
- if (!keyMatches(key, tool)) continue;
282
+ for (const key of keys) {
283
+ if (!names.some((name) => keyMatches(key, name))) continue;
280
284
  if (best === null || keyBeats(key, best)) best = key;
281
285
  }
282
286
  return best;
@@ -338,7 +342,7 @@ function decideLayer(statements, input) {
338
342
  return stricter(capability.statement.effect, ruleDecision.statement.effect) === ruleDecision.statement.effect ? ruleDecision : capability;
339
343
  }
340
344
  function decideRule(statements, input) {
341
- const key = selectRuleKey(statements, input.tool);
345
+ const key = selectRuleKey(statements, input);
342
346
  if (key === null) return null;
343
347
  const winner = variantsOf(statements, key).find((v) => conditionsHold(input, v.conditions));
344
348
  return winner ? { statement: winner, obligations: driftObligations(winner, input) } : null;
@@ -366,11 +370,12 @@ function driftObligations(statement, input) {
366
370
 
367
371
  // src/evaluate/evaluate.ts
368
372
  function evaluate(input, bound) {
373
+ if (!bound.floor && !bound.group && !bound.agent) throw new Error("evaluate: no document is bound to the target");
369
374
  const floor2 = decideFloor(bound.floor, input);
370
375
  if (floor2?.statement.effect === "block") return fromDecision(floor2, bound.floor, "floor");
371
- const candidate = decideCandidate(input, bound);
376
+ const candidate = decideCandidate(input, bound, floor2 === null);
372
377
  const floorVerdict = floor2?.statement.effect ?? null;
373
- if (floorVerdict && stricter(floorVerdict, candidate.verdict) !== candidate.verdict) {
378
+ if (!candidate || floorVerdict && stricter(floorVerdict, candidate.verdict) !== candidate.verdict) {
374
379
  return { ...fromDecision(floor2, bound.floor, "floor"), floorVerdict };
375
380
  }
376
381
  return { ...candidate, floorVerdict };
@@ -379,21 +384,28 @@ function decideFloor(doc, input) {
379
384
  if (!doc) return null;
380
385
  return decideLayer(liveStatements(doc, input).filter((s) => s.subject === null), input);
381
386
  }
382
- function decideCandidate(input, bound) {
383
- for (const doc of [bound.agent, bound.group]) {
384
- if (!doc) continue;
385
- const statements = liveStatements(doc, input);
387
+ function decideCandidate(input, bound, floorSilent) {
388
+ for (const doc2 of [bound.agent, bound.group]) {
389
+ if (!doc2) continue;
390
+ const statements = liveStatements(doc2, input);
386
391
  const member = decideLayer(memberScope(statements, input.member), input);
387
- if (member) return fromDecision(member, doc, "member");
392
+ if (member) return fromDecision(member, doc2, "member");
388
393
  const own = decideLayer(statements.filter((s) => s.subject === null), input);
389
- if (own) return fromDecision(own, doc, doc.layer);
394
+ if (own) return fromDecision(own, doc2, doc2.layer);
390
395
  }
391
- return fromDefault(mostSpecific(bound));
396
+ const doc = defaultDocument(bound, floorSilent, input.timestamp);
397
+ return doc ? fromDefault(doc) : null;
392
398
  }
393
- function mostSpecific(bound) {
394
- const doc = bound.agent ?? bound.group ?? bound.floor;
395
- if (!doc) throw new Error("evaluate: no document is bound to the target");
396
- return doc;
399
+ function defaultDocument(bound, floorSilent, timestamp) {
400
+ const all = [bound.agent, bound.group, bound.floor].filter((d) => d !== void 0);
401
+ const live = all.filter((d) => isLive(d.expiresAt, timestamp));
402
+ if (live.length === 0) return all[0] ?? null;
403
+ let winner = null;
404
+ for (const doc of live) {
405
+ if (doc === bound.floor && !floorSilent) continue;
406
+ if (!winner || stricter(winner.defaults.tools, doc.defaults.tools) !== winner.defaults.tools) winner = doc;
407
+ }
408
+ return winner;
397
409
  }
398
410
  function fromDecision(decision, doc, layer) {
399
411
  const { statement } = decision;
@@ -419,7 +431,7 @@ function fromDefault(doc) {
419
431
  return {
420
432
  verdict,
421
433
  floorVerdict: null,
422
- approval: null,
434
+ approval: verdict === "hold" ? doc.defaults.approval ?? null : null,
423
435
  obligations: [],
424
436
  provenance: { policyId: doc.policyId, statementId: null, ruleKey: "tools.default", variant: -1, layer: doc.layer }
425
437
  };
@@ -828,6 +840,35 @@ function parseCapture(r, value) {
828
840
  return out;
829
841
  }
830
842
 
843
+ // src/document/loosening.ts
844
+ function looseningsOf(base, overlay, inventory) {
845
+ const baseKeys = Object.keys(base.rules ?? {});
846
+ const overlayKeys = Object.keys(overlay);
847
+ const out = [];
848
+ for (const key of overlayKeys) {
849
+ const verdict = loosest(overlay[key]);
850
+ const bases = [baseVerdict(base, baseKeys.includes(key) ? key : null)];
851
+ for (const tool of inventory) {
852
+ const names = tool.qualifiedName === void 0 ? [tool.name] : [tool.name, tool.qualifiedName];
853
+ if (selectKey(overlayKeys, names) === key) bases.push(baseVerdict(base, selectKey(baseKeys, names)));
854
+ }
855
+ const strictest = bases.reduce((a, b) => looser(a, b) ? b : a);
856
+ if (looser(verdict, strictest)) out.push({ key, verdict, base: strictest });
857
+ }
858
+ return out;
859
+ }
860
+ function baseVerdict(base, key) {
861
+ const variants = key === null ? void 0 : base.rules?.[key];
862
+ if (!variants) return base.default;
863
+ return variants.reduce((v, x) => looser(v, x.action) ? x.action : v, "allow");
864
+ }
865
+ function loosest(variants) {
866
+ return variants.reduce((v, x) => looser(x.action, v) ? x.action : v, "block");
867
+ }
868
+ function looser(a, b) {
869
+ return VERDICT_RANK[a] < VERDICT_RANK[b];
870
+ }
871
+
831
872
  // src/document/portable-regex.ts
832
873
  function isPortablePattern(pattern) {
833
874
  if (typeof pattern !== "string") return false;
@@ -942,9 +983,9 @@ function isSurrogate(c) {
942
983
  }
943
984
 
944
985
  // src/document/validate.ts
945
- function validate(source) {
986
+ function validate(source, inventory = []) {
946
987
  const diag = new Diagnostics();
947
- const ctx = { diag, approvalDefaults: source.spec.approvalDefaults, base: source.spec.tools };
988
+ const ctx = { diag, approvalDefaults: source.spec.approvalDefaults, base: source.spec.tools, inventory };
948
989
  validateTargetSections(ctx, source);
949
990
  if (source.spec.approvalDefaults) validateApproval(ctx, source.spec.approvalDefaults, "/spec/approvalDefaults", true);
950
991
  validateRules(ctx, source.spec.tools.rules, "/spec/tools/rules");
@@ -1037,23 +1078,14 @@ function validateOverlays(ctx, overlays2, path) {
1037
1078
  }
1038
1079
  function flagLoosening(ctx, overlay, path) {
1039
1080
  const baseDefault = ctx.base.default;
1040
- if (overlay.tools?.default && looser(overlay.tools.default, baseDefault)) {
1081
+ if (overlay.tools?.default && looser2(overlay.tools.default, baseDefault)) {
1041
1082
  ctx.diag.warning("loosening_grant", `${path}/tools/default`, `default ${overlay.tools.default} is looser than the base default ${baseDefault}`);
1042
1083
  }
1043
- for (const [key, variants] of Object.entries(overlay.tools?.rules ?? {})) {
1044
- const base = baseVerdictFor(ctx.base, key);
1045
- const loosest = variants.reduce((v, x) => looser(x.action, v) ? x.action : v, "block");
1046
- if (looser(loosest, base)) {
1047
- ctx.diag.warning("loosening_grant", `${path}/tools/rules/${key}`, `${key}: ${loosest} is looser than the base ${base}`);
1048
- }
1084
+ for (const { key, verdict, base } of looseningsOf(ctx.base, overlay.tools?.rules ?? {}, ctx.inventory)) {
1085
+ ctx.diag.warning("loosening_grant", `${path}/tools/rules/${key}`, `${key}: ${verdict} is looser than the base ${base}`);
1049
1086
  }
1050
1087
  }
1051
- function baseVerdictFor(base, key) {
1052
- const variants = base.rules?.[key];
1053
- if (!variants) return base.default;
1054
- return variants.reduce((v, x) => looser(v, x.action) ? x.action : v, "allow");
1055
- }
1056
- function looser(a, b) {
1088
+ function looser2(a, b) {
1057
1089
  return VERDICT_RANK[a] < VERDICT_RANK[b];
1058
1090
  }
1059
1091
  function validateCapture(ctx, source) {
@@ -1095,11 +1127,11 @@ function resolveKey(key, inventory, diag, path) {
1095
1127
  }
1096
1128
  function bindExact(key, tool, diag, path) {
1097
1129
  if (!tool) {
1098
- diag.warning("unknown_tool_key", path, `"${key}" is not in the target's inventory; the rule compiles and binds nothing until the tool appears`);
1130
+ diag.warning("unknown_tool_key", path, `"${key}" is not in the target's inventory yet; the rule is enforced on any call that names it, but its conditions are not checked against a schema`);
1099
1131
  return null;
1100
1132
  }
1101
1133
  if (!tool.declared) {
1102
- diag.warning("observed_only_tool", path, `"${key}" has only been observed, never declared; the rule compiles without a schema binding`);
1134
+ diag.warning("observed_only_tool", path, `"${key}" has been observed but never declared; the rule is enforced on any call that names it, but its conditions are not checked against a schema`);
1103
1135
  return null;
1104
1136
  }
1105
1137
  return tool;
@@ -1270,7 +1302,25 @@ var HIPAA = [
1270
1302
  "164.312(d)",
1271
1303
  "164.312(e)(1)"
1272
1304
  ].map((c) => `HIPAA-${c}`);
1273
- var KNOWN_CONTROLS = /* @__PURE__ */ new Set([...SOC2, ...HIPAA]);
1305
+ var FERPA = ["99.10", "99.20", "99.30", "99.31", "99.32", "99.33", "99.34", "99.35", "99.36", "99.37"].map((c) => `FERPA-${c}`);
1306
+ var ITAR = [
1307
+ "120.11",
1308
+ "120.31",
1309
+ "120.32",
1310
+ "120.33",
1311
+ "120.34",
1312
+ "120.43",
1313
+ "120.50",
1314
+ "120.51",
1315
+ "120.52",
1316
+ "120.54",
1317
+ "120.55",
1318
+ "120.56",
1319
+ "120.62",
1320
+ "120.63"
1321
+ ].map((c) => `ITAR-${c}`);
1322
+ var EAR = ["734.3", "734.7", "734.8", "734.9", "734.13", "734.14", "734.15", "734.16", "734.17", "734.18", "734.19", "734.20"].map((c) => `EAR-${c}`);
1323
+ var KNOWN_CONTROLS = /* @__PURE__ */ new Set([...SOC2, ...HIPAA, ...FERPA, ...ITAR, ...EAR]);
1274
1324
 
1275
1325
  // src/compile/lower-rules.ts
1276
1326
  function lowerRules(rules, ctx, path, subject, scopeExpiry) {
@@ -1389,13 +1439,15 @@ function uncovered(source, inventory) {
1389
1439
 
1390
1440
  // src/compile/compile.ts
1391
1441
  function compile(source, inventory, options) {
1392
- const diag = validate(source);
1442
+ const diag = validate(source, inventory);
1393
1443
  const report = enforceabilityReport(source, inventory);
1394
1444
  if (diag.hasErrors) return { document: null, diagnostics: diag, report };
1395
1445
  const layer = layerOfTarget(targetOf2(source.target));
1396
1446
  const ctx = { inventory, diag, layer, approvalDefaults: source.spec.approvalDefaults, source: options.source ?? "yaml" };
1397
1447
  checkGlobCollisions(Object.keys(source.spec.tools.rules ?? {}), inventory, diag, "/spec/tools/rules");
1398
- checkDeviceFirst(source, diag);
1448
+ checkOverlayGlobCollisions(source.spec.members, inventory, diag, "/spec/members");
1449
+ checkOverlayGlobCollisions(source.spec.products, inventory, diag, "/spec/products");
1450
+ checkDeviceFirst(source, inventory, diag);
1399
1451
  const statements = [
1400
1452
  ...lowerRules(source.spec.tools.rules, ctx, "/spec/tools/rules", null, source.spec.expiresAt),
1401
1453
  ...lowerFloors(source.spec, ctx),
@@ -1431,7 +1483,8 @@ function defaultsOf(source) {
1431
1483
  tools: source.spec.tools.default,
1432
1484
  network: source.spec.network?.default ?? "block",
1433
1485
  files: "allow",
1434
- skills: source.spec.skills?.default ?? "allow"
1486
+ skills: source.spec.skills?.default ?? "allow",
1487
+ ...source.spec.approvalDefaults ? { approval: source.spec.approvalDefaults } : {}
1435
1488
  };
1436
1489
  }
1437
1490
  function captureOf(source) {
@@ -1443,24 +1496,19 @@ function captureOf(source) {
1443
1496
  sample: c?.sample ?? 1
1444
1497
  };
1445
1498
  }
1446
- function checkDeviceFirst(source, diag) {
1499
+ function checkOverlayGlobCollisions(overlays2, inventory, diag, path) {
1500
+ for (const [key, overlay] of Object.entries(overlays2 ?? {})) {
1501
+ checkGlobCollisions(Object.keys(overlay.tools?.rules ?? {}), inventory, diag, `${path}/${key}/tools/rules`);
1502
+ }
1503
+ }
1504
+ function checkDeviceFirst(source, inventory, diag) {
1447
1505
  if (!("device" in source.target) || source.precedence === "agent-first") return;
1448
1506
  for (const [product, overlay] of Object.entries(source.spec.products ?? {})) {
1449
- for (const [key, variants] of Object.entries(overlay.tools?.rules ?? {})) {
1450
- if (loosensBase(variants, baseRankFor(source, key))) {
1451
- diag.error("device_first_loosening", `/spec/products/${product}/tools/rules/${key}`, `under device-first a product overlay may only tighten the base; set precedence: agent-first to allow this`);
1452
- }
1507
+ for (const { key } of looseningsOf(source.spec.tools, overlay.tools?.rules ?? {}, inventory)) {
1508
+ diag.error("device_first_loosening", `/spec/products/${product}/tools/rules/${key}`, `under device-first a product overlay may only tighten the base; set precedence: agent-first to allow this`);
1453
1509
  }
1454
1510
  }
1455
1511
  }
1456
- function baseRankFor(source, key) {
1457
- const base = source.spec.tools.rules?.[key];
1458
- if (!Array.isArray(base)) return VERDICT_RANK[source.spec.tools.default];
1459
- return Math.min(...base.map((v) => VERDICT_RANK[v.action]));
1460
- }
1461
- function loosensBase(variants, baseRank) {
1462
- return variants.some((v) => VERDICT_RANK[v.action] < baseRank);
1463
- }
1464
1512
 
1465
1513
  // src/compile/serialize.ts
1466
1514
  var import_yaml2 = require("yaml");
@@ -1496,9 +1544,13 @@ function overlays(map) {
1496
1544
  }
1497
1545
  return out;
1498
1546
  }
1547
+
1548
+ // src/compose.ts
1549
+ var COMPOSE_INTENT_MAX = 4e3;
1499
1550
  // Annotate the CommonJS export names for ESM import in node:
1500
1551
  0 && (module.exports = {
1501
1552
  CAPABILITY_KEYS,
1553
+ COMPOSE_INTENT_MAX,
1502
1554
  Diagnostics,
1503
1555
  HASH_PREFIX,
1504
1556
  KNOWN_CONTROLS,