@paybond/kit 0.9.8 → 0.11.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/completion-presets/catalog.json +1187 -0
- package/completion-presets/catalog.sha256 +1 -0
- package/dev/trace-ui/dashboard.html +617 -0
- package/dist/agent/adapter.d.ts +51 -0
- package/dist/agent/adapter.js +66 -0
- package/dist/agent/attach-bundle.d.ts +37 -0
- package/dist/agent/attach-bundle.js +118 -0
- package/dist/agent/authorization-cache.d.ts +22 -0
- package/dist/agent/authorization-cache.js +36 -0
- package/dist/agent/deferred-tools.d.ts +11 -0
- package/dist/agent/deferred-tools.js +62 -0
- package/dist/agent/discover.d.ts +41 -0
- package/dist/agent/discover.js +147 -0
- package/dist/agent/evidence.d.ts +9 -0
- package/dist/agent/evidence.js +28 -0
- package/dist/agent/facade.d.ts +48 -0
- package/dist/agent/facade.js +112 -0
- package/dist/agent/gateway-trace-reporter.d.ts +28 -0
- package/dist/agent/gateway-trace-reporter.js +49 -0
- package/dist/agent/generic-runner.d.ts +14 -0
- package/dist/agent/generic-runner.js +49 -0
- package/dist/agent/generic-sandbox-demo.d.ts +36 -0
- package/dist/agent/generic-sandbox-demo.js +82 -0
- package/dist/agent/guarded-agent.d.ts +49 -0
- package/dist/agent/guarded-agent.js +100 -0
- package/dist/agent/index.d.ts +13 -0
- package/dist/agent/index.js +13 -0
- package/dist/agent/instrument.d.ts +156 -0
- package/dist/agent/instrument.js +442 -0
- package/dist/agent/interceptor.d.ts +24 -0
- package/dist/agent/interceptor.js +440 -0
- package/dist/agent/lazy-context-tools.d.ts +15 -0
- package/dist/agent/lazy-context-tools.js +81 -0
- package/dist/agent/registry-file.d.ts +39 -0
- package/dist/agent/registry-file.js +219 -0
- package/dist/agent/registry.d.ts +37 -0
- package/dist/agent/registry.js +128 -0
- package/dist/agent/run.d.ts +124 -0
- package/dist/agent/run.js +301 -0
- package/dist/agent/types.d.ts +318 -0
- package/dist/agent/types.js +42 -0
- package/dist/agent-recognition.d.ts +72 -0
- package/dist/agent-recognition.js +165 -0
- package/dist/bincode-wire.d.ts +18 -0
- package/dist/bincode-wire.js +93 -0
- package/dist/claude-agents/config.d.ts +21 -0
- package/dist/claude-agents/config.js +145 -0
- package/dist/claude-agents/index.d.ts +2 -0
- package/dist/claude-agents/index.js +2 -0
- package/dist/claude-agents/sandbox-demo.d.ts +30 -0
- package/dist/claude-agents/sandbox-demo.js +91 -0
- package/dist/cli/agent/env-quote.d.ts +1 -0
- package/dist/cli/agent/env-quote.js +6 -0
- package/dist/cli/agent/env-write.d.ts +8 -0
- package/dist/cli/agent/env-write.js +47 -0
- package/dist/cli/agent/paybond.d.ts +16 -0
- package/dist/cli/agent/paybond.js +55 -0
- package/dist/cli/agent/policy-file.d.ts +29 -0
- package/dist/cli/agent/policy-file.js +61 -0
- package/dist/cli/agent/production-evidence.d.ts +24 -0
- package/dist/cli/agent/production-evidence.js +98 -0
- package/dist/cli/agent/run-store.d.ts +30 -0
- package/dist/cli/agent/run-store.js +42 -0
- package/dist/cli/agent/run-trace-store.d.ts +39 -0
- package/dist/cli/agent/run-trace-store.js +143 -0
- package/dist/cli/agent-run-trace-table.d.ts +9 -0
- package/dist/cli/agent-run-trace-table.js +24 -0
- package/dist/cli/agent-sandbox-smoke-checklist.d.ts +9 -0
- package/dist/cli/agent-sandbox-smoke-checklist.js +50 -0
- package/dist/cli/audit-export.d.ts +7 -0
- package/dist/cli/audit-export.js +120 -0
- package/dist/cli/automation.d.ts +25 -0
- package/dist/cli/automation.js +297 -0
- package/dist/cli/body.d.ts +7 -0
- package/dist/cli/body.js +22 -0
- package/dist/cli/color.d.ts +15 -0
- package/dist/cli/color.js +39 -0
- package/dist/cli/command-spec.d.ts +13 -0
- package/dist/cli/command-spec.js +611 -0
- package/dist/cli/commands/agent.d.ts +16 -0
- package/dist/cli/commands/agent.js +1135 -0
- package/dist/cli/commands/dev.d.ts +7 -0
- package/dist/cli/commands/dev.js +348 -0
- package/dist/cli/commands/discovery.d.ts +8 -0
- package/dist/cli/commands/discovery.js +194 -0
- package/dist/cli/commands/policy.d.ts +13 -0
- package/dist/cli/commands/policy.js +769 -0
- package/dist/cli/commands/setup.d.ts +18 -0
- package/dist/cli/commands/setup.js +513 -0
- package/dist/cli/commands/workflows.d.ts +7 -0
- package/dist/cli/commands/workflows.js +214 -0
- package/dist/cli/config.d.ts +16 -0
- package/dist/cli/config.js +98 -0
- package/dist/cli/context.d.ts +22 -0
- package/dist/cli/context.js +110 -0
- package/dist/cli/credentials.d.ts +21 -0
- package/dist/cli/credentials.js +141 -0
- package/dist/cli/doctor-agent-middleware.d.ts +5 -0
- package/dist/cli/doctor-agent-middleware.js +49 -0
- package/dist/cli/doctor-agent.d.ts +15 -0
- package/dist/cli/doctor-agent.js +311 -0
- package/dist/cli/envelope.d.ts +14 -0
- package/dist/cli/envelope.js +46 -0
- package/dist/cli/globals.d.ts +23 -0
- package/dist/cli/globals.js +248 -0
- package/dist/cli/help.d.ts +3 -0
- package/dist/cli/help.js +83 -0
- package/dist/cli/mcp-install.d.ts +41 -0
- package/dist/cli/mcp-install.js +95 -0
- package/dist/cli/mcp-policy.d.ts +26 -0
- package/dist/cli/mcp-policy.js +110 -0
- package/dist/cli/mcp-verify-config.d.ts +37 -0
- package/dist/cli/mcp-verify-config.js +172 -0
- package/dist/cli/redact.d.ts +4 -0
- package/dist/cli/redact.js +88 -0
- package/dist/cli/request-id.d.ts +2 -0
- package/dist/cli/request-id.js +5 -0
- package/dist/cli/router.d.ts +2 -0
- package/dist/cli/router.js +378 -0
- package/dist/cli/smoke-deep-links.d.ts +15 -0
- package/dist/cli/smoke-deep-links.js +63 -0
- package/dist/cli/suggest.d.ts +4 -0
- package/dist/cli/suggest.js +58 -0
- package/dist/cli/support-diagnostics.d.ts +19 -0
- package/dist/cli/support-diagnostics.js +47 -0
- package/dist/cli/telemetry.d.ts +17 -0
- package/dist/cli/telemetry.js +94 -0
- package/dist/cli/types.d.ts +72 -0
- package/dist/cli/types.js +60 -0
- package/dist/cli/ux.d.ts +8 -0
- package/dist/cli/ux.js +164 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +38 -0
- package/dist/completion-catalog-digest.d.ts +2 -0
- package/dist/completion-catalog-digest.js +2 -0
- package/dist/completion-catalog-integrity.d.ts +2 -0
- package/dist/completion-catalog-integrity.js +17 -0
- package/dist/completion-catalog.d.ts +49 -0
- package/dist/completion-catalog.js +62 -0
- package/dist/completion-contract-digest.d.ts +37 -0
- package/dist/completion-contract-digest.js +73 -0
- package/dist/completion-forbidden-fields.d.ts +5 -0
- package/dist/completion-forbidden-fields.js +26 -0
- package/dist/completion-init.d.ts +8 -0
- package/dist/completion-init.js +334 -0
- package/dist/completion-resolve.d.ts +21 -0
- package/dist/completion-resolve.js +86 -0
- package/dist/completion-validate-evidence.d.ts +24 -0
- package/dist/completion-validate-evidence.js +145 -0
- package/dist/dev/offline-gateway.d.ts +24 -0
- package/dist/dev/offline-gateway.js +102 -0
- package/dist/dev/trace-buffer.d.ts +61 -0
- package/dist/dev/trace-buffer.js +330 -0
- package/dist/dev/trace-security-headers.d.ts +11 -0
- package/dist/dev/trace-security-headers.js +16 -0
- package/dist/dev/trace-server.d.ts +8 -0
- package/dist/dev/trace-server.js +38 -0
- package/dist/dev/trace-ui.d.ts +4 -0
- package/dist/dev/trace-ui.js +25 -0
- package/dist/dev/wiremock-up.d.ts +15 -0
- package/dist/dev/wiremock-up.js +118 -0
- package/dist/doctor-completion.d.ts +17 -0
- package/dist/doctor-completion.js +428 -0
- package/dist/gateway-url.d.ts +7 -0
- package/dist/gateway-url.js +69 -0
- package/dist/index.d.ts +119 -2
- package/dist/index.js +267 -6
- package/dist/init.js +380 -68
- package/dist/langgraph/awrap-tool-call.d.ts +25 -0
- package/dist/langgraph/awrap-tool-call.js +81 -0
- package/dist/langgraph/config.d.ts +13 -0
- package/dist/langgraph/config.js +11 -0
- package/dist/langgraph/index.d.ts +4 -0
- package/dist/langgraph/index.js +4 -0
- package/dist/langgraph/sandbox-demo.d.ts +40 -0
- package/dist/langgraph/sandbox-demo.js +96 -0
- package/dist/langgraph/tool-node.d.ts +10 -0
- package/dist/langgraph/tool-node.js +38 -0
- package/dist/login.d.ts +14 -1
- package/dist/login.js +130 -63
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/tool-surface.d.ts +25 -0
- package/dist/mcp/tool-surface.js +17 -0
- package/dist/mcp-capability-token-cache.d.ts +24 -0
- package/dist/mcp-capability-token-cache.js +101 -0
- package/dist/mcp-evidence-policy.d.ts +48 -0
- package/dist/mcp-evidence-policy.js +117 -0
- package/dist/mcp-policy-reload.d.ts +79 -0
- package/dist/mcp-policy-reload.js +200 -0
- package/dist/mcp-sep2828-evidence.d.ts +36 -0
- package/dist/mcp-sep2828-evidence.js +65 -0
- package/dist/mcp-server.d.ts +10 -0
- package/dist/mcp-server.js +423 -115
- package/dist/openai-agents/index.d.ts +40 -0
- package/dist/openai-agents/index.js +151 -0
- package/dist/openai-agents/sandbox-demo.d.ts +34 -0
- package/dist/openai-agents/sandbox-demo.js +118 -0
- package/dist/payee-evidence.js +2 -29
- package/dist/policy/catalog.d.ts +31 -0
- package/dist/policy/catalog.js +48 -0
- package/dist/policy/compose-utils.d.ts +3 -0
- package/dist/policy/compose-utils.js +4 -0
- package/dist/policy/compose.d.ts +20 -0
- package/dist/policy/compose.js +240 -0
- package/dist/policy/digest.d.ts +7 -0
- package/dist/policy/digest.js +75 -0
- package/dist/policy/domain.d.ts +15 -0
- package/dist/policy/domain.js +28 -0
- package/dist/policy/guardrail-spec.d.ts +17 -0
- package/dist/policy/guardrail-spec.js +140 -0
- package/dist/policy/guardrails.d.ts +48 -0
- package/dist/policy/guardrails.js +72 -0
- package/dist/policy/index.d.ts +21 -0
- package/dist/policy/index.js +21 -0
- package/dist/policy/init.d.ts +102 -0
- package/dist/policy/init.js +351 -0
- package/dist/policy/intent-spec.d.ts +52 -0
- package/dist/policy/intent-spec.js +176 -0
- package/dist/policy/json-path.d.ts +4 -0
- package/dist/policy/json-path.js +23 -0
- package/dist/policy/layers-io.d.ts +7 -0
- package/dist/policy/layers-io.js +28 -0
- package/dist/policy/load-effective.d.ts +22 -0
- package/dist/policy/load-effective.js +77 -0
- package/dist/policy/load.d.ts +85 -0
- package/dist/policy/load.js +164 -0
- package/dist/policy/merge.d.ts +29 -0
- package/dist/policy/merge.js +297 -0
- package/dist/policy/parse-text.d.ts +2 -0
- package/dist/policy/parse-text.js +126 -0
- package/dist/policy/policy-api.d.ts +45 -0
- package/dist/policy/policy-api.js +61 -0
- package/dist/policy/presets.d.ts +19 -0
- package/dist/policy/presets.js +66 -0
- package/dist/policy/registry.d.ts +7 -0
- package/dist/policy/registry.js +33 -0
- package/dist/policy/reload.d.ts +86 -0
- package/dist/policy/reload.js +233 -0
- package/dist/policy/render-yaml.d.ts +3 -0
- package/dist/policy/render-yaml.js +69 -0
- package/dist/policy/sandbox-bootstrap.d.ts +19 -0
- package/dist/policy/sandbox-bootstrap.js +66 -0
- package/dist/policy/schema.d.ts +204 -0
- package/dist/policy/schema.js +255 -0
- package/dist/policy/snapshot.d.ts +33 -0
- package/dist/policy/snapshot.js +23 -0
- package/dist/policy/validate-remote.d.ts +43 -0
- package/dist/policy/validate-remote.js +104 -0
- package/dist/policy/validate.d.ts +36 -0
- package/dist/policy/validate.js +150 -0
- package/dist/policy/watcher.d.ts +29 -0
- package/dist/policy/watcher.js +112 -0
- package/dist/principal-intent.d.ts +52 -0
- package/dist/principal-intent.js +193 -37
- package/dist/project-init.d.ts +34 -0
- package/dist/project-init.js +898 -0
- package/dist/sep2828-signature.d.ts +10 -0
- package/dist/sep2828-signature.js +134 -0
- package/dist/solutions/api.d.ts +22 -0
- package/dist/solutions/api.js +40 -0
- package/dist/solutions/catalog.d.ts +34 -0
- package/dist/solutions/catalog.js +129 -0
- package/dist/solutions/index.d.ts +2 -0
- package/dist/solutions/index.js +2 -0
- package/dist/template-init.d.ts +54 -0
- package/dist/template-init.js +203 -0
- package/dist/vercel-ai/config.d.ts +15 -0
- package/dist/vercel-ai/config.js +13 -0
- package/dist/vercel-ai/index.d.ts +4 -0
- package/dist/vercel-ai/index.js +4 -0
- package/dist/vercel-ai/sandbox-demo.d.ts +44 -0
- package/dist/vercel-ai/sandbox-demo.js +153 -0
- package/dist/vercel-ai/tool-approval.d.ts +16 -0
- package/dist/vercel-ai/tool-approval.js +41 -0
- package/dist/vercel-ai/wrap-tools.d.ts +9 -0
- package/dist/vercel-ai/wrap-tools.js +40 -0
- package/dist/x402-receipt-evidence.d.ts +29 -0
- package/dist/x402-receipt-evidence.js +97 -0
- package/dist/x402-receipt-signature.d.ts +12 -0
- package/dist/x402-receipt-signature.js +211 -0
- package/package.json +79 -4
- package/solutions/aws.json +17 -0
- package/solutions/saas.json +17 -0
- package/solutions/shopping.json +17 -0
- package/solutions/travel.json +18 -0
- package/templates/manifest.json +169 -0
- package/templates/openai-shopping-agent/.env.example +3 -0
- package/templates/openai-shopping-agent/.github/workflows/smoke.yml +20 -0
- package/templates/openai-shopping-agent/LICENSE +201 -0
- package/templates/openai-shopping-agent/README.md +29 -0
- package/templates/openai-shopping-agent/package.json +22 -0
- package/templates/openai-shopping-agent/paybond.policy.yaml +22 -0
- package/templates/openai-shopping-agent/src/index.ts +22 -0
- package/templates/openai-shopping-agent/src/paybond.config.ts +51 -0
- package/templates/openai-shopping-agent/tsconfig.json +13 -0
- package/templates/paybond-aws-operator/.env.example +3 -0
- package/templates/paybond-aws-operator/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-aws-operator/LICENSE +201 -0
- package/templates/paybond-aws-operator/README.md +29 -0
- package/templates/paybond-aws-operator/package.json +20 -0
- package/templates/paybond-aws-operator/paybond.policy.yaml +22 -0
- package/templates/paybond-aws-operator/src/index.ts +54 -0
- package/templates/paybond-aws-operator/src/paybond.config.ts +51 -0
- package/templates/paybond-aws-operator/tsconfig.json +13 -0
- package/templates/paybond-claude-agents-demo/.env.example +3 -0
- package/templates/paybond-claude-agents-demo/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-claude-agents-demo/LICENSE +201 -0
- package/templates/paybond-claude-agents-demo/README.md +29 -0
- package/templates/paybond-claude-agents-demo/package.json +22 -0
- package/templates/paybond-claude-agents-demo/paybond.policy.yaml +22 -0
- package/templates/paybond-claude-agents-demo/src/index.ts +22 -0
- package/templates/paybond-claude-agents-demo/src/paybond.config.ts +51 -0
- package/templates/paybond-claude-agents-demo/tsconfig.json +13 -0
- package/templates/paybond-invoice-agent/.env.example +3 -0
- package/templates/paybond-invoice-agent/.github/workflows/smoke.yml +19 -0
- package/templates/paybond-invoice-agent/LICENSE +201 -0
- package/templates/paybond-invoice-agent/README.md +29 -0
- package/templates/paybond-invoice-agent/app.py +27 -0
- package/templates/paybond-invoice-agent/package.json +6 -0
- package/templates/paybond-invoice-agent/paybond.policy.yaml +22 -0
- package/templates/paybond-invoice-agent/paybond_config.py +45 -0
- package/templates/paybond-invoice-agent/requirements.txt +2 -0
- package/templates/paybond-mcp-coding-agent/.env.example +3 -0
- package/templates/paybond-mcp-coding-agent/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-mcp-coding-agent/LICENSE +201 -0
- package/templates/paybond-mcp-coding-agent/README.md +39 -0
- package/templates/paybond-mcp-coding-agent/package.json +20 -0
- package/templates/paybond-mcp-coding-agent/paybond.policy.yaml +25 -0
- package/templates/paybond-mcp-coding-agent/src/index.ts +40 -0
- package/templates/paybond-mcp-coding-agent/src/paybond.config.ts +51 -0
- package/templates/paybond-mcp-coding-agent/tsconfig.json +13 -0
- package/templates/paybond-openai-agents-demo/.env.example +3 -0
- package/templates/paybond-openai-agents-demo/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-openai-agents-demo/LICENSE +201 -0
- package/templates/paybond-openai-agents-demo/README.md +29 -0
- package/templates/paybond-openai-agents-demo/package.json +22 -0
- package/templates/paybond-openai-agents-demo/paybond.policy.yaml +22 -0
- package/templates/paybond-openai-agents-demo/src/index.ts +22 -0
- package/templates/paybond-openai-agents-demo/src/paybond.config.ts +51 -0
- package/templates/paybond-openai-agents-demo/tsconfig.json +13 -0
- package/templates/paybond-procurement-agent/.env.example +3 -0
- package/templates/paybond-procurement-agent/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-procurement-agent/LICENSE +201 -0
- package/templates/paybond-procurement-agent/README.md +29 -0
- package/templates/paybond-procurement-agent/package.json +20 -0
- package/templates/paybond-procurement-agent/paybond.policy.yaml +25 -0
- package/templates/paybond-procurement-agent/src/index.ts +54 -0
- package/templates/paybond-procurement-agent/src/paybond.config.ts +51 -0
- package/templates/paybond-procurement-agent/tsconfig.json +13 -0
- package/templates/paybond-travel-agent/.env.example +3 -0
- package/templates/paybond-travel-agent/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-travel-agent/LICENSE +201 -0
- package/templates/paybond-travel-agent/README.md +29 -0
- package/templates/paybond-travel-agent/package.json +23 -0
- package/templates/paybond-travel-agent/paybond.policy.yaml +22 -0
- package/templates/paybond-travel-agent/src/index.ts +22 -0
- package/templates/paybond-travel-agent/src/paybond.config.ts +51 -0
- package/templates/paybond-travel-agent/tsconfig.json +13 -0
- package/templates/paybond-vercel-shopping-agent/.env.example +3 -0
- package/templates/paybond-vercel-shopping-agent/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-vercel-shopping-agent/LICENSE +201 -0
- package/templates/paybond-vercel-shopping-agent/README.md +29 -0
- package/templates/paybond-vercel-shopping-agent/package.json +22 -0
- package/templates/paybond-vercel-shopping-agent/paybond.policy.yaml +22 -0
- package/templates/paybond-vercel-shopping-agent/src/index.ts +22 -0
- package/templates/paybond-vercel-shopping-agent/src/paybond.config.ts +51 -0
- package/templates/paybond-vercel-shopping-agent/tsconfig.json +13 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { cloneToolEntry } from "./compose-utils.js";
|
|
2
|
+
import { guardrailLayerFromDocument } from "./guardrails.js";
|
|
3
|
+
import { loadBundledDefaultGuardrailsDocument, loadBundledDomainDocument, } from "./layers-io.js";
|
|
4
|
+
import { parsePolicyDocumentText } from "./parse-text.js";
|
|
5
|
+
import { readPolicyPresetYaml, resolvePolicyPresetPath } from "./presets.js";
|
|
6
|
+
import { parsePaybondPolicyDocumentV1, } from "./schema.js";
|
|
7
|
+
export const LAYERED_POLICY_PRESET_IDS = ["travel", "shopping", "saas", "aws"];
|
|
8
|
+
function mergeStricterDefaultDeny(...values) {
|
|
9
|
+
return values.some((value) => value === true);
|
|
10
|
+
}
|
|
11
|
+
function cloneDocument(document) {
|
|
12
|
+
return {
|
|
13
|
+
...document,
|
|
14
|
+
tools: Object.fromEntries(Object.entries(document.tools).map(([name, entry]) => [name, cloneToolEntry(entry)])),
|
|
15
|
+
intent: document.intent
|
|
16
|
+
? {
|
|
17
|
+
...document.intent,
|
|
18
|
+
...(document.intent.allowed_tools
|
|
19
|
+
? { allowed_tools: [...document.intent.allowed_tools] }
|
|
20
|
+
: {}),
|
|
21
|
+
...(document.intent.budget ? { budget: { ...document.intent.budget } } : {}),
|
|
22
|
+
...(document.intent.policy_binding
|
|
23
|
+
? { policy_binding: { ...document.intent.policy_binding } }
|
|
24
|
+
: {}),
|
|
25
|
+
}
|
|
26
|
+
: undefined,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function mergeToolEntry(base, patch) {
|
|
30
|
+
const merged = cloneToolEntry(base);
|
|
31
|
+
if (patch.side_effecting !== undefined) {
|
|
32
|
+
merged.side_effecting = patch.side_effecting;
|
|
33
|
+
}
|
|
34
|
+
if (patch.max_spend_cents !== undefined) {
|
|
35
|
+
merged.max_spend_cents =
|
|
36
|
+
merged.max_spend_cents !== undefined
|
|
37
|
+
? Math.min(merged.max_spend_cents, patch.max_spend_cents)
|
|
38
|
+
: patch.max_spend_cents;
|
|
39
|
+
}
|
|
40
|
+
if (patch.spend_from_args !== undefined) {
|
|
41
|
+
merged.spend_from_args = patch.spend_from_args;
|
|
42
|
+
delete merged.max_spend_cents;
|
|
43
|
+
}
|
|
44
|
+
if (patch.evidence_preset !== undefined) {
|
|
45
|
+
merged.evidence_preset = patch.evidence_preset;
|
|
46
|
+
}
|
|
47
|
+
if (patch.vendor_pack !== undefined) {
|
|
48
|
+
merged.vendor_pack = patch.vendor_pack;
|
|
49
|
+
}
|
|
50
|
+
if (patch.operation !== undefined) {
|
|
51
|
+
merged.operation = patch.operation;
|
|
52
|
+
}
|
|
53
|
+
return merged;
|
|
54
|
+
}
|
|
55
|
+
function mergeBudgetCaps(current, nextUsd) {
|
|
56
|
+
const currency = current?.currency ?? "usd";
|
|
57
|
+
const currentUsd = current?.max_spend_usd;
|
|
58
|
+
return {
|
|
59
|
+
...current,
|
|
60
|
+
currency,
|
|
61
|
+
max_spend_usd: currentUsd !== undefined ? Math.min(currentUsd, nextUsd) : nextUsd,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function applyReadOnlyFilter(document, searchOnly) {
|
|
65
|
+
const filteredEntries = Object.entries(document.tools).filter(([name, entry]) => {
|
|
66
|
+
if (entry.side_effecting) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return !searchOnly || name.startsWith("search.");
|
|
70
|
+
});
|
|
71
|
+
document.tools = Object.fromEntries(filteredEntries);
|
|
72
|
+
if (document.intent?.allowed_tools) {
|
|
73
|
+
const allowed = new Set(Object.keys(document.tools));
|
|
74
|
+
document.intent.allowed_tools = document.intent.allowed_tools.filter((tool) => allowed.has(tool));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function assertEvidenceRequired(document) {
|
|
78
|
+
for (const [name, entry] of Object.entries(document.tools)) {
|
|
79
|
+
if (entry.side_effecting && !entry.evidence_preset) {
|
|
80
|
+
throw new Error(`side-effecting tool "${name}" must declare evidence_preset`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function applyGuardrailLayer(document, layer) {
|
|
85
|
+
if (layer.default_deny !== undefined) {
|
|
86
|
+
document.default_deny = mergeStricterDefaultDeny(document.default_deny, layer.default_deny);
|
|
87
|
+
}
|
|
88
|
+
if (layer.tools) {
|
|
89
|
+
for (const [toolName, patch] of Object.entries(layer.tools)) {
|
|
90
|
+
const existing = document.tools[toolName];
|
|
91
|
+
if (existing) {
|
|
92
|
+
document.tools[toolName] = mergeToolEntry(existing, patch);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (layer.intent) {
|
|
97
|
+
document.intent = {
|
|
98
|
+
...document.intent,
|
|
99
|
+
...layer.intent,
|
|
100
|
+
...(layer.intent.allowed_tools
|
|
101
|
+
? {
|
|
102
|
+
allowed_tools: layer.intent.allowed_tools,
|
|
103
|
+
}
|
|
104
|
+
: {}),
|
|
105
|
+
...(layer.intent.budget
|
|
106
|
+
? {
|
|
107
|
+
budget: {
|
|
108
|
+
...document.intent?.budget,
|
|
109
|
+
...layer.intent.budget,
|
|
110
|
+
},
|
|
111
|
+
}
|
|
112
|
+
: {}),
|
|
113
|
+
...(layer.intent.policy_binding
|
|
114
|
+
? {
|
|
115
|
+
policy_binding: {
|
|
116
|
+
...document.intent?.policy_binding,
|
|
117
|
+
...layer.intent.policy_binding,
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
: {}),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (layer.caps?.sideEffectingMaxSpendCents !== undefined) {
|
|
124
|
+
const cents = layer.caps.sideEffectingMaxSpendCents;
|
|
125
|
+
for (const [toolName, entry] of Object.entries(document.tools)) {
|
|
126
|
+
if (entry.side_effecting) {
|
|
127
|
+
document.tools[toolName] = mergeToolEntry(entry, { max_spend_cents: cents });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (layer.caps?.budgetMaxSpendUsd !== undefined) {
|
|
132
|
+
document.intent = {
|
|
133
|
+
...document.intent,
|
|
134
|
+
budget: mergeBudgetCaps(document.intent?.budget, layer.caps.budgetMaxSpendUsd),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if (layer.filters?.readOnly || layer.filters?.readOnlySearch) {
|
|
138
|
+
applyReadOnlyFilter(document, Boolean(layer.filters.readOnlySearch));
|
|
139
|
+
}
|
|
140
|
+
if (layer.requireEvidence) {
|
|
141
|
+
assertEvidenceRequired(document);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** Stack a domain document with one or more guardrail layers (same-tenant compose, not org inheritance). */
|
|
145
|
+
export function composePolicyLayers(domainDocument, ...layers) {
|
|
146
|
+
const composed = cloneDocument(domainDocument);
|
|
147
|
+
for (const layer of layers) {
|
|
148
|
+
applyGuardrailLayer(composed, layer);
|
|
149
|
+
}
|
|
150
|
+
assertEvidenceRequired(composed);
|
|
151
|
+
return composed;
|
|
152
|
+
}
|
|
153
|
+
/** True when a bundled preset is composed from domain + guardrails layers. */
|
|
154
|
+
export function isLayeredPolicyPreset(presetId) {
|
|
155
|
+
return LAYERED_POLICY_PRESET_IDS.includes(presetId.trim());
|
|
156
|
+
}
|
|
157
|
+
function guardrailsFileName(presetId) {
|
|
158
|
+
return `default-${presetId}.yaml`;
|
|
159
|
+
}
|
|
160
|
+
function deepMergeRecord(base, patch) {
|
|
161
|
+
const result = { ...base };
|
|
162
|
+
for (const [key, patchValue] of Object.entries(patch)) {
|
|
163
|
+
const baseValue = result[key];
|
|
164
|
+
if (baseValue &&
|
|
165
|
+
patchValue &&
|
|
166
|
+
typeof baseValue === "object" &&
|
|
167
|
+
typeof patchValue === "object" &&
|
|
168
|
+
!Array.isArray(baseValue) &&
|
|
169
|
+
!Array.isArray(patchValue)) {
|
|
170
|
+
result[key] = deepMergeRecord(baseValue, patchValue);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
result[key] = patchValue;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
178
|
+
/** Merge domain and guardrail YAML objects (bundled preset file generation). */
|
|
179
|
+
export function composePolicyPresetLayers(domain, guardrails) {
|
|
180
|
+
return deepMergeRecord(domain, guardrails);
|
|
181
|
+
}
|
|
182
|
+
/** Default bundled guardrail layers for a vertical preset id. */
|
|
183
|
+
export function bundledDefaultGuardrails(presetId) {
|
|
184
|
+
return [guardrailLayerFromDocument(loadBundledDefaultGuardrailsDocument(presetId))];
|
|
185
|
+
}
|
|
186
|
+
/** Compose the shipped default for a vertical preset (domain + bundled guardrails). */
|
|
187
|
+
export function composeBundledPresetDefault(presetId) {
|
|
188
|
+
return composePolicyLayers(parsePaybondPolicyDocumentV1(loadBundledDomainDocument(presetId)), ...bundledDefaultGuardrails(presetId));
|
|
189
|
+
}
|
|
190
|
+
/** Load and compose a layered vertical preset (domain + guardrails YAML files). */
|
|
191
|
+
export function composeLayeredPolicyPresetDocument(presetId) {
|
|
192
|
+
const domain = loadBundledDomainDocument(presetId);
|
|
193
|
+
const guardrails = loadBundledDefaultGuardrailsDocument(presetId);
|
|
194
|
+
return composePolicyPresetLayers(domain, guardrails);
|
|
195
|
+
}
|
|
196
|
+
/** Compare composed layered presets with bundled flat preset files (tests). */
|
|
197
|
+
export function assertLayeredPresetMatchesFlat(presetId) {
|
|
198
|
+
if (!isLayeredPolicyPreset(presetId)) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const composed = composeLayeredPolicyPresetDocument(presetId);
|
|
202
|
+
const flatPath = resolvePolicyPresetPath(presetId);
|
|
203
|
+
const flat = parsePolicyDocumentText(readPolicyPresetYaml(presetId), flatPath);
|
|
204
|
+
if (JSON.stringify(normalizePolicyPresetDocument(composed)) !==
|
|
205
|
+
JSON.stringify(normalizePolicyPresetDocument(flat))) {
|
|
206
|
+
throw new Error(`composed preset ${presetId} does not match flat bundled file`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function normalizePolicyPresetDocument(document) {
|
|
210
|
+
const tools = document.tools;
|
|
211
|
+
const normalizedTools = tools && typeof tools === "object" && !Array.isArray(tools)
|
|
212
|
+
? Object.fromEntries(Object.entries(tools)
|
|
213
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
214
|
+
.map(([name, entry]) => [
|
|
215
|
+
name,
|
|
216
|
+
entry && typeof entry === "object" && !Array.isArray(entry)
|
|
217
|
+
? Object.fromEntries(Object.entries(entry).sort(([left], [right]) => left.localeCompare(right)))
|
|
218
|
+
: entry,
|
|
219
|
+
]))
|
|
220
|
+
: tools;
|
|
221
|
+
const intent = document.intent;
|
|
222
|
+
const normalizedIntent = intent && typeof intent === "object" && !Array.isArray(intent)
|
|
223
|
+
? {
|
|
224
|
+
...intent,
|
|
225
|
+
...(Array.isArray(intent.allowed_tools)
|
|
226
|
+
? {
|
|
227
|
+
allowed_tools: [
|
|
228
|
+
...intent.allowed_tools,
|
|
229
|
+
].sort(),
|
|
230
|
+
}
|
|
231
|
+
: {}),
|
|
232
|
+
}
|
|
233
|
+
: intent;
|
|
234
|
+
return {
|
|
235
|
+
...document,
|
|
236
|
+
...(normalizedTools !== undefined ? { tools: normalizedTools } : {}),
|
|
237
|
+
...(normalizedIntent !== undefined ? { intent: normalizedIntent } : {}),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
export { readPresetLayerYaml } from "./layers-io.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PaybondPolicyDocumentV1 } from "./schema.js";
|
|
2
|
+
/** Serialize a validated v1 policy document to Gateway-compatible JSON dict form. */
|
|
3
|
+
export declare function policyDocumentToDict(document: PaybondPolicyDocumentV1): Record<string, unknown>;
|
|
4
|
+
/** Return `sha256:<hex>` for the canonical JSON encoding of a v1 policy document. */
|
|
5
|
+
export declare function canonicalPolicyDocumentDigest(document: PaybondPolicyDocumentV1): string;
|
|
6
|
+
/** Human-readable policy version label (`{name}@{digest_short}`). */
|
|
7
|
+
export declare function policyVersionLabel(name: string, digest: string): string;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/** Serialize a validated v1 policy document to Gateway-compatible JSON dict form. */
|
|
3
|
+
export function policyDocumentToDict(document) {
|
|
4
|
+
const tools = Object.fromEntries(Object.entries(document.tools).map(([toolName, entry]) => [
|
|
5
|
+
toolName,
|
|
6
|
+
{
|
|
7
|
+
side_effecting: entry.side_effecting,
|
|
8
|
+
...(entry.max_spend_cents !== undefined ? { max_spend_cents: entry.max_spend_cents } : {}),
|
|
9
|
+
...(entry.spend_from_args !== undefined ? { spend_from_args: entry.spend_from_args } : {}),
|
|
10
|
+
...(entry.evidence_preset !== undefined ? { evidence_preset: entry.evidence_preset } : {}),
|
|
11
|
+
...(entry.vendor_pack !== undefined ? { vendor_pack: entry.vendor_pack } : {}),
|
|
12
|
+
...(entry.operation !== undefined ? { operation: entry.operation } : {}),
|
|
13
|
+
},
|
|
14
|
+
]));
|
|
15
|
+
const payload = {
|
|
16
|
+
version: document.version,
|
|
17
|
+
name: document.name,
|
|
18
|
+
default_deny: document.default_deny,
|
|
19
|
+
tools,
|
|
20
|
+
};
|
|
21
|
+
if (document.intent) {
|
|
22
|
+
const intent = {};
|
|
23
|
+
if (document.intent.policy_binding) {
|
|
24
|
+
const binding = {
|
|
25
|
+
template_id: document.intent.policy_binding.template_id,
|
|
26
|
+
};
|
|
27
|
+
if (document.intent.policy_binding.version_seq !== undefined) {
|
|
28
|
+
binding.version_seq = document.intent.policy_binding.version_seq;
|
|
29
|
+
}
|
|
30
|
+
if (document.intent.policy_binding.head_digest !== undefined) {
|
|
31
|
+
binding.head_digest = document.intent.policy_binding.head_digest;
|
|
32
|
+
}
|
|
33
|
+
intent.policy_binding = binding;
|
|
34
|
+
}
|
|
35
|
+
if (document.intent.budget) {
|
|
36
|
+
intent.budget = document.intent.budget;
|
|
37
|
+
}
|
|
38
|
+
if (document.intent.allowed_tools?.length) {
|
|
39
|
+
intent.allowed_tools = document.intent.allowed_tools;
|
|
40
|
+
}
|
|
41
|
+
if (Object.keys(intent).length > 0) {
|
|
42
|
+
payload.intent = intent;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return payload;
|
|
46
|
+
}
|
|
47
|
+
function canonicalizeJson(value) {
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
return value.map(canonicalizeJson);
|
|
50
|
+
}
|
|
51
|
+
if (value && typeof value === "object") {
|
|
52
|
+
const row = value;
|
|
53
|
+
const out = {};
|
|
54
|
+
for (const key of Object.keys(row).sort()) {
|
|
55
|
+
out[key] = canonicalizeJson(row[key]);
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
/** Return `sha256:<hex>` for the canonical JSON encoding of a v1 policy document. */
|
|
62
|
+
export function canonicalPolicyDocumentDigest(document) {
|
|
63
|
+
const wire = policyDocumentToDict(document);
|
|
64
|
+
const text = JSON.stringify(canonicalizeJson(wire));
|
|
65
|
+
const hash = createHash("sha256").update(text, "utf8").digest("hex");
|
|
66
|
+
return `sha256:${hash}`;
|
|
67
|
+
}
|
|
68
|
+
/** Human-readable policy version label (`{name}@{digest_short}`). */
|
|
69
|
+
export function policyVersionLabel(name, digest) {
|
|
70
|
+
const trimmed = digest.trim();
|
|
71
|
+
const short = trimmed.startsWith("sha256:") && trimmed.length >= 15
|
|
72
|
+
? trimmed.slice(7, 15)
|
|
73
|
+
: trimmed.slice(0, 8);
|
|
74
|
+
return `${name}@${short}`;
|
|
75
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type PaybondPolicyDocumentV1 } from "./schema.js";
|
|
2
|
+
/** Travel booking domain: hotel booking + read-only web search. */
|
|
3
|
+
export declare function travel(): PaybondPolicyDocumentV1;
|
|
4
|
+
/** Shopping domain: checkout + product search. */
|
|
5
|
+
export declare function shopping(): PaybondPolicyDocumentV1;
|
|
6
|
+
/** SaaS domain: seat provisioning + plan listing. */
|
|
7
|
+
export declare function saas(): PaybondPolicyDocumentV1;
|
|
8
|
+
/** AWS operator domain: EC2 start + describe. */
|
|
9
|
+
export declare function aws(): PaybondPolicyDocumentV1;
|
|
10
|
+
export declare const domain: {
|
|
11
|
+
readonly travel: typeof travel;
|
|
12
|
+
readonly shopping: typeof shopping;
|
|
13
|
+
readonly saas: typeof saas;
|
|
14
|
+
readonly aws: typeof aws;
|
|
15
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { parsePaybondPolicyDocumentV1, } from "./schema.js";
|
|
2
|
+
import { loadBundledDomainDocument } from "./layers-io.js";
|
|
3
|
+
const LAYERED_POLICY_PRESET_IDS = ["travel", "shopping", "saas", "aws"];
|
|
4
|
+
function loadDomain(presetId) {
|
|
5
|
+
return parsePaybondPolicyDocumentV1(loadBundledDomainDocument(presetId));
|
|
6
|
+
}
|
|
7
|
+
/** Travel booking domain: hotel booking + read-only web search. */
|
|
8
|
+
export function travel() {
|
|
9
|
+
return loadDomain("travel");
|
|
10
|
+
}
|
|
11
|
+
/** Shopping domain: checkout + product search. */
|
|
12
|
+
export function shopping() {
|
|
13
|
+
return loadDomain("shopping");
|
|
14
|
+
}
|
|
15
|
+
/** SaaS domain: seat provisioning + plan listing. */
|
|
16
|
+
export function saas() {
|
|
17
|
+
return loadDomain("saas");
|
|
18
|
+
}
|
|
19
|
+
/** AWS operator domain: EC2 start + describe. */
|
|
20
|
+
export function aws() {
|
|
21
|
+
return loadDomain("aws");
|
|
22
|
+
}
|
|
23
|
+
export const domain = {
|
|
24
|
+
travel,
|
|
25
|
+
shopping,
|
|
26
|
+
saas,
|
|
27
|
+
aws,
|
|
28
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { guardrails, type PolicyGuardrailLayer } from "./guardrails.js";
|
|
2
|
+
export type GuardrailCatalogEntry = {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
parameterized?: boolean;
|
|
7
|
+
};
|
|
8
|
+
/** Built-in guardrail ids accepted by `policy init --guardrails` and solution manifests. */
|
|
9
|
+
export declare const GUARDRAIL_CATALOG_ENTRIES: GuardrailCatalogEntry[];
|
|
10
|
+
/** Resolve a solution-manifest guardrail token (for example `max_spend_usd_200`). */
|
|
11
|
+
export declare function resolveGuardrailManifestToken(token: string): PolicyGuardrailLayer;
|
|
12
|
+
/** Parse one guardrail token from CLI `--guardrails` or solution manifests. */
|
|
13
|
+
export declare function parseGuardrailSpec(spec: string): PolicyGuardrailLayer;
|
|
14
|
+
/** Parse a comma-separated guardrail spec list from CLI flags. */
|
|
15
|
+
export declare function parseGuardrailSpecs(csv: string): PolicyGuardrailLayer[];
|
|
16
|
+
export declare function listGuardrailCatalogEntries(): GuardrailCatalogEntry[];
|
|
17
|
+
export { guardrails };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { auditOnly, allowDryRun, defaultDeny, guardrails, maxSpend, maxSpendUsd, readOnly, readOnlySearch, requireEvidence, strict, } from "./guardrails.js";
|
|
2
|
+
/** Built-in guardrail ids accepted by `policy init --guardrails` and solution manifests. */
|
|
3
|
+
export const GUARDRAIL_CATALOG_ENTRIES = [
|
|
4
|
+
{
|
|
5
|
+
id: "default-deny",
|
|
6
|
+
title: "Default deny",
|
|
7
|
+
description: "Require explicit tool registration (default_deny: true)",
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
id: "read-only",
|
|
11
|
+
title: "Read only",
|
|
12
|
+
description: "Keep only non-side-effecting tools",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: "read-only-search",
|
|
16
|
+
title: "Read-only search",
|
|
17
|
+
description: "Keep only non-side-effecting search.* tools",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "strict",
|
|
21
|
+
title: "Strict",
|
|
22
|
+
description: "Tight caps, default deny, and evidence required on side-effecting tools",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "require-evidence",
|
|
26
|
+
title: "Require evidence",
|
|
27
|
+
description: "Validate evidence_preset on side-effecting tools at compose time",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: "audit-only",
|
|
31
|
+
title: "Audit only",
|
|
32
|
+
description: "Reserved governance hook (no-op layer today)",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "allow-dry-run",
|
|
36
|
+
title: "Allow dry run",
|
|
37
|
+
description: "Reserved governance hook (no-op layer today)",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "max-spend:<usd>",
|
|
41
|
+
title: "Max spend (USD)",
|
|
42
|
+
description: "Cap intent budget and side-effecting tool spend (USD parameter)",
|
|
43
|
+
parameterized: true,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "max-spend-cents:<cents>",
|
|
47
|
+
title: "Max spend (cents)",
|
|
48
|
+
description: "Cap side-effecting tool spend in cents",
|
|
49
|
+
parameterized: true,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "max-spend-usd:<usd>",
|
|
53
|
+
title: "Max spend budget (USD)",
|
|
54
|
+
description: "Cap intent budget max_spend_usd only",
|
|
55
|
+
parameterized: true,
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
function normalizeGuardrailToken(token) {
|
|
59
|
+
return token.trim().toLowerCase().replace(/_/g, "-");
|
|
60
|
+
}
|
|
61
|
+
function parsePositiveNumber(raw, label) {
|
|
62
|
+
const value = Number(raw);
|
|
63
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
64
|
+
throw new Error(`${label} requires a non-negative number`);
|
|
65
|
+
}
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
/** Resolve a solution-manifest guardrail token (for example `max_spend_usd_200`). */
|
|
69
|
+
export function resolveGuardrailManifestToken(token) {
|
|
70
|
+
const trimmed = token.trim();
|
|
71
|
+
const manifestUsd = /^max_spend_usd_(\d+(?:\.\d+)?)$/i.exec(trimmed);
|
|
72
|
+
if (manifestUsd) {
|
|
73
|
+
return maxSpendUsd(parsePositiveNumber(manifestUsd[1], "max_spend_usd"));
|
|
74
|
+
}
|
|
75
|
+
return parseGuardrailSpec(trimmed);
|
|
76
|
+
}
|
|
77
|
+
/** Parse one guardrail token from CLI `--guardrails` or solution manifests. */
|
|
78
|
+
export function parseGuardrailSpec(spec) {
|
|
79
|
+
const normalized = normalizeGuardrailToken(spec);
|
|
80
|
+
if (!normalized) {
|
|
81
|
+
throw new Error("guardrail spec must not be empty");
|
|
82
|
+
}
|
|
83
|
+
const maxSpendMatch = /^max-spend:(\d+(?:\.\d+)?)$/.exec(normalized);
|
|
84
|
+
if (maxSpendMatch) {
|
|
85
|
+
const usd = parsePositiveNumber(maxSpendMatch[1], "max-spend");
|
|
86
|
+
return {
|
|
87
|
+
caps: {
|
|
88
|
+
budgetMaxSpendUsd: usd,
|
|
89
|
+
sideEffectingMaxSpendCents: Math.round(usd * 100),
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const maxSpendUsdMatch = /^max-spend-usd:(\d+(?:\.\d+)?)$/.exec(normalized);
|
|
94
|
+
if (maxSpendUsdMatch) {
|
|
95
|
+
return maxSpendUsd(parsePositiveNumber(maxSpendUsdMatch[1], "max-spend-usd"));
|
|
96
|
+
}
|
|
97
|
+
const maxSpendCentsMatch = /^max-spend-cents:(\d+)$/.exec(normalized);
|
|
98
|
+
if (maxSpendCentsMatch) {
|
|
99
|
+
return maxSpend(parsePositiveNumber(maxSpendCentsMatch[1], "max-spend-cents"));
|
|
100
|
+
}
|
|
101
|
+
switch (normalized) {
|
|
102
|
+
case "default-deny":
|
|
103
|
+
case "defaultdeny":
|
|
104
|
+
return defaultDeny();
|
|
105
|
+
case "read-only":
|
|
106
|
+
case "readonly":
|
|
107
|
+
return readOnly();
|
|
108
|
+
case "read-only-search":
|
|
109
|
+
case "readonlysearch":
|
|
110
|
+
return readOnlySearch();
|
|
111
|
+
case "strict":
|
|
112
|
+
return strict();
|
|
113
|
+
case "require-evidence":
|
|
114
|
+
case "requireevidence":
|
|
115
|
+
return requireEvidence();
|
|
116
|
+
case "audit-only":
|
|
117
|
+
case "auditonly":
|
|
118
|
+
return auditOnly();
|
|
119
|
+
case "allow-dry-run":
|
|
120
|
+
case "allowdryrun":
|
|
121
|
+
return allowDryRun();
|
|
122
|
+
default:
|
|
123
|
+
throw new Error(`unknown guardrail: ${spec}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** Parse a comma-separated guardrail spec list from CLI flags. */
|
|
127
|
+
export function parseGuardrailSpecs(csv) {
|
|
128
|
+
const tokens = csv
|
|
129
|
+
.split(",")
|
|
130
|
+
.map((token) => token.trim())
|
|
131
|
+
.filter((token) => token.length > 0);
|
|
132
|
+
if (tokens.length === 0) {
|
|
133
|
+
throw new Error("guardrails list must include at least one entry");
|
|
134
|
+
}
|
|
135
|
+
return tokens.map((token) => parseGuardrailSpec(token));
|
|
136
|
+
}
|
|
137
|
+
export function listGuardrailCatalogEntries() {
|
|
138
|
+
return [...GUARDRAIL_CATALOG_ENTRIES];
|
|
139
|
+
}
|
|
140
|
+
export { guardrails };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { PaybondPolicyIntentSection, PaybondPolicyToolEntry } from "./schema.js";
|
|
2
|
+
/** Partial policy patch applied on top of a domain document during compose. */
|
|
3
|
+
export type PolicyGuardrailLayer = {
|
|
4
|
+
default_deny?: boolean;
|
|
5
|
+
tools?: Record<string, Partial<PaybondPolicyToolEntry>>;
|
|
6
|
+
intent?: Partial<PaybondPolicyIntentSection>;
|
|
7
|
+
filters?: {
|
|
8
|
+
readOnly?: boolean;
|
|
9
|
+
readOnlySearch?: boolean;
|
|
10
|
+
};
|
|
11
|
+
caps?: {
|
|
12
|
+
sideEffectingMaxSpendCents?: number;
|
|
13
|
+
budgetMaxSpendUsd?: number;
|
|
14
|
+
};
|
|
15
|
+
requireEvidence?: boolean;
|
|
16
|
+
};
|
|
17
|
+
/** Require `default_deny: true` (stricter wins when stacked). */
|
|
18
|
+
export declare function defaultDeny(): PolicyGuardrailLayer;
|
|
19
|
+
/** Cap every side-effecting tool at `cents` (stricter min wins when stacked). */
|
|
20
|
+
export declare function maxSpend(cents: number): PolicyGuardrailLayer;
|
|
21
|
+
/** Cap intent budget at `usd` dollars (stricter min wins when stacked). */
|
|
22
|
+
export declare function maxSpendUsd(usd: number): PolicyGuardrailLayer;
|
|
23
|
+
/** Keep only non-side-effecting tools and intersect allowed_tools. */
|
|
24
|
+
export declare function readOnly(): PolicyGuardrailLayer;
|
|
25
|
+
/** Keep only non-side-effecting search.* tools. */
|
|
26
|
+
export declare function readOnlySearch(): PolicyGuardrailLayer;
|
|
27
|
+
/** Tight caps, default deny, and evidence required on side-effecting tools. */
|
|
28
|
+
export declare function strict(): PolicyGuardrailLayer;
|
|
29
|
+
/** Governance hook: validate evidence presets at compose time (no extra fields). */
|
|
30
|
+
export declare function requireEvidence(): PolicyGuardrailLayer;
|
|
31
|
+
/** Governance hook reserved for audit-only execution modes (no-op layer today). */
|
|
32
|
+
export declare function auditOnly(): PolicyGuardrailLayer;
|
|
33
|
+
/** Governance hook reserved for dry-run modes (no-op layer today). */
|
|
34
|
+
export declare function allowDryRun(): PolicyGuardrailLayer;
|
|
35
|
+
/** Convert a bundled guardrails YAML object into a compose layer. */
|
|
36
|
+
export declare function guardrailLayerFromDocument(document: Record<string, unknown>): PolicyGuardrailLayer;
|
|
37
|
+
export declare const guardrails: {
|
|
38
|
+
readonly defaultDeny: typeof defaultDeny;
|
|
39
|
+
readonly maxSpend: typeof maxSpend;
|
|
40
|
+
readonly maxSpendUsd: typeof maxSpendUsd;
|
|
41
|
+
readonly readOnly: typeof readOnly;
|
|
42
|
+
readonly readOnlySearch: typeof readOnlySearch;
|
|
43
|
+
readonly strict: typeof strict;
|
|
44
|
+
readonly requireEvidence: typeof requireEvidence;
|
|
45
|
+
readonly auditOnly: typeof auditOnly;
|
|
46
|
+
readonly allowDryRun: typeof allowDryRun;
|
|
47
|
+
readonly fromDocument: typeof guardrailLayerFromDocument;
|
|
48
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** Require `default_deny: true` (stricter wins when stacked). */
|
|
2
|
+
export function defaultDeny() {
|
|
3
|
+
return { default_deny: true };
|
|
4
|
+
}
|
|
5
|
+
/** Cap every side-effecting tool at `cents` (stricter min wins when stacked). */
|
|
6
|
+
export function maxSpend(cents) {
|
|
7
|
+
if (!Number.isInteger(cents) || cents < 0) {
|
|
8
|
+
throw new Error("maxSpend requires a non-negative integer cents value");
|
|
9
|
+
}
|
|
10
|
+
return { caps: { sideEffectingMaxSpendCents: cents } };
|
|
11
|
+
}
|
|
12
|
+
/** Cap intent budget at `usd` dollars (stricter min wins when stacked). */
|
|
13
|
+
export function maxSpendUsd(usd) {
|
|
14
|
+
if (typeof usd !== "number" || usd < 0 || !Number.isFinite(usd)) {
|
|
15
|
+
throw new Error("maxSpendUsd requires a non-negative finite USD value");
|
|
16
|
+
}
|
|
17
|
+
return { caps: { budgetMaxSpendUsd: usd } };
|
|
18
|
+
}
|
|
19
|
+
/** Keep only non-side-effecting tools and intersect allowed_tools. */
|
|
20
|
+
export function readOnly() {
|
|
21
|
+
return { filters: { readOnly: true } };
|
|
22
|
+
}
|
|
23
|
+
/** Keep only non-side-effecting search.* tools. */
|
|
24
|
+
export function readOnlySearch() {
|
|
25
|
+
return { filters: { readOnlySearch: true } };
|
|
26
|
+
}
|
|
27
|
+
/** Tight caps, default deny, and evidence required on side-effecting tools. */
|
|
28
|
+
export function strict() {
|
|
29
|
+
return {
|
|
30
|
+
default_deny: true,
|
|
31
|
+
caps: { sideEffectingMaxSpendCents: 1000, budgetMaxSpendUsd: 10 },
|
|
32
|
+
requireEvidence: true,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Governance hook: validate evidence presets at compose time (no extra fields). */
|
|
36
|
+
export function requireEvidence() {
|
|
37
|
+
return { requireEvidence: true };
|
|
38
|
+
}
|
|
39
|
+
/** Governance hook reserved for audit-only execution modes (no-op layer today). */
|
|
40
|
+
export function auditOnly() {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
/** Governance hook reserved for dry-run modes (no-op layer today). */
|
|
44
|
+
export function allowDryRun() {
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
/** Convert a bundled guardrails YAML object into a compose layer. */
|
|
48
|
+
export function guardrailLayerFromDocument(document) {
|
|
49
|
+
const layer = {};
|
|
50
|
+
if (document.default_deny === true) {
|
|
51
|
+
layer.default_deny = true;
|
|
52
|
+
}
|
|
53
|
+
if (document.tools && typeof document.tools === "object" && !Array.isArray(document.tools)) {
|
|
54
|
+
layer.tools = document.tools;
|
|
55
|
+
}
|
|
56
|
+
if (document.intent && typeof document.intent === "object" && !Array.isArray(document.intent)) {
|
|
57
|
+
layer.intent = document.intent;
|
|
58
|
+
}
|
|
59
|
+
return layer;
|
|
60
|
+
}
|
|
61
|
+
export const guardrails = {
|
|
62
|
+
defaultDeny,
|
|
63
|
+
maxSpend,
|
|
64
|
+
maxSpendUsd,
|
|
65
|
+
readOnly,
|
|
66
|
+
readOnlySearch,
|
|
67
|
+
strict,
|
|
68
|
+
requireEvidence,
|
|
69
|
+
auditOnly,
|
|
70
|
+
allowDryRun,
|
|
71
|
+
fromDocument: guardrailLayerFromDocument,
|
|
72
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { canonicalPolicyDocumentDigest, policyDocumentToDict, policyVersionLabel, } from "./digest.js";
|
|
2
|
+
export { PaybondPolicy, type PaybondPolicyLoadSource, type PaybondPolicyLoadEffectiveResult } from "./load.js";
|
|
3
|
+
export { isKnownPolicyPresetId, isLayeredPolicyPresetId, listPolicyPresetIds, readPolicyPresetYaml, resolveComposedPresetDocument, resolvePolicyPresetPath, type LayeredPolicyPresetId, type PolicyPresetId, } from "./presets.js";
|
|
4
|
+
export { assertLayeredPresetMatchesFlat, bundledDefaultGuardrails, composeBundledPresetDefault, composeLayeredPolicyPresetDocument, composePolicyLayers, composePolicyPresetLayers, isLayeredPolicyPreset, LAYERED_POLICY_PRESET_IDS, } from "./compose.js";
|
|
5
|
+
export { domain } from "./domain.js";
|
|
6
|
+
export { auditOnly, allowDryRun, defaultDeny, guardrailLayerFromDocument, guardrails, maxSpend, maxSpendUsd, readOnly, readOnlySearch, requireEvidence, strict, type PolicyGuardrailLayer, } from "./guardrails.js";
|
|
7
|
+
export { paybondPolicyPresets, type PaybondPolicyPresets, type VerticalPolicyOptions } from "./policy-api.js";
|
|
8
|
+
export { createPolicySnapshot, createPolicySnapshotFromEffective, type CreatePolicySnapshotInput, type PaybondPolicySnapshot, type PaybondPolicySnapshotSource, } from "./snapshot.js";
|
|
9
|
+
export { parsePolicyExtendsRef, renderOrgBasePolicyYaml, renderPaybondPolicyYaml, renderTenantOverlayPolicyYaml, scaffoldOrgBasePolicy, scaffoldPaybondPolicy, scaffoldPolicyFromPreset, scaffoldTenantOverlayPolicy, type ScaffoldOrgBasePolicyOptions, type ScaffoldPaybondPolicyOptions, type ScaffoldPolicyFromPresetOptions, type ScaffoldTenantOverlayPolicyOptions, } from "./init.js";
|
|
10
|
+
export { PaybondPolicyIntentSpecError, policyToIntentCreateInput, type PaybondPolicyIntentCreateInput, type PaybondPolicyIntentCreateOverrides, } from "./intent-spec.js";
|
|
11
|
+
export { PaybondPolicySandboxBootstrapError, policySandboxBootstrap, type PaybondPolicySandboxBootstrapOptions, } from "./sandbox-bootstrap.js";
|
|
12
|
+
export { resolveJsonPath, resolveSpendCentsFromJsonPath } from "./json-path.js";
|
|
13
|
+
export { parsePolicyDocumentText } from "./parse-text.js";
|
|
14
|
+
export { policyDocumentToToolRegistryConfig, policyToToolRegistry, } from "./registry.js";
|
|
15
|
+
export { mergePaybondPolicies, toEffectivePolicyDocument, type PolicyMergeDeniedWidening, type PolicyMergeOptions, type PolicyMergeReport, type PolicyMergeResult, } from "./merge.js";
|
|
16
|
+
export { PAYBOND_POLICY_SCHEMA_VERSION, PAYBOND_POLICY_SCHEMA_VERSION_V2, PaybondPolicyValidationError, isPaybondPolicyDocumentV1, isPaybondPolicyDocumentV2, isPaybondPolicyOverlay, parsePaybondPolicyDocument, parsePaybondPolicyDocumentV1, parsePaybondPolicyDocumentV2, paybondPolicyDocumentV1Schema, paybondPolicyDocumentV2Schema, type PaybondPolicyBinding, type PaybondPolicyBindingOverride, type PaybondPolicyBudget, type PaybondPolicyDocument, type PaybondPolicyDocumentV1, type PaybondPolicyDocumentV2, type PaybondPolicyExtends, type PaybondPolicyIntentOverrideSection, type PaybondPolicyIntentSection, type PaybondPolicyOverrides, type PaybondPolicyToolEntry, type PaybondPolicyToolOverrideEntry, type PaybondPolicyValidationIssue, } from "./schema.js";
|
|
17
|
+
export { PolicyValidator, type PolicyGatewayTemplateLookup, type PolicyValidatorError, type PolicyValidatorOptions, type PolicyValidatorResult, type PolicyValidatorToolCounts, } from "./validate.js";
|
|
18
|
+
export { parsePolicyRemoteValidateResponse, policyRemoteValidateResultToDict, policyValidateQueryString, validatePolicyPayloadRemote, validatePolicyRemote, type PolicyRemoteValidateCheck, type PolicyRemoteValidateClient, type PolicyRemoteValidateIssue, type PolicyRemoteValidateOptions, type PolicyRemoteValidateResult, } from "./validate-remote.js";
|
|
19
|
+
export { parseMergeReport, parsePolicyEffectiveResolveResponse, resolvePolicyEffectiveRemote, type PolicyEffectiveResolveClient, type PolicyEffectiveResolveResult, } from "./load-effective.js";
|
|
20
|
+
export { PaybondPolicyReloadController, type PaybondPolicyReloadControllerState, type PolicyReloadRunner, } from "./watcher.js";
|
|
21
|
+
export { PaybondPolicyReloadError, PaybondPolicyReloadUnchangedError, applyPolicySnapshotToRun, detectPolicyLoosening, loadPolicySnapshotFromEffectivePoll, loadPolicySnapshotFromFile, reloadPolicyOnHandle, reloadPolicyOnRun, requiresIntentRebind, type PaybondPolicyReloadBindConfig, type PaybondPolicyReloadFailedEvent, type PaybondPolicyReloadOptions, type PaybondPolicyReloadResult, type PaybondPolicyReloadedEvent, type PolicyReloadHandle, } from "./reload.js";
|