@armoriq/policy-ir 0.1.4 → 0.1.6
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.
- package/dist/{document-entry-CDOQVeis.d.cts → document-entry-iS3HikJ9.d.cts} +117 -3
- package/dist/{document-entry-CDOQVeis.d.ts → document-entry-iS3HikJ9.d.ts} +117 -3
- package/dist/document.cjs +86 -15
- package/dist/document.cjs.map +1 -1
- package/dist/document.d.cts +1 -1
- package/dist/document.d.ts +1 -1
- package/dist/document.js +85 -15
- package/dist/document.js.map +1 -1
- package/dist/index.cjs +85 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -44
- package/dist/index.d.ts +14 -44
- package/dist/index.js +84 -51
- package/dist/index.js.map +1 -1
- package/dist/vectors.cjs +26 -2
- package/dist/vectors.cjs.map +1 -1
- package/dist/vectors.js +26 -2
- package/dist/vectors.js.map +1 -1
- package/package.json +1 -1
- package/vectors/compile.json +8 -1
- package/vectors/evaluate.json +18 -1
package/dist/document.js.map
CHANGED
|
@@ -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 = 100_000;\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\n/** A server whose tools compose left out because it is waiting for admin review. */\nexport interface ComposeHeldServer {\n id: string;\n name: string;\n tools: number;\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 heldServers: ComposeHeldServer[];\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,
|
|
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
|
|
279
|
-
if (!keyMatches(key,
|
|
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
|
|
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
|
|
384
|
-
if (!
|
|
385
|
-
const statements = liveStatements(
|
|
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,
|
|
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,
|
|
394
|
+
if (own) return fromDecision(own, doc2, doc2.layer);
|
|
390
395
|
}
|
|
391
|
-
|
|
396
|
+
const doc = defaultDocument(bound, floorSilent, input.timestamp);
|
|
397
|
+
return doc ? fromDefault(doc) : null;
|
|
392
398
|
}
|
|
393
|
-
function
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
return
|
|
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 &&
|
|
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
|
|
1044
|
-
|
|
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
|
|
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
|
|
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
|
|
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;
|
|
@@ -1407,13 +1439,15 @@ function uncovered(source, inventory) {
|
|
|
1407
1439
|
|
|
1408
1440
|
// src/compile/compile.ts
|
|
1409
1441
|
function compile(source, inventory, options) {
|
|
1410
|
-
const diag = validate(source);
|
|
1442
|
+
const diag = validate(source, inventory);
|
|
1411
1443
|
const report = enforceabilityReport(source, inventory);
|
|
1412
1444
|
if (diag.hasErrors) return { document: null, diagnostics: diag, report };
|
|
1413
1445
|
const layer = layerOfTarget(targetOf2(source.target));
|
|
1414
1446
|
const ctx = { inventory, diag, layer, approvalDefaults: source.spec.approvalDefaults, source: options.source ?? "yaml" };
|
|
1415
1447
|
checkGlobCollisions(Object.keys(source.spec.tools.rules ?? {}), inventory, diag, "/spec/tools/rules");
|
|
1416
|
-
|
|
1448
|
+
checkOverlayGlobCollisions(source.spec.members, inventory, diag, "/spec/members");
|
|
1449
|
+
checkOverlayGlobCollisions(source.spec.products, inventory, diag, "/spec/products");
|
|
1450
|
+
checkDeviceFirst(source, inventory, diag);
|
|
1417
1451
|
const statements = [
|
|
1418
1452
|
...lowerRules(source.spec.tools.rules, ctx, "/spec/tools/rules", null, source.spec.expiresAt),
|
|
1419
1453
|
...lowerFloors(source.spec, ctx),
|
|
@@ -1449,7 +1483,8 @@ function defaultsOf(source) {
|
|
|
1449
1483
|
tools: source.spec.tools.default,
|
|
1450
1484
|
network: source.spec.network?.default ?? "block",
|
|
1451
1485
|
files: "allow",
|
|
1452
|
-
skills: source.spec.skills?.default ?? "allow"
|
|
1486
|
+
skills: source.spec.skills?.default ?? "allow",
|
|
1487
|
+
...source.spec.approvalDefaults ? { approval: source.spec.approvalDefaults } : {}
|
|
1453
1488
|
};
|
|
1454
1489
|
}
|
|
1455
1490
|
function captureOf(source) {
|
|
@@ -1461,24 +1496,19 @@ function captureOf(source) {
|
|
|
1461
1496
|
sample: c?.sample ?? 1
|
|
1462
1497
|
};
|
|
1463
1498
|
}
|
|
1464
|
-
function
|
|
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) {
|
|
1465
1505
|
if (!("device" in source.target) || source.precedence === "agent-first") return;
|
|
1466
1506
|
for (const [product, overlay] of Object.entries(source.spec.products ?? {})) {
|
|
1467
|
-
for (const
|
|
1468
|
-
|
|
1469
|
-
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`);
|
|
1470
|
-
}
|
|
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`);
|
|
1471
1509
|
}
|
|
1472
1510
|
}
|
|
1473
1511
|
}
|
|
1474
|
-
function baseRankFor(source, key) {
|
|
1475
|
-
const base = source.spec.tools.rules?.[key];
|
|
1476
|
-
if (!Array.isArray(base)) return VERDICT_RANK[source.spec.tools.default];
|
|
1477
|
-
return Math.min(...base.map((v) => VERDICT_RANK[v.action]));
|
|
1478
|
-
}
|
|
1479
|
-
function loosensBase(variants, baseRank) {
|
|
1480
|
-
return variants.some((v) => VERDICT_RANK[v.action] < baseRank);
|
|
1481
|
-
}
|
|
1482
1512
|
|
|
1483
1513
|
// src/compile/serialize.ts
|
|
1484
1514
|
var import_yaml2 = require("yaml");
|
|
@@ -1514,9 +1544,13 @@ function overlays(map) {
|
|
|
1514
1544
|
}
|
|
1515
1545
|
return out;
|
|
1516
1546
|
}
|
|
1547
|
+
|
|
1548
|
+
// src/compose.ts
|
|
1549
|
+
var COMPOSE_INTENT_MAX = 1e5;
|
|
1517
1550
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1518
1551
|
0 && (module.exports = {
|
|
1519
1552
|
CAPABILITY_KEYS,
|
|
1553
|
+
COMPOSE_INTENT_MAX,
|
|
1520
1554
|
Diagnostics,
|
|
1521
1555
|
HASH_PREFIX,
|
|
1522
1556
|
KNOWN_CONTROLS,
|