@scopebond/hook 0.8.0 → 0.9.0
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/README.md +210 -0
- package/dist/budget-load.d.ts +68 -0
- package/dist/budget-load.d.ts.map +1 -0
- package/dist/budget-load.js +164 -0
- package/dist/budget-load.js.map +1 -0
- package/dist/capabilities.d.ts +103 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +212 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/classify.d.ts +17 -0
- package/dist/classify.d.ts.map +1 -0
- package/dist/classify.js +78 -0
- package/dist/classify.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +546 -16
- package/dist/cli.js.map +1 -1
- package/dist/cloud.d.ts +8 -0
- package/dist/cloud.d.ts.map +1 -1
- package/dist/cloud.js.map +1 -1
- package/dist/dispatch-cli.d.ts +2 -0
- package/dist/dispatch-cli.d.ts.map +1 -0
- package/dist/dispatch-cli.js +128 -0
- package/dist/dispatch-cli.js.map +1 -0
- package/dist/explain.d.ts.map +1 -1
- package/dist/explain.js +2 -1
- package/dist/explain.js.map +1 -1
- package/dist/group.d.ts +12 -0
- package/dist/group.d.ts.map +1 -0
- package/dist/group.js +55 -0
- package/dist/group.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +10 -0
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +56 -0
- package/dist/install.js.map +1 -1
- package/dist/map.d.ts +4 -0
- package/dist/map.d.ts.map +1 -1
- package/dist/map.js +29 -1
- package/dist/map.js.map +1 -1
- package/dist/obs-emitter.d.ts +132 -0
- package/dist/obs-emitter.d.ts.map +1 -0
- package/dist/obs-emitter.js +415 -0
- package/dist/obs-emitter.js.map +1 -0
- package/dist/obs-store.d.ts +160 -0
- package/dist/obs-store.d.ts.map +1 -0
- package/dist/obs-store.js +367 -0
- package/dist/obs-store.js.map +1 -0
- package/dist/obs-upload.d.ts +24 -0
- package/dist/obs-upload.d.ts.map +1 -0
- package/dist/obs-upload.js +231 -0
- package/dist/obs-upload.js.map +1 -0
- package/dist/observation.d.ts +232 -0
- package/dist/observation.d.ts.map +1 -0
- package/dist/observation.js +308 -0
- package/dist/observation.js.map +1 -0
- package/dist/paths.d.ts +15 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +79 -0
- package/dist/paths.js.map +1 -0
- package/dist/policy-load.d.ts +60 -0
- package/dist/policy-load.d.ts.map +1 -0
- package/dist/policy-load.js +151 -0
- package/dist/policy-load.js.map +1 -0
- package/dist/proof.d.ts +30 -0
- package/dist/proof.d.ts.map +1 -0
- package/dist/proof.js +186 -0
- package/dist/proof.js.map +1 -0
- package/dist/rules.d.ts +20 -0
- package/dist/rules.d.ts.map +1 -1
- package/dist/rules.js +50 -0
- package/dist/rules.js.map +1 -1
- package/dist/runtime.d.ts +18 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +74 -10
- package/dist/runtime.js.map +1 -1
- package/dist/scan.d.ts +7 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +38 -0
- package/dist/scan.js.map +1 -0
- package/dist/shell.d.ts.map +1 -1
- package/dist/shell.js +12 -3
- package/dist/shell.js.map +1 -1
- package/dist/sql-classify.d.ts +11 -0
- package/dist/sql-classify.d.ts.map +1 -0
- package/dist/sql-classify.js +251 -0
- package/dist/sql-classify.js.map +1 -0
- package/dist/typed-infra.d.ts +73 -0
- package/dist/typed-infra.d.ts.map +1 -0
- package/dist/typed-infra.js +758 -0
- package/dist/typed-infra.js.map +1 -0
- package/dist/typed-ops.d.ts +140 -0
- package/dist/typed-ops.d.ts.map +1 -0
- package/dist/typed-ops.js +549 -0
- package/dist/typed-ops.js.map +1 -0
- package/dist/vectors.d.ts +40 -0
- package/dist/vectors.d.ts.map +1 -0
- package/dist/vectors.js +219 -0
- package/dist/vectors.js.map +1 -0
- package/package.json +4 -4
package/dist/rules.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"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","sourcesContent":["// Rules you can actually read and change.\n//\n// The site says \"set rules in plain terms\" and \"it is a plain JSON file — edit the\n// limits\". What `init` wrote was 6.7 KB of generated regular expression: the `safe-shell`\n// clause alone is a ~700-character case-folded negative lookahead. Nobody edits that, so\n// in practice the starter policy was the *only* policy and \"set your own rules\" was not\n// true.\n//\n// The fix is not to weaken the patterns — they are careful, and the canonicalization\n// tests exist because bypasses are subtle. It is to stop making the pattern the\n// interface. The lists the patterns are built from live in `.scopebond/rules.json`, a\n// short readable file, and `policy.json` is compiled from it. The regex stays as the\n// compiled form.\n//\n// `compile()` reproduces the shipped starter policy's enforcement patterns exactly —\n// `rules.test.mjs` asserts that against `starterPolicy()`, so a change here cannot\n// quietly alter what is enforced.\n\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { ci, under, named, dir, DESTRUCTIVE } from \"./runtime.js\";\n\n/** One protected location. `under`/`named`/`dir` are the readable, editable shapes;\n * `raw` carries the few patterns with bespoke exceptions (`.env` templates are allowed,\n * `.ssh/config` and `*.pub` are allowed) that no simple shape expresses. */\nexport type PathRule =\n | { kind: \"under\"; value: string; label: string }\n | { kind: \"named\"; value: string; label: string }\n | { kind: \"dir\"; value: string; label: string }\n | { kind: \"raw\"; pattern: string; label: string };\n\nexport interface RuleSet {\n version: 1;\n /** Refs an agent may not push to. `release/*` means the prefix `release/`. */\n protected_branches: string[];\n /** Programs an agent may not run, in any case and with or without .exe. */\n destructive_programs: string[];\n protected_write: PathRule[];\n protected_read: PathRule[];\n /** Action types recorded but not blocked. */\n observe: string[];\n}\n\nexport const RULES_FILE = \"rules.json\";\n\nconst pathPattern = (rule: PathRule): string =>\n rule.kind === \"under\" ? under(rule.value)\n : rule.kind === \"named\" ? named(rule.value)\n : rule.kind === \"dir\" ? dir(rule.value)\n : rule.pattern;\n\n/** Escape every regular-expression metacharacter, backslash included.\n *\n * A path the user typed is literal text, and this value goes straight into a rule that\n * decides what the agent may touch: if one metacharacter escapes escaping, the rule\n * silently protects something other than what they asked for. The class is therefore\n * complete on its own rather than relying on an earlier step having removed backslashes\n * (CodeQL js/incomplete-sanitization). */\nconst escapeRegex = (text: string): string => text.replace(/[\\\\^$.*+?()[\\]{}|/]/g, \"\\\\$&\");\n\n/** A protected-path rule from a plain path the user typed. A trailing `/` (or a path with\n * no dot in its last segment) reads as a directory; anything else as a file name.\n *\n * Normalisation is one obvious step at a time. The previous version folded separator\n * conversion and leading-`./` stripping into a single `^[./\\\\]+` replace with a callback,\n * which was both hard to read and quadratic on a path of many leading dots\n * (CodeQL js/polynomial-redos). */\nexport function pathRuleFor(input: string): PathRule {\n const trimmed = input.trim();\n const withForwardSlashes = trimmed.split(\"\\\\\").join(\"/\");\n const withoutDotSlash = withForwardSlashes.startsWith(\"./\") ? withForwardSlashes.slice(2) : withForwardSlashes;\n // Drop trailing separators without a quantifier, so the cost is plainly linear.\n let clean = withoutDotSlash;\n while (clean.endsWith(\"/\")) clean = clean.slice(0, -1);\n // A trailing slash is an explicit directory; so is a last segment with no extension.\n // Checked by string, not by `/\\.[^/]*$/`: that pattern is unanchored at the front, so it\n // retries at every position and goes quadratic on a long path.\n const lastSegment = clean.slice(clean.lastIndexOf(\"/\") + 1);\n const isDirectory = trimmed.endsWith(\"/\") || !lastSegment.includes(\".\");\n return isDirectory\n ? { kind: \"under\", value: escapeRegex(clean), label: `${clean}/ and everything in it` }\n : { kind: \"named\", value: escapeRegex(clean), label: clean };\n}\n\n/** The branch pattern: deny the listed refs, plus the \"every branch at once\" flags and a\n * push whose destination could not be read. `--tags` alone is allowed. */\nfunction branchPattern(branches: string[]): string {\n const exact = branches.filter((b) => !b.endsWith(\"/*\"));\n const prefixes = branches.filter((b) => b.endsWith(\"/*\")).map((b) => b.slice(0, -1));\n const parts = [\n exact.length ? `(?!(?:${exact.map(ci).join(\"|\")})$)` : \"\",\n ...prefixes.map((p) => `(?!${ci(p)})`),\n `(?!-(?!-${ci(\"tags\")}$))`,\n ];\n return `^${parts.join(\"\")}.+`;\n}\n\nconst programPattern = (programs: string[]): string =>\n `^(?!(?:${programs.map(ci).join(\"|\")})(?:${ci(\"\\\\.(?:exe|cmd|bat|com|ps1)\")})?$).+`;\n\nconst pathsPattern = (rules: PathRule[]): string => `^${rules.map(pathPattern).join(\"\")}.+`;\n\n/** A sentence listing what a clause covers, generated from the list rather than written by\n * hand — so it stays true after an edit. The block message quotes this, so a stale\n * description would be a lie told at the worst moment. */\nfunction sentence(items: string[], limit = 12): string {\n const shown = items.slice(0, limit);\n const rest = items.length - shown.length;\n return shown.join(\", \") + (rest > 0 ? `, and ${rest} more` : \"\");\n}\n\n/** Compile a rule set into the policy the gateway evaluates. */\nexport function compile(rules: RuleSet, agentKid: string): Record<string, unknown> {\n return {\n vocabulary_version: \"1.0\", policy_id: \"coding-agent\", version: 1,\n clauses: [\n {\n id: \"protect-branches\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"git.push\"],\n param_bounds: { ref: { pattern: branchPattern(rules.protected_branches) } },\n description: `Deny pushes to ${sentence(rules.protected_branches)} (any case, any refspec spelling), pushes of every branch at once (--all, --mirror) and pushes whose destination cannot be read from the command (a git alias, a configured push refspec, send-pack). A tags-only push (--tags) is allowed. Change these in .scopebond/${RULES_FILE}.`,\n },\n {\n id: \"safe-shell\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"shell.exec\"],\n param_bounds: { program: { pattern: programPattern(rules.destructive_programs) } },\n description: `Deny destructive programs (${sentence(rules.destructive_programs, 10)}) in any case and with or without .exe. An empty program — a command that could not be parsed, or whose program is only known at run time ($VAR, $(…), eval of a variable) — is denied. Argument-shaped deletion (find -delete, git clean) is not a program name and is not covered here. Change this list in .scopebond/${RULES_FILE}.`,\n },\n {\n id: \"protect-write\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"file.write\"],\n param_bounds: { path: { pattern: pathsPattern(rules.protected_write) } },\n description: `Allow workspace writes, but never to ${sentence(rules.protected_write.map((r) => r.label))}. Case-insensitive. Change this list in .scopebond/${RULES_FILE}.`,\n },\n {\n id: \"protect-read\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"file.read\"],\n param_bounds: { path: { pattern: pathsPattern(rules.protected_read) } },\n description: `Allow workspace reads, but never ${sentence(rules.protected_read.map((r) => r.label))}. Case-insensitive. Change this list in .scopebond/${RULES_FILE}.`,\n },\n {\n id: \"observe-net-mcp\", type: \"action_allowlist\", mode: \"monitor\",\n action_types: rules.observe,\n description: `Observe ${sentence(rules.observe)} — recorded, not blocked. Add bounds to enforce. Change this list in .scopebond/${RULES_FILE}.`,\n },\n { id: \"keys\", type: \"key_policy\", active_keys: [agentKid], description: \"Only the enrolled machine key may sign.\" },\n ],\n };\n}\n\n/** The shipped defaults. Every entry here reproduces one piece of the starter policy's\n * patterns; `rules.test.mjs` pins that equivalence. */\nexport function defaultRules(): RuleSet {\n return {\n version: 1,\n protected_branches: [\"main\", \"master\", \"release/*\"],\n destructive_programs: [...DESTRUCTIVE],\n protected_write: [\n { kind: \"under\", value: \"\\\\.scopebond\", label: \"the hook's own policy and keys (.scopebond)\" },\n { kind: \"raw\", pattern: `(?!(?:.*/)?${ci(\"\\\\.claude/settings\")})`, label: \"Claude Code settings\" },\n { kind: \"under\", value: \"\\\\.claude/hooks\", label: \"Claude Code hooks\" },\n { kind: \"under\", value: \"\\\\.claude/agents\", label: \"Claude Code agents\" },\n { kind: \"raw\", pattern: `(?!(?:.*/)?${ci(\"\\\\.cursor/hooks\")})`, label: \"Cursor hook settings\" },\n { kind: \"named\", value: \"\\\\.codex/hooks\\\\.json\", label: \"Codex hook settings\" },\n { kind: \"named\", value: \"\\\\.codex/config\\\\.toml\", label: \"Codex config\" },\n { kind: \"named\", value: \"\\\\.mcp\\\\.json\", label: \".mcp.json\" },\n { kind: \"under\", value: \"\\\\.git/hooks\", label: \"git hooks\" },\n { kind: \"named\", value: \"\\\\.git/config\", label: \"git config\" },\n { kind: \"under\", value: \"\\\\.husky\", label: \"Husky hooks\" },\n { kind: \"under\", value: \"\\\\.github/workflows\", label: \"GitHub workflows\" },\n { kind: \"under\", value: \"\\\\.github/actions\", label: \"GitHub actions\" },\n { kind: \"named\", value: \"\\\\.gitlab-ci\\\\.yml\", label: \".gitlab-ci.yml\" },\n { kind: \"named\", value: \"\\\\.gitlab-ci\\\\.yaml\", label: \".gitlab-ci.yaml\" },\n { kind: \"under\", value: \"\\\\.circleci\", label: \"CircleCI config\" },\n { kind: \"named\", value: \"azure-pipelines\\\\.yml\", label: \"azure-pipelines.yml\" },\n { kind: \"named\", value: \"Jenkinsfile\", label: \"Jenkinsfile\" },\n ],\n protected_read: [\n { kind: \"under\", value: \"\\\\.scopebond\", label: \"the hook's own policy and keys (.scopebond)\" },\n { kind: \"raw\", pattern: `(?!.*${ci(\"\\\\.(?:key|pem|p12|pfx|jks|keystore)\")}$)`, label: \"signing keys and key containers (*.key, *.pem, *.p12, *.pfx, *.jks)\" },\n {\n kind: \"raw\",\n pattern: `(?!(?:.*/)?${ci(\"\\\\.env\")}(?!(?:\\\\.[^/]*)?\\\\.(?:${ci(\"example\")}|${ci(\"sample\")}|${ci(\"template\")}|${ci(\"dist\")})$)(?:\\\\.[^/]*)?$)`,\n label: \"environment secret files (.env, .env.* — except .example/.sample/.template/.dist)\",\n },\n { kind: \"named\", value: \"\\\\.envrc\", label: \".envrc\" },\n {\n kind: \"raw\",\n pattern: `(?!(?:.*/)?${ci(\"\\\\.ssh\")}(?:$|/(?!.*${ci(\"\\\\.pub\")}$)(?!${ci(\"known_hosts\")}$)(?!${ci(\"config\")}$)))`,\n label: \"SSH private keys and the .ssh directory (public keys, known_hosts and config are allowed)\",\n },\n { kind: \"raw\", pattern: `(?!(?:.*/)?${ci(\"\\\\.aws\")}(?:$|/(?!${ci(\"config\")}$)))`, label: \"AWS credentials (.aws, except .aws/config)\" },\n { kind: \"named\", value: \"\\\\.npmrc\", label: \".npmrc\" },\n { kind: \"named\", value: \"\\\\.pypirc\", label: \".pypirc\" },\n { kind: \"named\", value: \"\\\\.netrc\", label: \".netrc\" },\n { kind: \"named\", value: \"_netrc\", label: \"_netrc\" },\n { kind: \"named\", value: \"\\\\.git-credentials\", label: \".git-credentials\" },\n { kind: \"dir\", value: \"\\\\.kube\", label: \"the .kube directory\" },\n { kind: \"named\", value: \"\\\\.kube/config\", label: \".kube/config\" },\n { kind: \"dir\", value: \"\\\\.docker\", label: \"the .docker directory\" },\n { kind: \"named\", value: \"\\\\.docker/config\\\\.json\", label: \".docker/config.json\" },\n { kind: \"under\", value: \"\\\\.config/gcloud\", label: \"gcloud credentials\" },\n { kind: \"under\", value: \"\\\\.azure\", label: \"Azure credentials\" },\n { kind: \"under\", value: \"\\\\.gnupg\", label: \"GnuPG keys\" },\n { kind: \"dir\", value: \"\\\\.config/gh\", label: \"the GitHub CLI config directory\" },\n { kind: \"named\", value: \"\\\\.config/gh/hosts\\\\.yml\", label: \"the GitHub CLI's hosts.yml\" },\n { kind: \"named\", value: \"\\\\.claude/\\\\.credentials\\\\.json\", label: \"Claude Code's .credentials.json\" },\n ],\n observe: [\"net.fetch\", \"mcp.tool.call\"],\n };\n}\n\nexport const rulesPath = (dir: string): string => join(dir, RULES_FILE);\n\nexport function loadRules(configDir: string): RuleSet | null {\n const file = rulesPath(configDir);\n if (!existsSync(file)) return null;\n try {\n const parsed = JSON.parse(readFileSync(file, \"utf8\")) as RuleSet;\n if (parsed?.version !== 1 || !Array.isArray(parsed.protected_branches)) return null;\n return parsed;\n } catch { return null; }\n}\n\nexport function saveRules(configDir: string, rules: RuleSet): string {\n const file = rulesPath(configDir);\n writeFileSync(file, `${JSON.stringify(rules, null, 2)}\\n`);\n return file;\n}\n\n/** Plain English, for `scopebond-hook rules`. */\nexport function describeRules(rules: RuleSet): string {\n const lines: string[] = [];\n lines.push(\"Blocked before it runs:\");\n lines.push(\"\");\n lines.push(` pushes to ${rules.protected_branches.join(\", \")}`);\n lines.push(` and any push whose destination cannot be read`);\n lines.push(` programs ${rules.destructive_programs.join(\", \")}`);\n lines.push(\"\");\n lines.push(` writes to ${rules.protected_write.length} protected location(s):`);\n for (const rule of rules.protected_write) lines.push(` ${rule.label}`);\n lines.push(\"\");\n lines.push(` reads of ${rules.protected_read.length} protected location(s):`);\n for (const rule of rules.protected_read) lines.push(` ${rule.label}`);\n lines.push(\"\");\n lines.push(\"Recorded, not blocked:\");\n lines.push(` ${rules.observe.join(\", \")}`);\n return lines.join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,EAAE;AACF,mFAAmF;AACnF,0FAA0F;AAC1F,yFAAyF;AACzF,wFAAwF;AACxF,QAAQ;AACR,EAAE;AACF,qFAAqF;AACrF,gFAAgF;AAChF,sFAAsF;AACtF,qFAAqF;AACrF,iBAAiB;AACjB,EAAE;AACF,qFAAqF;AACrF,mFAAmF;AACnF,kCAAkC;AAElC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAiClE,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,CAAC;AAEvC,MAAM,WAAW,GAAG,CAAC,IAAc,EAAU,EAAE,CAC7C,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;IACvC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;QAC3C,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;YACvC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AAEnB;;;;;;2CAM2C;AAC3C,MAAM,WAAW,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC;AAE3F;;;;;;oCAMoC;AACpC,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,MAAM,kBAAkB,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzD,MAAM,eAAe,GAAG,kBAAkB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC;IAC/G,gFAAgF;IAChF,IAAI,KAAK,GAAG,eAAe,CAAC;IAC5B,OAAO,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACvD,qFAAqF;IACrF,yFAAyF;IACzF,+DAA+D;IAC/D,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5D,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACxE,OAAO,WAAW;QAChB,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,wBAAwB,EAAE;QACvF,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AACjE,CAAC;AAED;2EAC2E;AAC3E,SAAS,aAAa,CAAC,QAAkB;IACvC,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,KAAK,GAAG;QACZ,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QACzD,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QACtC,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK;KAC3B,CAAC;IACF,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;AAChC,CAAC;AAED,MAAM,cAAc,GAAG,CAAC,QAAkB,EAAU,EAAE,CACpD,UAAU,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,4BAA4B,CAAC,QAAQ,CAAC;AAEtF,MAAM,YAAY,GAAG,CAAC,KAAiB,EAAU,EAAE,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;AAE5F;;2DAE2D;AAC3D,SAAS,QAAQ,CAAC,KAAe,EAAE,KAAK,GAAG,EAAE;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACnE,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,OAAO,CAAC,KAAc,EAAE,QAAgB;IACtD,OAAO;QACL,kBAAkB,EAAE,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC;QAChE,OAAO,EAAE;YACP;gBACE,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,UAAU,CAAC;gBAC7F,YAAY,EAAE,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,EAAE;gBAC3E,WAAW,EAAE,kBAAkB,QAAQ,CAAC,KAAK,CAAC,kBAAkB,CAAC,0QAA0Q,UAAU,GAAG;aACzV;YACD;gBACE,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,YAAY,CAAC;gBACzF,YAAY,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,EAAE;gBAClF,WAAW,EAAE,8BAA8B,QAAQ,CAAC,KAAK,CAAC,oBAAoB,EAAE,EAAE,CAAC,4TAA4T,UAAU,GAAG;aAC7Z;YACD;gBACE,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,YAAY,CAAC;gBAC5F,YAAY,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,EAAE;gBACxE,WAAW,EAAE,wCAAwC,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,sDAAsD,UAAU,GAAG;aAC5K;YACD;gBACE,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,WAAW,CAAC;gBAC1F,YAAY,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,EAAE;gBACvE,WAAW,EAAE,oCAAoC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,sDAAsD,UAAU,GAAG;aACvK;YACD;gBACE,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS;gBAChE,YAAY,EAAE,KAAK,CAAC,OAAO;gBAC3B,WAAW,EAAE,WAAW,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,mFAAmF,UAAU,GAAG;aAChJ;YACD,GAAG,CAAC,KAAK,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;oBACjC,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,YAAY,CAAC;oBAC3F,YAAY,EAAE,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE;oBACrD,WAAW,EAAE,gDAAgD,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,0IAA0I,UAAU,GAAG;iBAClP,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACR,GAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;oBACnC,EAAE,EAAE,yBAAyB,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,SAAS,CAAC;oBACnG,YAAY,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE;oBACjD,WAAW,EAAE,kXAAkX,UAAU,GAAG;iBAC7Y,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACR,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,yCAAyC,EAAE;SACpH;KACF,CAAC;AACJ,CAAC;AAED;wDACwD;AACxD,MAAM,UAAU,YAAY;IAC1B,OAAO;QACL,OAAO,EAAE,CAAC;QACV,kBAAkB,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,CAAC;QACnD,oBAAoB,EAAE,CAAC,GAAG,WAAW,CAAC;QACtC,eAAe,EAAE;YACf,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,6CAA6C,EAAE;YAC9F,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,oBAAoB,CAAC,GAAG,EAAE,KAAK,EAAE,sBAAsB,EAAE;YAClG,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,mBAAmB,EAAE;YACvE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,oBAAoB,EAAE;YACzE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,iBAAiB,CAAC,GAAG,EAAE,KAAK,EAAE,sBAAsB,EAAE;YAC/F,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,uBAAuB,EAAE,KAAK,EAAE,qBAAqB,EAAE;YAC/E,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,wBAAwB,EAAE,KAAK,EAAE,cAAc,EAAE;YACzE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,EAAE;YAC7D,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,WAAW,EAAE;YAC5D,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,YAAY,EAAE;YAC9D,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE;YAC1D,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,sBAAsB,EAAE,KAAK,EAAE,mBAAmB,EAAE;YAC5E,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,uBAAuB,EAAE;YACvE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,qBAAqB,EAAE,KAAK,EAAE,kBAAkB,EAAE;YAC1E,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,gBAAgB,EAAE;YACtE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,gBAAgB,EAAE;YACvE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,qBAAqB,EAAE,KAAK,EAAE,iBAAiB,EAAE;YACzE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,iBAAiB,EAAE;YACjE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,uBAAuB,EAAE,KAAK,EAAE,qBAAqB,EAAE;YAC/E,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE;YAC7D,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,wBAAwB,EAAE,KAAK,EAAE,sBAAsB,EAAE;YACjF,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,2BAA2B,EAAE,KAAK,EAAE,yBAAyB,EAAE;YACvF,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,aAAa,EAAE;YACjE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,YAAY,EAAE;YAC/D,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,iBAAiB,EAAE;YACvE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,gBAAgB,EAAE;YACrE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,qBAAqB,EAAE;SACvE;QACD,cAAc,EAAE;YACd,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,6CAA6C,EAAE;YAC9F,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,qCAAqC,CAAC,IAAI,EAAE,KAAK,EAAE,qEAAqE,EAAE;YAC7J;gBACE,IAAI,EAAE,KAAK;gBACX,OAAO,EAAE,cAAc,EAAE,CAAC,QAAQ,CAAC,yBAAyB,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,oBAAoB;gBAC7I,KAAK,EAAE,mFAAmF;aAC3F;YACD,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE;YACrD;gBACE,IAAI,EAAE,KAAK;gBACX,OAAO,EAAE,cAAc,EAAE,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,MAAM;gBAChH,KAAK,EAAE,2FAA2F;aACnG;YACD,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,4CAA4C,EAAE;YACvI,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE;YACrD,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE;YACvD,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE;YACrD,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;YACnD,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,kBAAkB,EAAE;YACzE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,qBAAqB,EAAE;YAC/D,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,cAAc,EAAE;YACjE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,uBAAuB,EAAE;YACnE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,yBAAyB,EAAE,KAAK,EAAE,qBAAqB,EAAE;YACjF,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,oBAAoB,EAAE;YACzE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,mBAAmB,EAAE;YAChE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE;YACzD,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,iCAAiC,EAAE;YAChF,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,0BAA0B,EAAE,KAAK,EAAE,4BAA4B,EAAE;YACzF,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,iCAAiC,EAAE,KAAK,EAAE,iCAAiC,EAAE;SACtG;QACD,OAAO,EAAE,CAAC,WAAW,EAAE,eAAe,CAAC;KACxC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;AAExE,MAAM,UAAU,SAAS,CAAC,SAAiB;IACzC,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IAClC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAY,CAAC;QACjE,IAAI,MAAM,EAAE,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC;YAAE,OAAO,IAAI,CAAC;QACpF,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,SAAiB,EAAE,KAAc;IACzD,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IAClC,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAC3D,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;+BAG+B;AAC/B,MAAM,UAAU,eAAe,CAAC,IAAc,EAAE,IAAY;IAC1D,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAC9B,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3D,CAAC;AAED;uEACuE;AACvE,MAAM,UAAU,oBAAoB,CAAC,KAAc,EAAE,OAAe;IAClE,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC;IAC7E,OAAO,IAAI,KAAK,EAAE,IAAI,KAAK,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,CAAC;AACzF,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,iBAAiB,CAAC,KAAc,EAAE,GAAW;IAC3D,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAC/B,OAAO,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;QACzC,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAC1B,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IACtC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,wBAAwB,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1E,KAAK,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC;IACjF,KAAK,CAAC,IAAI,CAAC,wBAAwB,KAAK,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,wBAAwB,KAAK,CAAC,eAAe,CAAC,MAAM,yBAAyB,CAAC,CAAC;IAC1F,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,eAAe;QAAE,KAAK,CAAC,IAAI,CAAC,0BAA0B,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC7F,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,wBAAwB,KAAK,CAAC,cAAc,CAAC,MAAM,yBAAyB,CAAC,CAAC;IACzF,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,cAAc;QAAE,KAAK,CAAC,IAAI,CAAC,0BAA0B,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC5F,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,IAAI,KAAK,CAAC,uBAAuB,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,0FAA0F,CAAC,CAAC;QACvG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,IAAI,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,wBAAwB,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAC/G,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACrC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC","sourcesContent":["// Rules you can actually read and change.\n//\n// The site says \"set rules in plain terms\" and \"it is a plain JSON file — edit the\n// limits\". What `init` wrote was 6.7 KB of generated regular expression: the `safe-shell`\n// clause alone is a ~700-character case-folded negative lookahead. Nobody edits that, so\n// in practice the starter policy was the *only* policy and \"set your own rules\" was not\n// true.\n//\n// The fix is not to weaken the patterns — they are careful, and the canonicalization\n// tests exist because bypasses are subtle. It is to stop making the pattern the\n// interface. The lists the patterns are built from live in `.scopebond/rules.json`, a\n// short readable file, and `policy.json` is compiled from it. The regex stays as the\n// compiled form.\n//\n// `compile()` reproduces the shipped starter policy's enforcement patterns exactly —\n// `rules.test.mjs` asserts that against `starterPolicy()`, so a change here cannot\n// quietly alter what is enforced.\n\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { ci, under, named, dir, DESTRUCTIVE } from \"./runtime.js\";\n\n/** One protected location. `under`/`named`/`dir` are the readable, editable shapes;\n * `raw` carries the few patterns with bespoke exceptions (`.env` templates are allowed,\n * `.ssh/config` and `*.pub` are allowed) that no simple shape expresses. */\nexport type PathRule =\n | { kind: \"under\"; value: string; label: string }\n | { kind: \"named\"; value: string; label: string }\n | { kind: \"dir\"; value: string; label: string }\n | { kind: \"raw\"; pattern: string; label: string };\n\nexport interface RuleSet {\n version: 1;\n /** Refs an agent may not push to. `release/*` means the prefix `release/`. */\n protected_branches: string[];\n /** Programs an agent may not run, in any case and with or without .exe. */\n destructive_programs: string[];\n protected_write: PathRule[];\n protected_read: PathRule[];\n /** Action types recorded but not blocked. */\n observe: string[];\n /** Optional workspace scope. When set, a write whose physical target (symlinks and\n * junctions followed, rename and link destinations included) is outside these roots,\n * or cannot be resolved, is denied. `.` means the project directory. Absent = not\n * enforced, which is the default. */\n allowed_roots?: string[];\n /** Optional. When true, a shell command that runs SQL against a remote database (a Wrangler\n * D1 command without --local, or psql to a host other than this machine) is denied before it\n * runs if the SQL drops a table, deletes or updates every row, drops or renames in an ALTER, or\n * cannot be read. Absent = not enforced, which is the default. */\n protect_remote_database?: boolean;\n}\n\nexport const RULES_FILE = \"rules.json\";\n\nconst pathPattern = (rule: PathRule): string =>\n rule.kind === \"under\" ? under(rule.value)\n : rule.kind === \"named\" ? named(rule.value)\n : rule.kind === \"dir\" ? dir(rule.value)\n : rule.pattern;\n\n/** Escape every regular-expression metacharacter, backslash included.\n *\n * A path the user typed is literal text, and this value goes straight into a rule that\n * decides what the agent may touch: if one metacharacter escapes escaping, the rule\n * silently protects something other than what they asked for. The class is therefore\n * complete on its own rather than relying on an earlier step having removed backslashes\n * (CodeQL js/incomplete-sanitization). */\nconst escapeRegex = (text: string): string => text.replace(/[\\\\^$.*+?()[\\]{}|/]/g, \"\\\\$&\");\n\n/** A protected-path rule from a plain path the user typed. A trailing `/` (or a path with\n * no dot in its last segment) reads as a directory; anything else as a file name.\n *\n * Normalisation is one obvious step at a time. The previous version folded separator\n * conversion and leading-`./` stripping into a single `^[./\\\\]+` replace with a callback,\n * which was both hard to read and quadratic on a path of many leading dots\n * (CodeQL js/polynomial-redos). */\nexport function pathRuleFor(input: string): PathRule {\n const trimmed = input.trim();\n const withForwardSlashes = trimmed.split(\"\\\\\").join(\"/\");\n const withoutDotSlash = withForwardSlashes.startsWith(\"./\") ? withForwardSlashes.slice(2) : withForwardSlashes;\n // Drop trailing separators without a quantifier, so the cost is plainly linear.\n let clean = withoutDotSlash;\n while (clean.endsWith(\"/\")) clean = clean.slice(0, -1);\n // A trailing slash is an explicit directory; so is a last segment with no extension.\n // Checked by string, not by `/\\.[^/]*$/`: that pattern is unanchored at the front, so it\n // retries at every position and goes quadratic on a long path.\n const lastSegment = clean.slice(clean.lastIndexOf(\"/\") + 1);\n const isDirectory = trimmed.endsWith(\"/\") || !lastSegment.includes(\".\");\n return isDirectory\n ? { kind: \"under\", value: escapeRegex(clean), label: `${clean}/ and everything in it` }\n : { kind: \"named\", value: escapeRegex(clean), label: clean };\n}\n\n/** The branch pattern: deny the listed refs, plus the \"every branch at once\" flags and a\n * push whose destination could not be read. `--tags` alone is allowed. */\nfunction branchPattern(branches: string[]): string {\n const exact = branches.filter((b) => !b.endsWith(\"/*\"));\n const prefixes = branches.filter((b) => b.endsWith(\"/*\")).map((b) => b.slice(0, -1));\n const parts = [\n exact.length ? `(?!(?:${exact.map(ci).join(\"|\")})$)` : \"\",\n ...prefixes.map((p) => `(?!${ci(p)})`),\n `(?!-(?!-${ci(\"tags\")}$))`,\n ];\n return `^${parts.join(\"\")}.+`;\n}\n\nconst programPattern = (programs: string[]): string =>\n `^(?!(?:${programs.map(ci).join(\"|\")})(?:${ci(\"\\\\.(?:exe|cmd|bat|com|ps1)\")})?$).+`;\n\nconst pathsPattern = (rules: PathRule[]): string => `^${rules.map(pathPattern).join(\"\")}.+`;\n\n/** A sentence listing what a clause covers, generated from the list rather than written by\n * hand — so it stays true after an edit. The block message quotes this, so a stale\n * description would be a lie told at the worst moment. */\nfunction sentence(items: string[], limit = 12): string {\n const shown = items.slice(0, limit);\n const rest = items.length - shown.length;\n return shown.join(\", \") + (rest > 0 ? `, and ${rest} more` : \"\");\n}\n\n/** Compile a rule set into the policy the gateway evaluates. */\nexport function compile(rules: RuleSet, agentKid: string): Record<string, unknown> {\n return {\n vocabulary_version: \"1.0\", policy_id: \"coding-agent\", version: 1,\n clauses: [\n {\n id: \"protect-branches\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"git.push\"],\n param_bounds: { ref: { pattern: branchPattern(rules.protected_branches) } },\n description: `Deny pushes to ${sentence(rules.protected_branches)} (any case, any refspec spelling), pushes of every branch at once (--all, --mirror) and pushes whose destination cannot be read from the command (a git alias, a configured push refspec, send-pack). A tags-only push (--tags) is allowed. Change these in .scopebond/${RULES_FILE}.`,\n },\n {\n id: \"safe-shell\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"shell.exec\"],\n param_bounds: { program: { pattern: programPattern(rules.destructive_programs) } },\n description: `Deny destructive programs (${sentence(rules.destructive_programs, 10)}) in any case and with or without .exe. An empty program — a command that could not be parsed, or whose program is only known at run time ($VAR, $(…), eval of a variable) — is denied. Argument-shaped deletion (find -delete, git clean) is not a program name and is not covered here. Change this list in .scopebond/${RULES_FILE}.`,\n },\n {\n id: \"protect-write\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"file.write\"],\n param_bounds: { path: { pattern: pathsPattern(rules.protected_write) } },\n description: `Allow workspace writes, but never to ${sentence(rules.protected_write.map((r) => r.label))}. Case-insensitive. Change this list in .scopebond/${RULES_FILE}.`,\n },\n {\n id: \"protect-read\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"file.read\"],\n param_bounds: { path: { pattern: pathsPattern(rules.protected_read) } },\n description: `Allow workspace reads, but never ${sentence(rules.protected_read.map((r) => r.label))}. Case-insensitive. Change this list in .scopebond/${RULES_FILE}.`,\n },\n {\n id: \"observe-net-mcp\", type: \"action_allowlist\", mode: \"monitor\",\n action_types: rules.observe,\n description: `Observe ${sentence(rules.observe)} — recorded, not blocked. Add bounds to enforce. Change this list in .scopebond/${RULES_FILE}.`,\n },\n ...(rules.allowed_roots?.length ? [{\n id: \"protect-root\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"file.write\"],\n param_bounds: { root_scope: { pattern: \"^inside$\" } },\n description: `Deny writes whose physical target is outside ${sentence(rules.allowed_roots)} — symlinks, junctions, rename and link destinations followed — and writes whose target cannot be resolved. Change these in .scopebond/${RULES_FILE}.`,\n }] : []),\n ...(rules.protect_remote_database ? [{\n id: \"protect-remote-database\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"db.exec\"],\n param_bounds: { risk: { pattern: \"^ordinary$\" } },\n description: `Deny shell commands that run SQL against a remote database (a wrangler d1 command without --local, or psql to a host other than this machine) when the SQL drops a table, deletes or updates every row, drops or renames inside an ALTER, or cannot be read. The hook cannot tell which database is production, so every remote database is covered. Change this in .scopebond/${RULES_FILE}.`,\n }] : []),\n { id: \"keys\", type: \"key_policy\", active_keys: [agentKid], description: \"Only the enrolled machine key may sign.\" },\n ],\n };\n}\n\n/** The shipped defaults. Every entry here reproduces one piece of the starter policy's\n * patterns; `rules.test.mjs` pins that equivalence. */\nexport function defaultRules(): RuleSet {\n return {\n version: 1,\n protected_branches: [\"main\", \"master\", \"release/*\"],\n destructive_programs: [...DESTRUCTIVE],\n protected_write: [\n { kind: \"under\", value: \"\\\\.scopebond\", label: \"the hook's own policy and keys (.scopebond)\" },\n { kind: \"raw\", pattern: `(?!(?:.*/)?${ci(\"\\\\.claude/settings\")})`, label: \"Claude Code settings\" },\n { kind: \"under\", value: \"\\\\.claude/hooks\", label: \"Claude Code hooks\" },\n { kind: \"under\", value: \"\\\\.claude/agents\", label: \"Claude Code agents\" },\n { kind: \"raw\", pattern: `(?!(?:.*/)?${ci(\"\\\\.cursor/hooks\")})`, label: \"Cursor hook settings\" },\n { kind: \"named\", value: \"\\\\.codex/hooks\\\\.json\", label: \"Codex hook settings\" },\n { kind: \"named\", value: \"\\\\.codex/config\\\\.toml\", label: \"Codex config\" },\n { kind: \"named\", value: \"\\\\.mcp\\\\.json\", label: \".mcp.json\" },\n { kind: \"under\", value: \"\\\\.git/hooks\", label: \"git hooks\" },\n { kind: \"named\", value: \"\\\\.git/config\", label: \"git config\" },\n { kind: \"under\", value: \"\\\\.husky\", label: \"Husky hooks\" },\n { kind: \"named\", value: \"\\\\.cursor/mcp\\\\.json\", label: \"Cursor MCP config\" },\n { kind: \"under\", value: \"\\\\.githooks\", label: \"git hooks (.githooks)\" },\n { kind: \"under\", value: \"\\\\.github/workflows\", label: \"GitHub workflows\" },\n { kind: \"under\", value: \"\\\\.github/actions\", label: \"GitHub actions\" },\n { kind: \"named\", value: \"\\\\.gitlab-ci\\\\.yml\", label: \".gitlab-ci.yml\" },\n { kind: \"named\", value: \"\\\\.gitlab-ci\\\\.yaml\", label: \".gitlab-ci.yaml\" },\n { kind: \"under\", value: \"\\\\.circleci\", label: \"CircleCI config\" },\n { kind: \"named\", value: \"azure-pipelines\\\\.yml\", label: \"azure-pipelines.yml\" },\n { kind: \"named\", value: \"Jenkinsfile\", label: \"Jenkinsfile\" },\n { kind: \"named\", value: \"azure-pipelines\\\\.yaml\", label: \"azure-pipelines.yaml\" },\n { kind: \"named\", value: \"bitbucket-pipelines\\\\.yml\", label: \"bitbucket-pipelines.yml\" },\n { kind: \"named\", value: \"\\\\.travis\\\\.yml\", label: \".travis.yml\" },\n { kind: \"named\", value: \"\\\\.drone\\\\.yml\", label: \".drone.yml\" },\n { kind: \"named\", value: \"cloudbuild\\\\.yaml\", label: \"cloudbuild.yaml\" },\n { kind: \"named\", value: \"cloudbuild\\\\.yml\", label: \"cloudbuild.yml\" },\n { kind: \"under\", value: \"\\\\.buildkite\", label: \"Buildkite pipelines\" },\n ],\n protected_read: [\n { kind: \"under\", value: \"\\\\.scopebond\", label: \"the hook's own policy and keys (.scopebond)\" },\n { kind: \"raw\", pattern: `(?!.*${ci(\"\\\\.(?:key|pem|p12|pfx|jks|keystore)\")}$)`, label: \"signing keys and key containers (*.key, *.pem, *.p12, *.pfx, *.jks)\" },\n {\n kind: \"raw\",\n pattern: `(?!(?:.*/)?${ci(\"\\\\.env\")}(?!(?:\\\\.[^/]*)?\\\\.(?:${ci(\"example\")}|${ci(\"sample\")}|${ci(\"template\")}|${ci(\"dist\")})$)(?:\\\\.[^/]*)?$)`,\n label: \"environment secret files (.env, .env.* — except .example/.sample/.template/.dist)\",\n },\n { kind: \"named\", value: \"\\\\.envrc\", label: \".envrc\" },\n {\n kind: \"raw\",\n pattern: `(?!(?:.*/)?${ci(\"\\\\.ssh\")}(?:$|/(?!.*${ci(\"\\\\.pub\")}$)(?!${ci(\"known_hosts\")}$)(?!${ci(\"config\")}$)))`,\n label: \"SSH private keys and the .ssh directory (public keys, known_hosts and config are allowed)\",\n },\n { kind: \"raw\", pattern: `(?!(?:.*/)?${ci(\"\\\\.aws\")}(?:$|/(?!${ci(\"config\")}$)))`, label: \"AWS credentials (.aws, except .aws/config)\" },\n { kind: \"named\", value: \"\\\\.npmrc\", label: \".npmrc\" },\n { kind: \"named\", value: \"\\\\.pypirc\", label: \".pypirc\" },\n { kind: \"named\", value: \"\\\\.netrc\", label: \".netrc\" },\n { kind: \"named\", value: \"_netrc\", label: \"_netrc\" },\n { kind: \"named\", value: \"\\\\.git-credentials\", label: \".git-credentials\" },\n { kind: \"dir\", value: \"\\\\.kube\", label: \"the .kube directory\" },\n { kind: \"named\", value: \"\\\\.kube/config\", label: \".kube/config\" },\n { kind: \"dir\", value: \"\\\\.docker\", label: \"the .docker directory\" },\n { kind: \"named\", value: \"\\\\.docker/config\\\\.json\", label: \".docker/config.json\" },\n { kind: \"under\", value: \"\\\\.config/gcloud\", label: \"gcloud credentials\" },\n { kind: \"under\", value: \"\\\\.azure\", label: \"Azure credentials\" },\n { kind: \"under\", value: \"\\\\.gnupg\", label: \"GnuPG keys\" },\n { kind: \"dir\", value: \"\\\\.config/gh\", label: \"the GitHub CLI config directory\" },\n { kind: \"named\", value: \"\\\\.config/gh/hosts\\\\.yml\", label: \"the GitHub CLI's hosts.yml\" },\n { kind: \"named\", value: \"\\\\.claude/\\\\.credentials\\\\.json\", label: \"Claude Code's .credentials.json\" },\n ],\n observe: [\"net.fetch\", \"mcp.tool.call\"],\n };\n}\n\nexport const rulesPath = (dir: string): string => join(dir, RULES_FILE);\n\nexport function loadRules(configDir: string): RuleSet | null {\n const file = rulesPath(configDir);\n if (!existsSync(file)) return null;\n try {\n const parsed = JSON.parse(readFileSync(file, \"utf8\")) as RuleSet;\n if (parsed?.version !== 1 || !Array.isArray(parsed.protected_branches)) return null;\n return parsed;\n } catch { return null; }\n}\n\nexport function saveRules(configDir: string, rules: RuleSet): string {\n const file = rulesPath(configDir);\n writeFileSync(file, `${JSON.stringify(rules, null, 2)}\\n`);\n return file;\n}\n\n/** Whether `path` is inside the location a protected-path rule names. This is the same\n * pattern the compiled policy evaluates (the rule allows a path when the pattern's\n * negative lookahead matches), tested rule by rule so a classification can say which\n * kind of location it was. */\nexport function pathRuleMatches(rule: PathRule, path: string): boolean {\n if (path === \"\") return false;\n return !new RegExp(`^${pathPattern(rule)}.+`).test(path);\n}\n\n/** Whether a shell program is on the destructive list, folded the way the compiled\n * policy folds it: case-insensitive, without an executable suffix. */\nexport function isDestructiveProgram(rules: RuleSet, program: string): boolean {\n const name = program.toLowerCase().replace(/\\.(?:exe|cmd|bat|com|ps1)$/, \"\");\n return name !== \"\" && rules.destructive_programs.some((p) => p.toLowerCase() === name);\n}\n\n/** Whether a push destination is one of the protected refs (`release/*` is a prefix). */\nexport function isProtectedBranch(rules: RuleSet, ref: string): boolean {\n const name = ref.toLowerCase();\n return rules.protected_branches.some((b) => {\n const p = b.toLowerCase();\n return p.endsWith(\"/*\") ? name.startsWith(p.slice(0, -1)) : name === p;\n });\n}\n\n/** Plain English, for `scopebond-hook rules`. */\nexport function describeRules(rules: RuleSet): string {\n const lines: string[] = [];\n lines.push(\"Blocked before it runs:\");\n lines.push(\"\");\n lines.push(` pushes to ${rules.protected_branches.join(\", \")}`);\n lines.push(` and any push whose destination cannot be read`);\n lines.push(` programs ${rules.destructive_programs.join(\", \")}`);\n lines.push(\"\");\n lines.push(` writes to ${rules.protected_write.length} protected location(s):`);\n for (const rule of rules.protected_write) lines.push(` ${rule.label}`);\n lines.push(\"\");\n lines.push(` reads of ${rules.protected_read.length} protected location(s):`);\n for (const rule of rules.protected_read) lines.push(` ${rule.label}`);\n lines.push(\"\");\n if (rules.protect_remote_database) {\n lines.push(` remote SQL that drops a table, deletes or updates every row, or cannot be read`);\n lines.push(\"\");\n }\n if (rules.allowed_roots?.length) {\n lines.push(` writes outside ${rules.allowed_roots.join(\", \")} (physical target; unresolved targets too)`);\n lines.push(\"\");\n }\n lines.push(\"Recorded, not blocked:\");\n lines.push(` ${rules.observe.join(\", \")}`);\n return lines.join(\"\\n\");\n}\n"]}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type CloudExporter } from "@scopebond/gateway";
|
|
2
2
|
import type { Mapped } from "./map.js";
|
|
3
3
|
import { type HookConnection } from "./cloud.js";
|
|
4
|
+
import { type DispatchDecision } from "@scopebond/gateway";
|
|
4
5
|
export interface RuntimeConfig {
|
|
5
6
|
policyPath: string;
|
|
6
7
|
keyPath: string;
|
|
@@ -10,6 +11,9 @@ export interface RuntimeConfig {
|
|
|
10
11
|
* allowlist) instead of observed. Fail-closed for tools with no taxonomy
|
|
11
12
|
* mapping; default false (observe, matching the connector conformance vector). */
|
|
12
13
|
strict?: boolean;
|
|
14
|
+
/** The working directory the harness reported, used to resolve workspace roots when
|
|
15
|
+
* the rule set lists `allowed_roots`. Defaults to the process directory. */
|
|
16
|
+
cwd?: string;
|
|
13
17
|
/** When connected to a Cloud workspace, receipts are auto-exported to the portal.
|
|
14
18
|
* Export is best-effort and never changes the local decision. */
|
|
15
19
|
cloud?: {
|
|
@@ -27,6 +31,17 @@ export interface Decision {
|
|
|
27
31
|
receipt?: unknown;
|
|
28
32
|
/** Every receipt produced — one per simple command in a decomposed shell call. */
|
|
29
33
|
receipts?: unknown[];
|
|
34
|
+
/** Each action as actually evaluated (after root scoping and grouping), with its
|
|
35
|
+
* receipt: what the observation emitters bind a request digest to. */
|
|
36
|
+
/** What the dispatch boundary spent or refused for this call, when one is configured. */
|
|
37
|
+
dispatch?: DispatchDecision;
|
|
38
|
+
dispatched?: Array<{
|
|
39
|
+
action: {
|
|
40
|
+
action_type: string;
|
|
41
|
+
params: Record<string, unknown>;
|
|
42
|
+
};
|
|
43
|
+
receipt?: unknown;
|
|
44
|
+
}>;
|
|
30
45
|
}
|
|
31
46
|
export declare const ci: (s: string) => string;
|
|
32
47
|
export declare const under: (dir: string) => string;
|
|
@@ -61,6 +76,8 @@ export declare function createHookRuntime(config: RuntimeConfig): {
|
|
|
61
76
|
evaluateOne(mapped: Mapped): Promise<Decision>;
|
|
62
77
|
/** Decide a whole tool call. A shell call decomposes into several simple
|
|
63
78
|
* commands; every one is recorded, and a single deny denies the call. */
|
|
64
|
-
evaluate(mapped: Mapped | Mapped[]
|
|
79
|
+
evaluate(mapped: Mapped | Mapped[], options?: {
|
|
80
|
+
groupKey?: string;
|
|
81
|
+
}): Promise<Decision>;
|
|
65
82
|
};
|
|
66
83
|
//# sourceMappingURL=runtime.d.ts.map
|
package/dist/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAOA,OAAO,EAA6C,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAgC,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAOA,OAAO,EAA6C,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAgC,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAO/E,OAAO,EAAoB,KAAK,gBAAgB,EAAsB,MAAM,oBAAoB,CAAC;AAEjG,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf;;uFAEmF;IACnF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;iFAC6E;IAC7E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;sEACkE;IAClE,KAAK,CAAC,EAAE;QAAE,UAAU,EAAE,cAAc,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACvF;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,eAAe,CAAC;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,iEAAiE;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB;2EACuE;IACvE,yFAAyF;IACzF,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE;YAAE,WAAW,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;SAAE,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC7G;AAWD,eAAO,MAAM,EAAE,GAAI,GAAG,MAAM,KAAG,MAAiF,CAAC;AACjH,eAAO,MAAM,KAAK,GAAI,KAAK,MAAM,KAAG,MAAyC,CAAC;AAC9E,eAAO,MAAM,KAAK,GAAI,MAAM,MAAM,KAAG,MAAoC,CAAC;AAC1E,eAAO,MAAM,GAAG,GAAI,GAAG,MAAM,KAAG,MAAmC,CAAC;AA0CpE,eAAO,MAAM,WAAW,UAGvB,CAAC;AAwBF;;uFAEuF;AACvF,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAQpD;AAED;;;0BAG0B;AAC1B,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgCvE;AAED;4EAC4E;AAC5E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa;;;;IAoCnD;qFACiF;aAClE,OAAO,CAAC,IAAI,CAAC;IAG5B;;;;2DAIuD;aAC9C,IAAI;IAKb,gEAAgE;wBACtC,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IA+BpD;8EAC0E;qBACnD,MAAM,GAAG,MAAM,EAAE,YAAW;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAQ,OAAO,CAAC,QAAQ,CAAC;EAiDpG"}
|
package/dist/runtime.js
CHANGED
|
@@ -9,8 +9,12 @@ import { loadOrCreateAttester, openReceiptStore } from "@scopebond/gateway/node"
|
|
|
9
9
|
import { createSigner } from "@scopebond/sdk";
|
|
10
10
|
import { attachExporter, flushBounded } from "./cloud.js";
|
|
11
11
|
import { explainDeny } from "./explain.js";
|
|
12
|
-
import { RULES_FILE } from "./rules.js";
|
|
12
|
+
import { RULES_FILE, loadRules } from "./rules.js";
|
|
13
|
+
import { applyRootScope } from "./paths.js";
|
|
14
|
+
import { withActionGroup, actionGroupId, ACTION_GROUP_PARAM } from "./group.js";
|
|
13
15
|
import { cliCommand } from "./version.js";
|
|
16
|
+
import { openDispatchGuard, DELEGATION_ENV } from "@scopebond/gateway/node";
|
|
17
|
+
import { dispatchIntentOf } from "@scopebond/gateway";
|
|
14
18
|
// The hook's own config and keys must be off-limits to the agent it governs:
|
|
15
19
|
// otherwise the agent could rewrite its policy or read the signing keys and the
|
|
16
20
|
// receipts stop meaning anything. These patterns are "allow if the path does NOT
|
|
@@ -24,13 +28,27 @@ export const ci = (s) => s.replace(/[A-Za-z]/g, (c) => `[${c.toLowerCase()}${c.t
|
|
|
24
28
|
export const under = (dir) => `(?!(?:.*/)?${ci(dir)}(?:/|$))`; // dir itself or anything inside it
|
|
25
29
|
export const named = (file) => `(?!(?:.*/)?${ci(file)}$)`; // exactly this file name
|
|
26
30
|
export const dir = (d) => `(?!(?:.*/)?${ci(d)}/?$)`; // the directory itself (a recursive read or copy)
|
|
27
|
-
|
|
31
|
+
// The protected-write set, in two typed groups the catalog classifies separately:
|
|
32
|
+
// guardrail/hook configuration (C02) and CI configuration (H03).
|
|
33
|
+
const GUARDRAIL_WRITE_PREV = [
|
|
28
34
|
under("\\.scopebond"), `(?!(?:.*/)?${ci("\\.claude/settings")})`, under("\\.claude/hooks"), under("\\.claude/agents"),
|
|
29
35
|
`(?!(?:.*/)?${ci("\\.cursor/hooks")})`, named("\\.codex/hooks\\.json"), named("\\.codex/config\\.toml"), named("\\.mcp\\.json"),
|
|
30
36
|
under("\\.git/hooks"), named("\\.git/config"), under("\\.husky"),
|
|
37
|
+
];
|
|
38
|
+
const CI_WRITE_PREV = [
|
|
31
39
|
under("\\.github/workflows"), under("\\.github/actions"), named("\\.gitlab-ci\\.yml"), named("\\.gitlab-ci\\.yaml"), under("\\.circleci"),
|
|
32
40
|
named("azure-pipelines\\.yml"), named("Jenkinsfile"),
|
|
33
|
-
]
|
|
41
|
+
];
|
|
42
|
+
const GUARDRAIL_WRITE = [...GUARDRAIL_WRITE_PREV, named("\\.cursor/mcp\\.json"), under("\\.githooks")];
|
|
43
|
+
const CI_WRITE = [
|
|
44
|
+
...CI_WRITE_PREV,
|
|
45
|
+
named("azure-pipelines\\.yaml"), named("bitbucket-pipelines\\.yml"), named("\\.travis\\.yml"), named("\\.drone\\.yml"),
|
|
46
|
+
named("cloudbuild\\.yaml"), named("cloudbuild\\.yml"), under("\\.buildkite"),
|
|
47
|
+
];
|
|
48
|
+
// What 0.8 compiled, kept so an installed policy that still carries it verbatim is
|
|
49
|
+
// upgraded in memory (see LEGACY_STARTER_PATTERNS).
|
|
50
|
+
const PROTECTED_WRITE_PREV = "^" + [...GUARDRAIL_WRITE_PREV, ...CI_WRITE_PREV].join("") + ".+";
|
|
51
|
+
const PROTECTED_WRITE = "^" + [...GUARDRAIL_WRITE, ...CI_WRITE].join("") + ".+";
|
|
34
52
|
const PROTECTED_READ = "^" + [
|
|
35
53
|
under("\\.scopebond"),
|
|
36
54
|
`(?!.*${ci("\\.(?:key|pem|p12|pfx|jks|keystore)")}$)`,
|
|
@@ -62,6 +80,7 @@ const SAFE_REF = `^(?!(?:${ci("main")}|${ci("master")})$)(?!${ci("release")}/)(?
|
|
|
62
80
|
// policy on disk still carries them verbatim. An operator's own edits never match
|
|
63
81
|
// these strings and are left untouched.
|
|
64
82
|
const LEGACY_STARTER_PATTERNS = {
|
|
83
|
+
[PROTECTED_WRITE_PREV]: PROTECTED_WRITE,
|
|
65
84
|
"^(?!(?:main|master)$)(?!release/).+": SAFE_REF,
|
|
66
85
|
"^(?!(?:rm|sudo|shutdown|reboot|mkfs|dd|del|rd|rmdir|erase|deltree|format|Remove-Item|ri)$).+": SAFE_SHELL,
|
|
67
86
|
"^(?!(?:rm|sudo|shutdown|reboot|mkfs|dd)$).+": SAFE_SHELL,
|
|
@@ -105,7 +124,7 @@ export function starterPolicy(agentKid) {
|
|
|
105
124
|
{
|
|
106
125
|
id: "protect-write", type: "action_allowlist", mode: "enforce", action_types: ["file.write"],
|
|
107
126
|
param_bounds: { path: { pattern: PROTECTED_WRITE } },
|
|
108
|
-
description: "Allow workspace writes, but never to the hook's policy/keys, Claude Code settings, hooks and agents, Cursor or Codex hook settings, .mcp.json, git hooks and git config, Husky hooks, or CI config (.github/workflows, .github/actions, .gitlab-ci.yml/.yaml, .circleci, azure-pipelines.yml, Jenkinsfile). Case-insensitive.",
|
|
127
|
+
description: "Allow workspace writes, but never to the hook's policy/keys, Claude Code settings, hooks and agents, Cursor or Codex hook settings, .mcp.json and .cursor/mcp.json, git hooks (.git/hooks, .githooks) and git config, Husky hooks, or CI config (.github/workflows, .github/actions, .gitlab-ci.yml/.yaml, .circleci, azure-pipelines, bitbucket-pipelines.yml, .travis.yml, .drone.yml, cloudbuild, .buildkite, Jenkinsfile). Case-insensitive.",
|
|
109
128
|
},
|
|
110
129
|
{
|
|
111
130
|
id: "protect-read", type: "action_allowlist", mode: "enforce", action_types: ["file.read"],
|
|
@@ -147,7 +166,13 @@ export function createHookRuntime(config) {
|
|
|
147
166
|
exporter = attached.exporter;
|
|
148
167
|
outbox = attached.outbox;
|
|
149
168
|
}
|
|
150
|
-
const
|
|
169
|
+
const scopeRoots = loadRules(dirname(config.policyPath))?.allowed_roots ?? [];
|
|
170
|
+
// The dispatch boundary is checked once per tool call, after every intent has been allowed, so the
|
|
171
|
+
// gateway's own per-intent hook only reports what the runtime already decided for this call.
|
|
172
|
+
const boundary = openDispatchGuard(dirname(config.policyPath));
|
|
173
|
+
let boundaryVerdict = null;
|
|
174
|
+
const gatewayGuard = { authorize: async () => boundaryVerdict ?? { allow: true, reason: "ok", consumed_approvals: [], budgets: [] } };
|
|
175
|
+
const gateway = createGateway({ policy, authentication: { keys }, attester, store, mode: "check_only", dispatchGuard: gatewayGuard });
|
|
151
176
|
return {
|
|
152
177
|
gateway,
|
|
153
178
|
agentKid: agent.kid,
|
|
@@ -172,6 +197,10 @@ export function createHookRuntime(config) {
|
|
|
172
197
|
outbox?.close();
|
|
173
198
|
}
|
|
174
199
|
catch { /* best effort */ }
|
|
200
|
+
try {
|
|
201
|
+
boundary?.close();
|
|
202
|
+
}
|
|
203
|
+
catch { /* best effort */ }
|
|
175
204
|
},
|
|
176
205
|
/** Decide one mapped action, recording a receipt either way. */
|
|
177
206
|
async evaluateOne(mapped) {
|
|
@@ -208,19 +237,27 @@ export function createHookRuntime(config) {
|
|
|
208
237
|
},
|
|
209
238
|
/** Decide a whole tool call. A shell call decomposes into several simple
|
|
210
239
|
* commands; every one is recorded, and a single deny denies the call. */
|
|
211
|
-
async evaluate(mapped) {
|
|
212
|
-
const
|
|
213
|
-
if (
|
|
240
|
+
async evaluate(mapped, options = {}) {
|
|
241
|
+
const raw = Array.isArray(mapped) ? mapped : [mapped];
|
|
242
|
+
if (raw.length === 0)
|
|
214
243
|
return { decision: "not_evaluated", reason: "no action", receipts: [] };
|
|
244
|
+
// Every intent of one tool call carries one parent group id, so the receipts of a
|
|
245
|
+
// decomposed call (a command, its file reads and writes, a rename destination)
|
|
246
|
+
// link to each other and count once as an action. It is part of the signed
|
|
247
|
+
// intent, so it is authenticated by the same signature as the rest.
|
|
248
|
+
const scoped = scopeRoots.length ? applyRootScope(raw, { cwd: config.cwd ?? process.cwd(), roots: scopeRoots }) : raw;
|
|
249
|
+
const list = withActionGroup(scoped, actionGroupId(options.groupKey));
|
|
215
250
|
const receipts = [];
|
|
251
|
+
const dispatched = [];
|
|
216
252
|
let allow = null;
|
|
217
253
|
let notEvaluated = null;
|
|
218
254
|
for (const m of list) {
|
|
219
255
|
const d = await this.evaluateOne(m);
|
|
220
256
|
if (d.receipt !== undefined)
|
|
221
257
|
receipts.push(d.receipt);
|
|
258
|
+
dispatched.push({ action: { action_type: m.intent.action_type, params: m.intent.params }, ...(d.receipt !== undefined ? { receipt: d.receipt } : {}) });
|
|
222
259
|
if (d.decision === "deny")
|
|
223
|
-
return { ...d, receipts }; // any deny denies the call
|
|
260
|
+
return { ...d, receipts, dispatched }; // any deny denies the call
|
|
224
261
|
if (d.decision === "allow" && !allow)
|
|
225
262
|
allow = d;
|
|
226
263
|
if (d.decision === "not_evaluated" && !notEvaluated)
|
|
@@ -228,7 +265,34 @@ export function createHookRuntime(config) {
|
|
|
228
265
|
}
|
|
229
266
|
// No deny: allow if any command was evaluated-and-allowed, else not_evaluated.
|
|
230
267
|
const chosen = allow ?? notEvaluated;
|
|
231
|
-
|
|
268
|
+
if (boundary) {
|
|
269
|
+
// Immediately before permitted dispatch: approvals are consumed and the budget slot is reserved
|
|
270
|
+
// atomically, once for the whole parent action, or nothing is spent and the call is denied.
|
|
271
|
+
const group = String(list[0].intent.params[ACTION_GROUP_PARAM]);
|
|
272
|
+
const delegation = process.env[DELEGATION_ENV] ?? "";
|
|
273
|
+
const verdict = await boundary.authorize({
|
|
274
|
+
actor: agent.kid, action_group: group, policy_digest: gateway.policyHash,
|
|
275
|
+
intents: list.map((m) => dispatchIntentOf(m.intent)),
|
|
276
|
+
...(delegation !== "" ? { delegation_id: delegation } : {}),
|
|
277
|
+
});
|
|
278
|
+
if (!verdict.allow) {
|
|
279
|
+
// Record the refusal as its own denied receipt, then deny the call.
|
|
280
|
+
boundaryVerdict = verdict;
|
|
281
|
+
try {
|
|
282
|
+
const last = list[list.length - 1];
|
|
283
|
+
const signed = agent.sign(last.intent);
|
|
284
|
+
const result = await gateway.handleAction({ intent: signed.intent, authorization: signed.authorization });
|
|
285
|
+
if (result.receipt !== undefined)
|
|
286
|
+
receipts.push(result.receipt);
|
|
287
|
+
}
|
|
288
|
+
finally {
|
|
289
|
+
boundaryVerdict = null;
|
|
290
|
+
}
|
|
291
|
+
return { decision: "deny", reason: `Scopebond blocked this before it ran: ${verdict.reason}${verdict.detail ? ` (${verdict.detail})` : ""}`, receipts, dispatched, dispatch: verdict };
|
|
292
|
+
}
|
|
293
|
+
return { ...chosen, receipts, dispatched, dispatch: verdict };
|
|
294
|
+
}
|
|
295
|
+
return { ...chosen, receipts, dispatched };
|
|
232
296
|
},
|
|
233
297
|
};
|
|
234
298
|
}
|
package/dist/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["// The hook runtime: a check-only (M0) gateway built once from the enrolled\n// machine key, policy and a durable local receipt log. Each mapped action is\n// signed by the machine key, decided against policy and countersigned — locally,\n// with no HTTP server and no Cloud dependency in 0.1.\n\nimport { readFileSync, existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { createGateway, StaticPrincipalKeyRegistry, type CloudExporter } from \"@scopebond/gateway\";\nimport { loadOrCreateAttester, openReceiptStore } from \"@scopebond/gateway/node\";\nimport { createSigner } from \"@scopebond/sdk\";\nimport type { Mapped } from \"./map.js\";\nimport { attachExporter, flushBounded, type HookConnection } from \"./cloud.js\";\nimport { explainDeny, type ExplainIntent } from \"./explain.js\";\nimport { RULES_FILE } from \"./rules.js\";\nimport { cliCommand } from \"./version.js\";\n\nexport interface RuntimeConfig {\n policyPath: string;\n keyPath: string;\n attesterPath: string;\n dbPath: string;\n /** Strict mode: an unmapped tool is policy-checked (and denied by a closed\n * allowlist) instead of observed. Fail-closed for tools with no taxonomy\n * mapping; default false (observe, matching the connector conformance vector). */\n strict?: boolean;\n /** When connected to a Cloud workspace, receipts are auto-exported to the portal.\n * Export is best-effort and never changes the local decision. */\n cloud?: { connection: HookConnection; fetch?: typeof fetch; flushTimeoutMs?: number };\n}\n\nexport interface Decision {\n decision: \"allow\" | \"deny\" | \"not_evaluated\";\n reason: string;\n /** The clause that decided a deny, when the verdict named one. */\n clauseId?: string | null;\n /** The deciding receipt (the denied one, or the first allow). */\n receipt?: unknown;\n /** Every receipt produced — one per simple command in a decomposed shell call. */\n receipts?: unknown[];\n}\n\n// The hook's own config and keys must be off-limits to the agent it governs:\n// otherwise the agent could rewrite its policy or read the signing keys and the\n// receipts stop meaning anything. These patterns are \"allow if the path does NOT\n// match a protected location\"; they run against the cwd-relative path the mapper\n// produces (and equally against an absolute one).\n//\n// Matching is case-insensitive — Windows and macOS open `.ENV` and `.env` as the\n// same file — by expanding each letter to a two-case class (policy patterns are\n// plain regular expressions with no flags). `ci()` is applied to literal text only.\nexport const ci = (s: string): string => s.replace(/[A-Za-z]/g, (c) => `[${c.toLowerCase()}${c.toUpperCase()}]`);\nexport const under = (dir: string): string => `(?!(?:.*/)?${ci(dir)}(?:/|$))`; // dir itself or anything inside it\nexport const named = (file: string): string => `(?!(?:.*/)?${ci(file)}$)`; // exactly this file name\nexport const dir = (d: string): string => `(?!(?:.*/)?${ci(d)}/?$)`; // the directory itself (a recursive read or copy)\n\nconst PROTECTED_WRITE = \"^\" + [\n under(\"\\\\.scopebond\"), `(?!(?:.*/)?${ci(\"\\\\.claude/settings\")})`, under(\"\\\\.claude/hooks\"), under(\"\\\\.claude/agents\"),\n `(?!(?:.*/)?${ci(\"\\\\.cursor/hooks\")})`, named(\"\\\\.codex/hooks\\\\.json\"), named(\"\\\\.codex/config\\\\.toml\"), named(\"\\\\.mcp\\\\.json\"),\n under(\"\\\\.git/hooks\"), named(\"\\\\.git/config\"), under(\"\\\\.husky\"),\n under(\"\\\\.github/workflows\"), under(\"\\\\.github/actions\"), named(\"\\\\.gitlab-ci\\\\.yml\"), named(\"\\\\.gitlab-ci\\\\.yaml\"), under(\"\\\\.circleci\"),\n named(\"azure-pipelines\\\\.yml\"), named(\"Jenkinsfile\"),\n].join(\"\") + \".+\";\n\nconst PROTECTED_READ = \"^\" + [\n under(\"\\\\.scopebond\"),\n `(?!.*${ci(\"\\\\.(?:key|pem|p12|pfx|jks|keystore)\")}$)`,\n // .env, .env.* — except templates whose name ends in .example/.sample/.template/.dist\n `(?!(?:.*/)?${ci(\"\\\\.env\")}(?!(?:\\\\.[^/]*)?\\\\.(?:${ci(\"example\")}|${ci(\"sample\")}|${ci(\"template\")}|${ci(\"dist\")})$)(?:\\\\.[^/]*)?$)`,\n named(\"\\\\.envrc\"),\n // Credentials outside the workspace that an agent can reach by absolute or ~ path,\n // and their directories as a whole (`cp -r ~/.ssh`, `grep -r x ~/.aws`).\n `(?!(?:.*/)?${ci(\"\\\\.ssh\")}(?:$|/(?!.*${ci(\"\\\\.pub\")}$)(?!${ci(\"known_hosts\")}$)(?!${ci(\"config\")}$)))`,\n `(?!(?:.*/)?${ci(\"\\\\.aws\")}(?:$|/(?!${ci(\"config\")}$)))`,\n named(\"\\\\.npmrc\"), named(\"\\\\.pypirc\"), named(\"\\\\.netrc\"), named(\"_netrc\"), named(\"\\\\.git-credentials\"),\n dir(\"\\\\.kube\"), named(\"\\\\.kube/config\"), dir(\"\\\\.docker\"), named(\"\\\\.docker/config\\\\.json\"),\n under(\"\\\\.config/gcloud\"), under(\"\\\\.azure\"), under(\"\\\\.gnupg\"),\n dir(\"\\\\.config/gh\"), named(\"\\\\.config/gh/hosts\\\\.yml\"), named(\"\\\\.claude/\\\\.credentials\\\\.json\"),\n].join(\"\") + \".+\";\n\n// Destructive programs, POSIX and Windows. The mapper records the program as typed,\n// so the pattern accepts any case and an executable suffix (`RM.exe`, `Remove-Item`).\nexport const DESTRUCTIVE = [\n \"rm\", \"sudo\", \"doas\", \"shutdown\", \"reboot\", \"halt\", \"poweroff\", \"mkfs\", \"dd\", \"shred\", \"truncate\", \"unlink\", \"wipe\", \"srm\",\n \"del\", \"rd\", \"rmdir\", \"erase\", \"deltree\", \"format\", \"diskpart\", \"remove-item\", \"ri\", \"clear-content\", \"clc\", \"stop-computer\", \"restart-computer\",\n];\nconst SAFE_SHELL = `^(?!(?:${DESTRUCTIVE.map(ci).join(\"|\")})(?:${ci(\"\\\\.(?:exe|cmd|bat|com|ps1)\")})?$).+`;\n\n// A push destination the starter policy refuses: main, master, release/*, the\n// \"every branch\" flags (`--all`, `--mirror`, `--branches`) and a push whose\n// destination the mapper could not read (`--unknown`: a git alias, a configured push\n// refspec, `send-pack`), in any case. `--tags` alone pushes only tags and is allowed.\nconst SAFE_REF = `^(?!(?:${ci(\"main\")}|${ci(\"master\")})$)(?!${ci(\"release\")}/)(?!-(?!-${ci(\"tags\")}$)).+`;\n\n// Patterns written by earlier starter policies (0.3–0.5), upgraded in memory when a\n// policy on disk still carries them verbatim. An operator's own edits never match\n// these strings and are left untouched.\nconst LEGACY_STARTER_PATTERNS: Record<string, string> = {\n \"^(?!(?:main|master)$)(?!release/).+\": SAFE_REF,\n \"^(?!(?:rm|sudo|shutdown|reboot|mkfs|dd|del|rd|rmdir|erase|deltree|format|Remove-Item|ri)$).+\": SAFE_SHELL,\n \"^(?!(?:rm|sudo|shutdown|reboot|mkfs|dd)$).+\": SAFE_SHELL,\n \"^(?!(?:.*/)?\\\\.scopebond/)(?!(?:.*/)?\\\\.claude/settings)(?!(?:.*/)?\\\\.cursor/hooks)(?!(?:.*/)?\\\\.codex/(?:hooks\\\\.json|config\\\\.toml)$)(?!(?:.*/)?\\\\.git/hooks/)(?!(?:.*/)?\\\\.github/workflows/)(?!(?:.*/)?\\\\.github/actions/)(?!(?:.*/)?\\\\.gitlab-ci\\\\.yml$)(?!(?:.*/)?\\\\.circleci/)(?!(?:.*/)?azure-pipelines\\\\.yml$)(?!(?:.*/)?Jenkinsfile$).+\": PROTECTED_WRITE,\n \"^(?!(?:.*/)?\\\\.scopebond/)(?!(?:.*/)?\\\\.claude/settings)(?!(?:.*/)?\\\\.cursor/hooks)(?!(?:.*/)?\\\\.git/hooks/)(?!(?:.*/)?\\\\.github/workflows/)(?!(?:.*/)?\\\\.github/actions/)(?!(?:.*/)?\\\\.gitlab-ci\\\\.yml$)(?!(?:.*/)?\\\\.circleci/)(?!(?:.*/)?azure-pipelines\\\\.yml$)(?!(?:.*/)?Jenkinsfile$).+\": PROTECTED_WRITE,\n \"^(?!(?:.*/)?\\\\.scopebond/)(?!(?:.*/)?\\\\.claude/settings)(?!(?:.*/)?\\\\.cursor/hooks)(?!(?:.*/)?\\\\.git/hooks/).+\": PROTECTED_WRITE,\n \"^(?!(?:.*/)?\\\\.scopebond/)(?!.*\\\\.key$)(?!(?:.*/)?\\\\.env(?:\\\\.(?!example$|sample$|template$)[^/]*)?$).+\": PROTECTED_READ,\n \"^(?!(?:.*/)?\\\\.scopebond/)(?!.*\\\\.key$).+\": PROTECTED_READ,\n};\n\n/** Upgrade the starter-policy patterns an older hook wrote, in memory, so a user who\n * installed an earlier version gets the current protections without re-running init.\n * Only exact legacy strings are replaced; any other pattern is the operator's own. */\nexport function upgradeStarterPolicy<T>(policy: T): T {\n const p = policy as { clauses?: Array<{ param_bounds?: Record<string, { pattern?: string }> }> };\n for (const clause of p?.clauses ?? []) {\n for (const bound of Object.values(clause?.param_bounds ?? {})) {\n if (bound && typeof bound.pattern === \"string\" && LEGACY_STARTER_PATTERNS[bound.pattern]) bound.pattern = LEGACY_STARTER_PATTERNS[bound.pattern];\n }\n }\n return policy;\n}\n\n/** The default starter policy for a coding agent: protect release branches, deny\n * destructive programs, allow workspace file access except the hook's own config\n * and keys, and trust only the enrolled machine key. Every threshold is the\n * operator's to edit. */\nexport function starterPolicy(agentKid: string): Record<string, unknown> {\n return {\n vocabulary_version: \"1.0\", policy_id: \"coding-agent\", version: 1,\n clauses: [\n {\n id: \"protect-branches\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"git.push\"],\n param_bounds: { ref: { pattern: SAFE_REF } },\n description: \"Deny pushes to main, master and release/* (any case, any refspec spelling), pushes of every branch at once (--all, --mirror) and pushes whose destination cannot be read from the command (a git alias, a configured push refspec, send-pack). A tags-only push (--tags) is allowed.\",\n },\n {\n id: \"safe-shell\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"shell.exec\"],\n param_bounds: { program: { pattern: SAFE_SHELL } },\n description: \"Deny destructive programs — POSIX (rm, sudo, doas, shutdown, reboot, mkfs, dd, shred, truncate, unlink, wipe) and Windows/PowerShell (del, rd, rmdir, erase, deltree, format, diskpart, Remove-Item, Clear-Content) — in any case and with or without .exe. An empty program (a command that could not be parsed, or whose program is only known at run time: $VAR, $(…), eval of a variable) is denied. Argument-shaped deletion (find -delete, git clean) is not a program name and is not covered here.\",\n },\n {\n id: \"protect-write\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"file.write\"],\n param_bounds: { path: { pattern: PROTECTED_WRITE } },\n description: \"Allow workspace writes, but never to the hook's policy/keys, Claude Code settings, hooks and agents, Cursor or Codex hook settings, .mcp.json, git hooks and git config, Husky hooks, or CI config (.github/workflows, .github/actions, .gitlab-ci.yml/.yaml, .circleci, azure-pipelines.yml, Jenkinsfile). Case-insensitive.\",\n },\n {\n id: \"protect-read\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"file.read\"],\n param_bounds: { path: { pattern: PROTECTED_READ } },\n description: \"Allow workspace reads, but never signing keys and key containers (*.key, *.pem, *.p12, *.pfx, *.jks), environment secret files (.env, .env.*, .envrc — except names ending in .example/.sample/.template/.dist), SSH private keys and the .ssh directory, cloud/registry/git credentials (.aws except .aws/config, .npmrc, .pypirc, .netrc, .git-credentials, .kube/config, .docker/config.json, gcloud, Azure, GnuPG, the GitHub CLI's hosts.yml, Claude Code's .credentials.json) or the hook's own .scopebond directory. Case-insensitive.\",\n },\n {\n id: \"observe-net-mcp\", type: \"action_allowlist\", mode: \"monitor\",\n action_types: [\"net.fetch\", \"mcp.tool.call\"],\n description: \"Observe network fetches and MCP tool calls (recorded, not blocked) — add bounds to enforce.\",\n },\n { id: \"keys\", type: \"key_policy\", active_keys: [agentKid], description: \"Only the enrolled machine key may sign.\" },\n ],\n };\n}\n\n/** Build the runtime. Throws on any setup failure (unparseable policy, missing\n * key, unavailable store) — the CLI turns that into a fail-closed deny. */\nexport function createHookRuntime(config: RuntimeConfig) {\n const policy = upgradeStarterPolicy(JSON.parse(readFileSync(config.policyPath, \"utf8\")));\n const agent = createSigner({ privateKeyPem: readFileSync(config.keyPath, \"utf8\") });\n const keys = new StaticPrincipalKeyRegistry([\n { kid: agent.kid, publicKeyPem: agent.publicKeyPem, purposes: [\"agent\"], status: \"active\" },\n ]);\n const { attester } = loadOrCreateAttester({ file: config.attesterPath });\n // When the project has a readable rule set, a denial names the command that edits it\n // rather than the generated file.\n const rulesRemedy = existsSync(join(dirname(config.policyPath), RULES_FILE))\n ? `run \\`${cliCommand(\"rules\")}\\` to see the limits in plain terms, or edit ${join(dirname(config.policyPath), RULES_FILE)}`\n : undefined;\n const { store: baseStore } = openReceiptStore({ db: config.dbPath });\n // When connected, mirror every stored receipt to the hosted portal through a\n // durable outbox. The wrapped store's decision is unchanged; export is best-effort.\n let store = baseStore;\n let exporter: CloudExporter | undefined;\n let outbox: { close(): void } | undefined;\n if (config.cloud) {\n const attached = attachExporter(config.dbPath + \".cloud-outbox.db\", config.cloud.connection, baseStore, config.cloud.fetch);\n store = attached.store;\n exporter = attached.exporter;\n outbox = attached.outbox;\n }\n const gateway = createGateway({ policy, authentication: { keys }, attester, store, mode: \"check_only\" });\n\n return {\n gateway,\n agentKid: agent.kid,\n exporter,\n /** Deliver queued receipts to Cloud with a bounded timeout, then it is safe to\n * exit. Undelivered receipts persist in the durable outbox for the next run. */\n async flush(): Promise<void> {\n if (exporter) await flushBounded(exporter, config.cloud?.flushTimeoutMs);\n },\n /** Release the SQLite handles. The hook is a per-tool-call process, and a writer that\n * exits without closing leaves its write-ahead log on disk for the next process to\n * extend — measured at ~11 KiB of WAL per receipt against ~1.7 KiB when closed, so a\n * busy session was writing tens of megabytes of pure overhead into the user's project.\n * Always safe to call, and every exit path should. */\n close(): void {\n try { baseStore.close?.(); } catch { /* the decision is already recorded */ }\n try { outbox?.close(); } catch { /* best effort */ }\n },\n /** Decide one mapped action, recording a receipt either way. */\n async evaluateOne(mapped: Mapped): Promise<Decision> {\n const signed = agent.sign(mapped.intent);\n if (!mapped.evaluated && !config.strict) {\n // Unknown tool or unparseable command, non-strict: observe without\n // evaluating — grants nothing (D30).\n const { receipt } = await gateway.observeAction({ intent: signed.intent, authorization: signed.authorization });\n return { decision: \"not_evaluated\", reason: `no policy applies to ${mapped.intent.action_type}`, receipt };\n }\n // Evaluated actions, and (in strict mode) unmapped tool.<name>/opaque commands,\n // go through policy — a closed allowlist denies an unlisted action.\n const result = await gateway.handleAction({ intent: signed.intent, authorization: signed.authorization });\n if (result.allowed) return { decision: \"allow\", reason: result.reason, receipt: result.receipt };\n // A deny is the one message the user and their agent actually read, so it is\n // composed from the deciding clause's own words rather than the engine's\n // internal reason (\"param ref fails pattern\").\n const clauseId = result.verdict?.clause_id ?? null;\n return {\n decision: \"deny\",\n reason: explainDeny({\n policy, clauseId, detail: result.reason,\n intent: signed.intent as ExplainIntent, policyPath: config.policyPath,\n postHoc: mapped.postHoc,\n // Point at the editable surface when there is one. `policy.json` is compiled\n // from `rules.json`, so telling someone to hand-edit it invites a change the\n // next `rules` run would overwrite.\n remedy: rulesRemedy,\n }),\n clauseId,\n receipt: result.receipt,\n };\n },\n /** Decide a whole tool call. A shell call decomposes into several simple\n * commands; every one is recorded, and a single deny denies the call. */\n async evaluate(mapped: Mapped | Mapped[]): Promise<Decision> {\n const list = Array.isArray(mapped) ? mapped : [mapped];\n if (list.length === 0) return { decision: \"not_evaluated\", reason: \"no action\", receipts: [] };\n const receipts: unknown[] = [];\n let allow: Decision | null = null;\n let notEvaluated: Decision | null = null;\n for (const m of list) {\n const d = await this.evaluateOne(m);\n if (d.receipt !== undefined) receipts.push(d.receipt);\n if (d.decision === \"deny\") return { ...d, receipts }; // any deny denies the call\n if (d.decision === \"allow\" && !allow) allow = d;\n if (d.decision === \"not_evaluated\" && !notEvaluated) notEvaluated = d;\n }\n // No deny: allow if any command was evaluated-and-allowed, else not_evaluated.\n const chosen = allow ?? notEvaluated!;\n return { ...chosen, receipts };\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["// The hook runtime: a check-only (M0) gateway built once from the enrolled\n// machine key, policy and a durable local receipt log. Each mapped action is\n// signed by the machine key, decided against policy and countersigned — locally,\n// with no HTTP server and no Cloud dependency in 0.1.\n\nimport { readFileSync, existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { createGateway, StaticPrincipalKeyRegistry, type CloudExporter } from \"@scopebond/gateway\";\nimport { loadOrCreateAttester, openReceiptStore } from \"@scopebond/gateway/node\";\nimport { createSigner } from \"@scopebond/sdk\";\nimport type { Mapped } from \"./map.js\";\nimport { attachExporter, flushBounded, type HookConnection } from \"./cloud.js\";\nimport { explainDeny, type ExplainIntent } from \"./explain.js\";\nimport { RULES_FILE, loadRules } from \"./rules.js\";\nimport { applyRootScope } from \"./paths.js\";\nimport { withActionGroup, actionGroupId, ACTION_GROUP_PARAM } from \"./group.js\";\nimport { cliCommand } from \"./version.js\";\nimport { openDispatchGuard, DELEGATION_ENV } from \"@scopebond/gateway/node\";\nimport { dispatchIntentOf, type DispatchDecision, type DispatchGuard } from \"@scopebond/gateway\";\n\nexport interface RuntimeConfig {\n policyPath: string;\n keyPath: string;\n attesterPath: string;\n dbPath: string;\n /** Strict mode: an unmapped tool is policy-checked (and denied by a closed\n * allowlist) instead of observed. Fail-closed for tools with no taxonomy\n * mapping; default false (observe, matching the connector conformance vector). */\n strict?: boolean;\n /** The working directory the harness reported, used to resolve workspace roots when\n * the rule set lists `allowed_roots`. Defaults to the process directory. */\n cwd?: string;\n /** When connected to a Cloud workspace, receipts are auto-exported to the portal.\n * Export is best-effort and never changes the local decision. */\n cloud?: { connection: HookConnection; fetch?: typeof fetch; flushTimeoutMs?: number };\n}\n\nexport interface Decision {\n decision: \"allow\" | \"deny\" | \"not_evaluated\";\n reason: string;\n /** The clause that decided a deny, when the verdict named one. */\n clauseId?: string | null;\n /** The deciding receipt (the denied one, or the first allow). */\n receipt?: unknown;\n /** Every receipt produced — one per simple command in a decomposed shell call. */\n receipts?: unknown[];\n /** Each action as actually evaluated (after root scoping and grouping), with its\n * receipt: what the observation emitters bind a request digest to. */\n /** What the dispatch boundary spent or refused for this call, when one is configured. */\n dispatch?: DispatchDecision;\n dispatched?: Array<{ action: { action_type: string; params: Record<string, unknown> }; receipt?: unknown }>;\n}\n\n// The hook's own config and keys must be off-limits to the agent it governs:\n// otherwise the agent could rewrite its policy or read the signing keys and the\n// receipts stop meaning anything. These patterns are \"allow if the path does NOT\n// match a protected location\"; they run against the cwd-relative path the mapper\n// produces (and equally against an absolute one).\n//\n// Matching is case-insensitive — Windows and macOS open `.ENV` and `.env` as the\n// same file — by expanding each letter to a two-case class (policy patterns are\n// plain regular expressions with no flags). `ci()` is applied to literal text only.\nexport const ci = (s: string): string => s.replace(/[A-Za-z]/g, (c) => `[${c.toLowerCase()}${c.toUpperCase()}]`);\nexport const under = (dir: string): string => `(?!(?:.*/)?${ci(dir)}(?:/|$))`; // dir itself or anything inside it\nexport const named = (file: string): string => `(?!(?:.*/)?${ci(file)}$)`; // exactly this file name\nexport const dir = (d: string): string => `(?!(?:.*/)?${ci(d)}/?$)`; // the directory itself (a recursive read or copy)\n\n// The protected-write set, in two typed groups the catalog classifies separately:\n// guardrail/hook configuration (C02) and CI configuration (H03).\nconst GUARDRAIL_WRITE_PREV = [\n under(\"\\\\.scopebond\"), `(?!(?:.*/)?${ci(\"\\\\.claude/settings\")})`, under(\"\\\\.claude/hooks\"), under(\"\\\\.claude/agents\"),\n `(?!(?:.*/)?${ci(\"\\\\.cursor/hooks\")})`, named(\"\\\\.codex/hooks\\\\.json\"), named(\"\\\\.codex/config\\\\.toml\"), named(\"\\\\.mcp\\\\.json\"),\n under(\"\\\\.git/hooks\"), named(\"\\\\.git/config\"), under(\"\\\\.husky\"),\n];\nconst CI_WRITE_PREV = [\n under(\"\\\\.github/workflows\"), under(\"\\\\.github/actions\"), named(\"\\\\.gitlab-ci\\\\.yml\"), named(\"\\\\.gitlab-ci\\\\.yaml\"), under(\"\\\\.circleci\"),\n named(\"azure-pipelines\\\\.yml\"), named(\"Jenkinsfile\"),\n];\nconst GUARDRAIL_WRITE = [...GUARDRAIL_WRITE_PREV, named(\"\\\\.cursor/mcp\\\\.json\"), under(\"\\\\.githooks\")];\nconst CI_WRITE = [\n ...CI_WRITE_PREV,\n named(\"azure-pipelines\\\\.yaml\"), named(\"bitbucket-pipelines\\\\.yml\"), named(\"\\\\.travis\\\\.yml\"), named(\"\\\\.drone\\\\.yml\"),\n named(\"cloudbuild\\\\.yaml\"), named(\"cloudbuild\\\\.yml\"), under(\"\\\\.buildkite\"),\n];\n// What 0.8 compiled, kept so an installed policy that still carries it verbatim is\n// upgraded in memory (see LEGACY_STARTER_PATTERNS).\nconst PROTECTED_WRITE_PREV = \"^\" + [...GUARDRAIL_WRITE_PREV, ...CI_WRITE_PREV].join(\"\") + \".+\";\nconst PROTECTED_WRITE = \"^\" + [...GUARDRAIL_WRITE, ...CI_WRITE].join(\"\") + \".+\";\n\nconst PROTECTED_READ = \"^\" + [\n under(\"\\\\.scopebond\"),\n `(?!.*${ci(\"\\\\.(?:key|pem|p12|pfx|jks|keystore)\")}$)`,\n // .env, .env.* — except templates whose name ends in .example/.sample/.template/.dist\n `(?!(?:.*/)?${ci(\"\\\\.env\")}(?!(?:\\\\.[^/]*)?\\\\.(?:${ci(\"example\")}|${ci(\"sample\")}|${ci(\"template\")}|${ci(\"dist\")})$)(?:\\\\.[^/]*)?$)`,\n named(\"\\\\.envrc\"),\n // Credentials outside the workspace that an agent can reach by absolute or ~ path,\n // and their directories as a whole (`cp -r ~/.ssh`, `grep -r x ~/.aws`).\n `(?!(?:.*/)?${ci(\"\\\\.ssh\")}(?:$|/(?!.*${ci(\"\\\\.pub\")}$)(?!${ci(\"known_hosts\")}$)(?!${ci(\"config\")}$)))`,\n `(?!(?:.*/)?${ci(\"\\\\.aws\")}(?:$|/(?!${ci(\"config\")}$)))`,\n named(\"\\\\.npmrc\"), named(\"\\\\.pypirc\"), named(\"\\\\.netrc\"), named(\"_netrc\"), named(\"\\\\.git-credentials\"),\n dir(\"\\\\.kube\"), named(\"\\\\.kube/config\"), dir(\"\\\\.docker\"), named(\"\\\\.docker/config\\\\.json\"),\n under(\"\\\\.config/gcloud\"), under(\"\\\\.azure\"), under(\"\\\\.gnupg\"),\n dir(\"\\\\.config/gh\"), named(\"\\\\.config/gh/hosts\\\\.yml\"), named(\"\\\\.claude/\\\\.credentials\\\\.json\"),\n].join(\"\") + \".+\";\n\n// Destructive programs, POSIX and Windows. The mapper records the program as typed,\n// so the pattern accepts any case and an executable suffix (`RM.exe`, `Remove-Item`).\nexport const DESTRUCTIVE = [\n \"rm\", \"sudo\", \"doas\", \"shutdown\", \"reboot\", \"halt\", \"poweroff\", \"mkfs\", \"dd\", \"shred\", \"truncate\", \"unlink\", \"wipe\", \"srm\",\n \"del\", \"rd\", \"rmdir\", \"erase\", \"deltree\", \"format\", \"diskpart\", \"remove-item\", \"ri\", \"clear-content\", \"clc\", \"stop-computer\", \"restart-computer\",\n];\nconst SAFE_SHELL = `^(?!(?:${DESTRUCTIVE.map(ci).join(\"|\")})(?:${ci(\"\\\\.(?:exe|cmd|bat|com|ps1)\")})?$).+`;\n\n// A push destination the starter policy refuses: main, master, release/*, the\n// \"every branch\" flags (`--all`, `--mirror`, `--branches`) and a push whose\n// destination the mapper could not read (`--unknown`: a git alias, a configured push\n// refspec, `send-pack`), in any case. `--tags` alone pushes only tags and is allowed.\nconst SAFE_REF = `^(?!(?:${ci(\"main\")}|${ci(\"master\")})$)(?!${ci(\"release\")}/)(?!-(?!-${ci(\"tags\")}$)).+`;\n\n// Patterns written by earlier starter policies (0.3–0.5), upgraded in memory when a\n// policy on disk still carries them verbatim. An operator's own edits never match\n// these strings and are left untouched.\nconst LEGACY_STARTER_PATTERNS: Record<string, string> = {\n [PROTECTED_WRITE_PREV]: PROTECTED_WRITE,\n \"^(?!(?:main|master)$)(?!release/).+\": SAFE_REF,\n \"^(?!(?:rm|sudo|shutdown|reboot|mkfs|dd|del|rd|rmdir|erase|deltree|format|Remove-Item|ri)$).+\": SAFE_SHELL,\n \"^(?!(?:rm|sudo|shutdown|reboot|mkfs|dd)$).+\": SAFE_SHELL,\n \"^(?!(?:.*/)?\\\\.scopebond/)(?!(?:.*/)?\\\\.claude/settings)(?!(?:.*/)?\\\\.cursor/hooks)(?!(?:.*/)?\\\\.codex/(?:hooks\\\\.json|config\\\\.toml)$)(?!(?:.*/)?\\\\.git/hooks/)(?!(?:.*/)?\\\\.github/workflows/)(?!(?:.*/)?\\\\.github/actions/)(?!(?:.*/)?\\\\.gitlab-ci\\\\.yml$)(?!(?:.*/)?\\\\.circleci/)(?!(?:.*/)?azure-pipelines\\\\.yml$)(?!(?:.*/)?Jenkinsfile$).+\": PROTECTED_WRITE,\n \"^(?!(?:.*/)?\\\\.scopebond/)(?!(?:.*/)?\\\\.claude/settings)(?!(?:.*/)?\\\\.cursor/hooks)(?!(?:.*/)?\\\\.git/hooks/)(?!(?:.*/)?\\\\.github/workflows/)(?!(?:.*/)?\\\\.github/actions/)(?!(?:.*/)?\\\\.gitlab-ci\\\\.yml$)(?!(?:.*/)?\\\\.circleci/)(?!(?:.*/)?azure-pipelines\\\\.yml$)(?!(?:.*/)?Jenkinsfile$).+\": PROTECTED_WRITE,\n \"^(?!(?:.*/)?\\\\.scopebond/)(?!(?:.*/)?\\\\.claude/settings)(?!(?:.*/)?\\\\.cursor/hooks)(?!(?:.*/)?\\\\.git/hooks/).+\": PROTECTED_WRITE,\n \"^(?!(?:.*/)?\\\\.scopebond/)(?!.*\\\\.key$)(?!(?:.*/)?\\\\.env(?:\\\\.(?!example$|sample$|template$)[^/]*)?$).+\": PROTECTED_READ,\n \"^(?!(?:.*/)?\\\\.scopebond/)(?!.*\\\\.key$).+\": PROTECTED_READ,\n};\n\n/** Upgrade the starter-policy patterns an older hook wrote, in memory, so a user who\n * installed an earlier version gets the current protections without re-running init.\n * Only exact legacy strings are replaced; any other pattern is the operator's own. */\nexport function upgradeStarterPolicy<T>(policy: T): T {\n const p = policy as { clauses?: Array<{ param_bounds?: Record<string, { pattern?: string }> }> };\n for (const clause of p?.clauses ?? []) {\n for (const bound of Object.values(clause?.param_bounds ?? {})) {\n if (bound && typeof bound.pattern === \"string\" && LEGACY_STARTER_PATTERNS[bound.pattern]) bound.pattern = LEGACY_STARTER_PATTERNS[bound.pattern];\n }\n }\n return policy;\n}\n\n/** The default starter policy for a coding agent: protect release branches, deny\n * destructive programs, allow workspace file access except the hook's own config\n * and keys, and trust only the enrolled machine key. Every threshold is the\n * operator's to edit. */\nexport function starterPolicy(agentKid: string): Record<string, unknown> {\n return {\n vocabulary_version: \"1.0\", policy_id: \"coding-agent\", version: 1,\n clauses: [\n {\n id: \"protect-branches\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"git.push\"],\n param_bounds: { ref: { pattern: SAFE_REF } },\n description: \"Deny pushes to main, master and release/* (any case, any refspec spelling), pushes of every branch at once (--all, --mirror) and pushes whose destination cannot be read from the command (a git alias, a configured push refspec, send-pack). A tags-only push (--tags) is allowed.\",\n },\n {\n id: \"safe-shell\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"shell.exec\"],\n param_bounds: { program: { pattern: SAFE_SHELL } },\n description: \"Deny destructive programs — POSIX (rm, sudo, doas, shutdown, reboot, mkfs, dd, shred, truncate, unlink, wipe) and Windows/PowerShell (del, rd, rmdir, erase, deltree, format, diskpart, Remove-Item, Clear-Content) — in any case and with or without .exe. An empty program (a command that could not be parsed, or whose program is only known at run time: $VAR, $(…), eval of a variable) is denied. Argument-shaped deletion (find -delete, git clean) is not a program name and is not covered here.\",\n },\n {\n id: \"protect-write\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"file.write\"],\n param_bounds: { path: { pattern: PROTECTED_WRITE } },\n description: \"Allow workspace writes, but never to the hook's policy/keys, Claude Code settings, hooks and agents, Cursor or Codex hook settings, .mcp.json and .cursor/mcp.json, git hooks (.git/hooks, .githooks) and git config, Husky hooks, or CI config (.github/workflows, .github/actions, .gitlab-ci.yml/.yaml, .circleci, azure-pipelines, bitbucket-pipelines.yml, .travis.yml, .drone.yml, cloudbuild, .buildkite, Jenkinsfile). Case-insensitive.\",\n },\n {\n id: \"protect-read\", type: \"action_allowlist\", mode: \"enforce\", action_types: [\"file.read\"],\n param_bounds: { path: { pattern: PROTECTED_READ } },\n description: \"Allow workspace reads, but never signing keys and key containers (*.key, *.pem, *.p12, *.pfx, *.jks), environment secret files (.env, .env.*, .envrc — except names ending in .example/.sample/.template/.dist), SSH private keys and the .ssh directory, cloud/registry/git credentials (.aws except .aws/config, .npmrc, .pypirc, .netrc, .git-credentials, .kube/config, .docker/config.json, gcloud, Azure, GnuPG, the GitHub CLI's hosts.yml, Claude Code's .credentials.json) or the hook's own .scopebond directory. Case-insensitive.\",\n },\n {\n id: \"observe-net-mcp\", type: \"action_allowlist\", mode: \"monitor\",\n action_types: [\"net.fetch\", \"mcp.tool.call\"],\n description: \"Observe network fetches and MCP tool calls (recorded, not blocked) — add bounds to enforce.\",\n },\n { id: \"keys\", type: \"key_policy\", active_keys: [agentKid], description: \"Only the enrolled machine key may sign.\" },\n ],\n };\n}\n\n/** Build the runtime. Throws on any setup failure (unparseable policy, missing\n * key, unavailable store) — the CLI turns that into a fail-closed deny. */\nexport function createHookRuntime(config: RuntimeConfig) {\n const policy = upgradeStarterPolicy(JSON.parse(readFileSync(config.policyPath, \"utf8\")));\n const agent = createSigner({ privateKeyPem: readFileSync(config.keyPath, \"utf8\") });\n const keys = new StaticPrincipalKeyRegistry([\n { kid: agent.kid, publicKeyPem: agent.publicKeyPem, purposes: [\"agent\"], status: \"active\" },\n ]);\n const { attester } = loadOrCreateAttester({ file: config.attesterPath });\n // When the project has a readable rule set, a denial names the command that edits it\n // rather than the generated file.\n const rulesRemedy = existsSync(join(dirname(config.policyPath), RULES_FILE))\n ? `run \\`${cliCommand(\"rules\")}\\` to see the limits in plain terms, or edit ${join(dirname(config.policyPath), RULES_FILE)}`\n : undefined;\n const { store: baseStore } = openReceiptStore({ db: config.dbPath });\n // When connected, mirror every stored receipt to the hosted portal through a\n // durable outbox. The wrapped store's decision is unchanged; export is best-effort.\n let store = baseStore;\n let exporter: CloudExporter | undefined;\n let outbox: { close(): void } | undefined;\n if (config.cloud) {\n const attached = attachExporter(config.dbPath + \".cloud-outbox.db\", config.cloud.connection, baseStore, config.cloud.fetch);\n store = attached.store;\n exporter = attached.exporter;\n outbox = attached.outbox;\n }\n const scopeRoots = loadRules(dirname(config.policyPath))?.allowed_roots ?? [];\n // The dispatch boundary is checked once per tool call, after every intent has been allowed, so the\n // gateway's own per-intent hook only reports what the runtime already decided for this call.\n const boundary = openDispatchGuard(dirname(config.policyPath));\n let boundaryVerdict: DispatchDecision | null = null;\n const gatewayGuard: DispatchGuard = { authorize: async () => boundaryVerdict ?? { allow: true, reason: \"ok\", consumed_approvals: [], budgets: [] } };\n const gateway = createGateway({ policy, authentication: { keys }, attester, store, mode: \"check_only\", dispatchGuard: gatewayGuard });\n\n return {\n gateway,\n agentKid: agent.kid,\n exporter,\n /** Deliver queued receipts to Cloud with a bounded timeout, then it is safe to\n * exit. Undelivered receipts persist in the durable outbox for the next run. */\n async flush(): Promise<void> {\n if (exporter) await flushBounded(exporter, config.cloud?.flushTimeoutMs);\n },\n /** Release the SQLite handles. The hook is a per-tool-call process, and a writer that\n * exits without closing leaves its write-ahead log on disk for the next process to\n * extend — measured at ~11 KiB of WAL per receipt against ~1.7 KiB when closed, so a\n * busy session was writing tens of megabytes of pure overhead into the user's project.\n * Always safe to call, and every exit path should. */\n close(): void {\n try { baseStore.close?.(); } catch { /* the decision is already recorded */ }\n try { outbox?.close(); } catch { /* best effort */ }\n try { boundary?.close(); } catch { /* best effort */ }\n },\n /** Decide one mapped action, recording a receipt either way. */\n async evaluateOne(mapped: Mapped): Promise<Decision> {\n const signed = agent.sign(mapped.intent);\n if (!mapped.evaluated && !config.strict) {\n // Unknown tool or unparseable command, non-strict: observe without\n // evaluating — grants nothing (D30).\n const { receipt } = await gateway.observeAction({ intent: signed.intent, authorization: signed.authorization });\n return { decision: \"not_evaluated\", reason: `no policy applies to ${mapped.intent.action_type}`, receipt };\n }\n // Evaluated actions, and (in strict mode) unmapped tool.<name>/opaque commands,\n // go through policy — a closed allowlist denies an unlisted action.\n const result = await gateway.handleAction({ intent: signed.intent, authorization: signed.authorization });\n if (result.allowed) return { decision: \"allow\", reason: result.reason, receipt: result.receipt };\n // A deny is the one message the user and their agent actually read, so it is\n // composed from the deciding clause's own words rather than the engine's\n // internal reason (\"param ref fails pattern\").\n const clauseId = result.verdict?.clause_id ?? null;\n return {\n decision: \"deny\",\n reason: explainDeny({\n policy, clauseId, detail: result.reason,\n intent: signed.intent as ExplainIntent, policyPath: config.policyPath,\n postHoc: mapped.postHoc,\n // Point at the editable surface when there is one. `policy.json` is compiled\n // from `rules.json`, so telling someone to hand-edit it invites a change the\n // next `rules` run would overwrite.\n remedy: rulesRemedy,\n }),\n clauseId,\n receipt: result.receipt,\n };\n },\n /** Decide a whole tool call. A shell call decomposes into several simple\n * commands; every one is recorded, and a single deny denies the call. */\n async evaluate(mapped: Mapped | Mapped[], options: { groupKey?: string } = {}): Promise<Decision> {\n const raw = Array.isArray(mapped) ? mapped : [mapped];\n if (raw.length === 0) return { decision: \"not_evaluated\", reason: \"no action\", receipts: [] };\n // Every intent of one tool call carries one parent group id, so the receipts of a\n // decomposed call (a command, its file reads and writes, a rename destination)\n // link to each other and count once as an action. It is part of the signed\n // intent, so it is authenticated by the same signature as the rest.\n const scoped = scopeRoots.length ? applyRootScope(raw, { cwd: config.cwd ?? process.cwd(), roots: scopeRoots }) : raw;\n const list = withActionGroup(scoped, actionGroupId(options.groupKey));\n const receipts: unknown[] = [];\n const dispatched: NonNullable<Decision[\"dispatched\"]> = [];\n let allow: Decision | null = null;\n let notEvaluated: Decision | null = null;\n for (const m of list) {\n const d = await this.evaluateOne(m);\n if (d.receipt !== undefined) receipts.push(d.receipt);\n dispatched.push({ action: { action_type: m.intent.action_type, params: m.intent.params as Record<string, unknown> }, ...(d.receipt !== undefined ? { receipt: d.receipt } : {}) });\n if (d.decision === \"deny\") return { ...d, receipts, dispatched }; // any deny denies the call\n if (d.decision === \"allow\" && !allow) allow = d;\n if (d.decision === \"not_evaluated\" && !notEvaluated) notEvaluated = d;\n }\n // No deny: allow if any command was evaluated-and-allowed, else not_evaluated.\n const chosen = allow ?? notEvaluated!;\n if (boundary) {\n // Immediately before permitted dispatch: approvals are consumed and the budget slot is reserved\n // atomically, once for the whole parent action, or nothing is spent and the call is denied.\n const group = String(list[0]!.intent.params[ACTION_GROUP_PARAM]);\n const delegation = process.env[DELEGATION_ENV] ?? \"\";\n const verdict = await boundary.authorize({\n actor: agent.kid, action_group: group, policy_digest: gateway.policyHash,\n intents: list.map((m) => dispatchIntentOf(m.intent as never)),\n ...(delegation !== \"\" ? { delegation_id: delegation } : {}),\n });\n if (!verdict.allow) {\n // Record the refusal as its own denied receipt, then deny the call.\n boundaryVerdict = verdict;\n try {\n const last = list[list.length - 1]!;\n const signed = agent.sign(last.intent);\n const result = await gateway.handleAction({ intent: signed.intent, authorization: signed.authorization });\n if (result.receipt !== undefined) receipts.push(result.receipt);\n } finally { boundaryVerdict = null; }\n return { decision: \"deny\", reason: `Scopebond blocked this before it ran: ${verdict.reason}${verdict.detail ? ` (${verdict.detail})` : \"\"}`, receipts, dispatched, dispatch: verdict };\n }\n return { ...chosen, receipts, dispatched, dispatch: verdict };\n }\n return { ...chosen, receipts, dispatched };\n },\n };\n}\n"]}
|
package/dist/scan.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface Scanned {
|
|
2
|
+
positionals: string[];
|
|
3
|
+
flags: Map<string, string | true>;
|
|
4
|
+
}
|
|
5
|
+
export declare function scan(argv: string[], valued: readonly string[]): Scanned;
|
|
6
|
+
export declare const flagValue: (s: Scanned, ...names: string[]) => string | undefined;
|
|
7
|
+
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,OAAO;IAAG,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAA;CAAE;AAErF,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAevE;AAED,eAAO,MAAM,SAAS,GAAI,GAAG,OAAO,EAAE,GAAG,OAAO,MAAM,EAAE,KAAG,MAAM,GAAG,SAGnE,CAAC"}
|
package/dist/scan.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Option scanning shared by the typed-operation derivations.
|
|
2
|
+
export function scan(argv, valued) {
|
|
3
|
+
const positionals = [];
|
|
4
|
+
const flags = new Map();
|
|
5
|
+
const takes = new Set(valued);
|
|
6
|
+
for (let i = 0; i < argv.length; i++) {
|
|
7
|
+
const t = argv[i];
|
|
8
|
+
if (t === "--") {
|
|
9
|
+
positionals.push(...argv.slice(i + 1));
|
|
10
|
+
break;
|
|
11
|
+
}
|
|
12
|
+
if (t.startsWith("--") && t.includes("=")) {
|
|
13
|
+
const at = t.indexOf("=");
|
|
14
|
+
flags.set(t.slice(0, at), t.slice(at + 1));
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (t.startsWith("-") && t.length > 1) {
|
|
18
|
+
if (takes.has(t)) {
|
|
19
|
+
flags.set(t, argv[i + 1] ?? "");
|
|
20
|
+
i += 1;
|
|
21
|
+
}
|
|
22
|
+
else
|
|
23
|
+
flags.set(t, true);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
positionals.push(t);
|
|
27
|
+
}
|
|
28
|
+
return { positionals, flags };
|
|
29
|
+
}
|
|
30
|
+
export const flagValue = (s, ...names) => {
|
|
31
|
+
for (const n of names) {
|
|
32
|
+
const v = s.flags.get(n);
|
|
33
|
+
if (typeof v === "string" && v !== "")
|
|
34
|
+
return v;
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=scan.js.map
|
package/dist/scan.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAI7D,MAAM,UAAU,IAAI,CAAC,IAAc,EAAE,MAAyB;IAC5D,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC/C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YAAC,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAAC,MAAM;QAAC,CAAC;QAClE,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAAC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;YAAC,SAAS;QAAC,CAAC;QAC/H,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;gBAAC,CAAC,IAAI,CAAC,CAAC;YAAC,CAAC;;gBAAM,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;YACvF,SAAS;QACX,CAAC;QACD,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAU,EAAE,GAAG,KAAe,EAAsB,EAAE;IAC9E,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,EAAE;YAAE,OAAO,CAAC,CAAC;IAAC,CAAC;IACrG,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC","sourcesContent":["// Option scanning shared by the typed-operation derivations.\n\nexport interface Scanned { positionals: string[]; flags: Map<string, string | true> }\n\nexport function scan(argv: string[], valued: readonly string[]): Scanned {\n const positionals: string[] = [];\n const flags = new Map<string, string | true>();\n const takes = new Set(valued);\n for (let i = 0; i < argv.length; i++) {\n const t = argv[i];\n if (t === \"--\") { positionals.push(...argv.slice(i + 1)); break; }\n if (t.startsWith(\"--\") && t.includes(\"=\")) { const at = t.indexOf(\"=\"); flags.set(t.slice(0, at), t.slice(at + 1)); continue; }\n if (t.startsWith(\"-\") && t.length > 1) {\n if (takes.has(t)) { flags.set(t, argv[i + 1] ?? \"\"); i += 1; } else flags.set(t, true);\n continue;\n }\n positionals.push(t);\n }\n return { positionals, flags };\n}\n\nexport const flagValue = (s: Scanned, ...names: string[]): string | undefined => {\n for (const n of names) { const v = s.flags.get(n); if (typeof v === \"string\" && v !== \"\") return v; }\n return undefined;\n};\n\n"]}
|
package/dist/shell.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../src/shell.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,QAAQ;IACvB,4EAA4E;IAC5E,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B;8CAC0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB;sFACkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,wEAAwE;IACxE,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,oEAAoE;IACpE,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;2DAG2D;AAC3D,eAAO,MAAM,YAAY,GAAI,GAAG,MAAM,KAAG,MAC0C,CAAC;AA6dpF;oEACoE;AACpE,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../src/shell.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,QAAQ;IACvB,4EAA4E;IAC5E,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B;8CAC0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB;sFACkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,wEAAwE;IACxE,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,oEAAoE;IACpE,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;2DAG2D;AAC3D,eAAO,MAAM,YAAY,GAAI,GAAG,MAAM,KAAG,MAC0C,CAAC;AA6dpF;oEACoE;AACpE,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,aAAa,EAAE,CA6E1E;AAED,uFAAuF;AACvF,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf;wFACoF;IACpF,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;uFACmF;IACnF,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED;;sFAEsF;AACtF,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIxD;AAGD;;mFAEmF;AACnF,wBAAgB,OAAO,CAAC,GAAG,EAAE,aAAa,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CActG;AAED;;;;4EAI4E;AAC5E,eAAO,MAAM,WAAW,cAAc,CAAC;AAEvC;;;;;;;;;yCASyC;AACzC,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,UAAU,EAAE,CAAA;CAAE,GAAG,IAAI,CA4DhI"}
|