@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,17 @@
|
|
|
1
|
+
import { buildMcpServerEntry, defaultMcpServerCommand, serializeMcpInstallPayload, } from "../cli/mcp-install.js";
|
|
2
|
+
/**
|
|
3
|
+
* Framework runner helper for external MCP hosts (Claude Desktop, Codex, generic stdio).
|
|
4
|
+
*
|
|
5
|
+
* The bound {@link PaybondAgentRun} establishes tenant/intent context for your app;
|
|
6
|
+
* the returned `serverConfig` is the stdio entry coding-agent hosts consume via
|
|
7
|
+
* `PAYBOND_ENV_FILE` (never raw API keys in host config files).
|
|
8
|
+
*/
|
|
9
|
+
export function createPaybondMcpToolSurface(_run, options) {
|
|
10
|
+
const envFile = options?.envFile?.trim() || ".env.local";
|
|
11
|
+
const serverCommand = options?.serverCommand ?? defaultMcpServerCommand();
|
|
12
|
+
const serverConfig = buildMcpServerEntry(envFile, serverCommand, options?.toolPolicy);
|
|
13
|
+
return {
|
|
14
|
+
serverConfig,
|
|
15
|
+
installPayload: (format = "json") => serializeMcpInstallPayload(format, serverConfig),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const MCP_CAPABILITY_TOKEN_TTL_ENV = "PAYBOND_MCP_CAPABILITY_TOKEN_TTL_SEC";
|
|
2
|
+
export declare const MCP_CAPABILITY_TOKEN_CACHE_MAX_ENV = "PAYBOND_MCP_CAPABILITY_TOKEN_CACHE_MAX";
|
|
3
|
+
export declare const DEFAULT_MCP_CAPABILITY_TOKEN_TTL_SEC = 900;
|
|
4
|
+
export declare const DEFAULT_MCP_CAPABILITY_TOKEN_CACHE_MAX = 64;
|
|
5
|
+
/** MCP tools that mint or return funded intent capability tokens from Harbor. */
|
|
6
|
+
export declare const MCP_CAPABILITY_TOKEN_STORE_TOOLS: readonly ["paybond_bootstrap_sandbox_guardrail", "paybond_create_intent", "paybond_create_spend_intent", "paybond_fund_intent"];
|
|
7
|
+
export type McpCapabilityTokenStoreTool = (typeof MCP_CAPABILITY_TOKEN_STORE_TOOLS)[number];
|
|
8
|
+
/** Return true when an MCP tool response may populate the runtime token cache. */
|
|
9
|
+
export declare function mcpToolStoresCapabilityToken(toolName: string): boolean;
|
|
10
|
+
export type McpCapabilityTokenCacheConfig = {
|
|
11
|
+
ttlSec: number;
|
|
12
|
+
maxEntries: number;
|
|
13
|
+
};
|
|
14
|
+
export declare class McpCapabilityTokenCache {
|
|
15
|
+
private readonly ttlSec;
|
|
16
|
+
private readonly maxEntries;
|
|
17
|
+
private readonly entries;
|
|
18
|
+
constructor(config?: McpCapabilityTokenCacheConfig);
|
|
19
|
+
store(intentId: string, token: string): void;
|
|
20
|
+
resolve(intentId: string): string | undefined;
|
|
21
|
+
private evictExpired;
|
|
22
|
+
private evictOverflow;
|
|
23
|
+
}
|
|
24
|
+
export declare function parseMcpCapabilityTokenCacheConfig(env?: Record<string, string | undefined>): McpCapabilityTokenCacheConfig;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export const MCP_CAPABILITY_TOKEN_TTL_ENV = "PAYBOND_MCP_CAPABILITY_TOKEN_TTL_SEC";
|
|
2
|
+
export const MCP_CAPABILITY_TOKEN_CACHE_MAX_ENV = "PAYBOND_MCP_CAPABILITY_TOKEN_CACHE_MAX";
|
|
3
|
+
export const DEFAULT_MCP_CAPABILITY_TOKEN_TTL_SEC = 900;
|
|
4
|
+
export const DEFAULT_MCP_CAPABILITY_TOKEN_CACHE_MAX = 64;
|
|
5
|
+
const MIN_MCP_CAPABILITY_TOKEN_TTL_SEC = 60;
|
|
6
|
+
const MAX_MCP_CAPABILITY_TOKEN_TTL_SEC = 86_400;
|
|
7
|
+
const MIN_MCP_CAPABILITY_TOKEN_CACHE_MAX = 1;
|
|
8
|
+
const MAX_MCP_CAPABILITY_TOKEN_CACHE_MAX = 512;
|
|
9
|
+
/** MCP tools that mint or return funded intent capability tokens from Harbor. */
|
|
10
|
+
export const MCP_CAPABILITY_TOKEN_STORE_TOOLS = [
|
|
11
|
+
"paybond_bootstrap_sandbox_guardrail",
|
|
12
|
+
"paybond_create_intent",
|
|
13
|
+
"paybond_create_spend_intent",
|
|
14
|
+
"paybond_fund_intent",
|
|
15
|
+
];
|
|
16
|
+
const MCP_CAPABILITY_TOKEN_STORE_TOOL_SET = new Set(MCP_CAPABILITY_TOKEN_STORE_TOOLS);
|
|
17
|
+
/** Return true when an MCP tool response may populate the runtime token cache. */
|
|
18
|
+
export function mcpToolStoresCapabilityToken(toolName) {
|
|
19
|
+
return MCP_CAPABILITY_TOKEN_STORE_TOOL_SET.has(toolName.trim());
|
|
20
|
+
}
|
|
21
|
+
export class McpCapabilityTokenCache {
|
|
22
|
+
ttlSec;
|
|
23
|
+
maxEntries;
|
|
24
|
+
entries = new Map();
|
|
25
|
+
constructor(config) {
|
|
26
|
+
this.ttlSec = config?.ttlSec ?? DEFAULT_MCP_CAPABILITY_TOKEN_TTL_SEC;
|
|
27
|
+
this.maxEntries = config?.maxEntries ?? DEFAULT_MCP_CAPABILITY_TOKEN_CACHE_MAX;
|
|
28
|
+
}
|
|
29
|
+
store(intentId, token) {
|
|
30
|
+
const key = intentId.trim();
|
|
31
|
+
const value = token.trim();
|
|
32
|
+
if (!key || !value) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.evictExpired();
|
|
36
|
+
this.entries.set(key, { token: value, storedAtMs: Date.now() });
|
|
37
|
+
this.evictOverflow();
|
|
38
|
+
}
|
|
39
|
+
resolve(intentId) {
|
|
40
|
+
this.evictExpired();
|
|
41
|
+
const key = String(intentId).trim();
|
|
42
|
+
const entry = this.entries.get(key);
|
|
43
|
+
if (!entry) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
if (Date.now() - entry.storedAtMs > this.ttlSec * 1000) {
|
|
47
|
+
this.entries.delete(key);
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
this.entries.delete(key);
|
|
51
|
+
this.entries.set(key, entry);
|
|
52
|
+
return entry.token;
|
|
53
|
+
}
|
|
54
|
+
evictExpired() {
|
|
55
|
+
const now = Date.now();
|
|
56
|
+
const ttlMs = this.ttlSec * 1000;
|
|
57
|
+
for (const [key, entry] of this.entries) {
|
|
58
|
+
if (now - entry.storedAtMs > ttlMs) {
|
|
59
|
+
this.entries.delete(key);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
evictOverflow() {
|
|
64
|
+
while (this.entries.size > this.maxEntries) {
|
|
65
|
+
const oldest = this.entries.keys().next().value;
|
|
66
|
+
if (oldest === undefined) {
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
this.entries.delete(oldest);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function parseMcpCapabilityTokenCacheConfig(env = process.env) {
|
|
74
|
+
const ttlRaw = env[MCP_CAPABILITY_TOKEN_TTL_ENV]?.trim();
|
|
75
|
+
const maxRaw = env[MCP_CAPABILITY_TOKEN_CACHE_MAX_ENV]?.trim();
|
|
76
|
+
let ttlSec = DEFAULT_MCP_CAPABILITY_TOKEN_TTL_SEC;
|
|
77
|
+
if (ttlRaw) {
|
|
78
|
+
const parsed = Number.parseFloat(ttlRaw);
|
|
79
|
+
if (!Number.isFinite(parsed)) {
|
|
80
|
+
throw new Error(`invalid ${MCP_CAPABILITY_TOKEN_TTL_ENV} (expected a number of seconds)`);
|
|
81
|
+
}
|
|
82
|
+
if (parsed < MIN_MCP_CAPABILITY_TOKEN_TTL_SEC ||
|
|
83
|
+
parsed > MAX_MCP_CAPABILITY_TOKEN_TTL_SEC) {
|
|
84
|
+
throw new Error(`invalid ${MCP_CAPABILITY_TOKEN_TTL_ENV} (expected ${MIN_MCP_CAPABILITY_TOKEN_TTL_SEC}-${MAX_MCP_CAPABILITY_TOKEN_TTL_SEC} seconds)`);
|
|
85
|
+
}
|
|
86
|
+
ttlSec = parsed;
|
|
87
|
+
}
|
|
88
|
+
let maxEntries = DEFAULT_MCP_CAPABILITY_TOKEN_CACHE_MAX;
|
|
89
|
+
if (maxRaw) {
|
|
90
|
+
const parsed = Number.parseInt(maxRaw, 10);
|
|
91
|
+
if (!Number.isInteger(parsed)) {
|
|
92
|
+
throw new Error(`invalid ${MCP_CAPABILITY_TOKEN_CACHE_MAX_ENV} (expected an integer)`);
|
|
93
|
+
}
|
|
94
|
+
if (parsed < MIN_MCP_CAPABILITY_TOKEN_CACHE_MAX ||
|
|
95
|
+
parsed > MAX_MCP_CAPABILITY_TOKEN_CACHE_MAX) {
|
|
96
|
+
throw new Error(`invalid ${MCP_CAPABILITY_TOKEN_CACHE_MAX_ENV} (expected ${MIN_MCP_CAPABILITY_TOKEN_CACHE_MAX}-${MAX_MCP_CAPABILITY_TOKEN_CACHE_MAX})`);
|
|
97
|
+
}
|
|
98
|
+
maxEntries = parsed;
|
|
99
|
+
}
|
|
100
|
+
return { ttlSec, maxEntries };
|
|
101
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type CompletionEvidenceValidationReport } from "./completion-validate-evidence.js";
|
|
2
|
+
export type McpEvidencePolicy = "strict" | "off";
|
|
3
|
+
export declare const MCP_EVIDENCE_POLICY_ENV = "PAYBOND_MCP_EVIDENCE_POLICY";
|
|
4
|
+
export declare const DEFAULT_MCP_EVIDENCE_POLICY: McpEvidencePolicy;
|
|
5
|
+
export declare const EVIDENCE_SUBMIT_TOOL_NAMES: Set<string>;
|
|
6
|
+
export declare class McpEvidencePolicyError extends Error {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
9
|
+
export declare function parseMcpEvidencePolicy(raw: string | undefined): McpEvidencePolicy;
|
|
10
|
+
export declare function completionEvidenceValidationOk(report: CompletionEvidenceValidationReport): boolean;
|
|
11
|
+
export declare function evidenceValidationGateKey(input: {
|
|
12
|
+
presetId: string;
|
|
13
|
+
vendorPayload?: Record<string, unknown>;
|
|
14
|
+
canonicalPayload?: Record<string, unknown>;
|
|
15
|
+
}): string;
|
|
16
|
+
export declare function extractHarborEvidenceValidationInput(body: Record<string, unknown>, completionPresetId?: string): {
|
|
17
|
+
presetId: string;
|
|
18
|
+
vendorPayload?: Record<string, unknown>;
|
|
19
|
+
canonicalPayload?: Record<string, unknown>;
|
|
20
|
+
};
|
|
21
|
+
export declare function extractSandboxGuardrailValidationInput(input: {
|
|
22
|
+
payload?: Record<string, unknown>;
|
|
23
|
+
completionPresetId?: string;
|
|
24
|
+
}): {
|
|
25
|
+
presetId: string;
|
|
26
|
+
vendorPayload?: Record<string, unknown>;
|
|
27
|
+
canonicalPayload?: Record<string, unknown>;
|
|
28
|
+
};
|
|
29
|
+
export declare class McpEvidenceValidationGate {
|
|
30
|
+
readonly policy: McpEvidencePolicy;
|
|
31
|
+
private readonly passes;
|
|
32
|
+
constructor(policy?: McpEvidencePolicy);
|
|
33
|
+
recordPass(gateKey: string): void;
|
|
34
|
+
hasPass(gateKey: string): boolean;
|
|
35
|
+
requirePass(input: {
|
|
36
|
+
presetId: string;
|
|
37
|
+
vendorPayload?: Record<string, unknown>;
|
|
38
|
+
canonicalPayload?: Record<string, unknown>;
|
|
39
|
+
}): void;
|
|
40
|
+
validateAndRecord(input: {
|
|
41
|
+
presetId: string;
|
|
42
|
+
vendorPayload?: Record<string, unknown>;
|
|
43
|
+
canonicalPayload?: Record<string, unknown>;
|
|
44
|
+
frozenVendorApiVersion?: string;
|
|
45
|
+
frozenVendorSchemaDigestHex?: string;
|
|
46
|
+
frozenCanonicalSchemaDigestHex?: string;
|
|
47
|
+
}): CompletionEvidenceValidationReport;
|
|
48
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { validateCompletionEvidence, } from "./completion-validate-evidence.js";
|
|
2
|
+
import { jsonValueDigest } from "./json-digest.js";
|
|
3
|
+
export const MCP_EVIDENCE_POLICY_ENV = "PAYBOND_MCP_EVIDENCE_POLICY";
|
|
4
|
+
export const DEFAULT_MCP_EVIDENCE_POLICY = "strict";
|
|
5
|
+
export const EVIDENCE_SUBMIT_TOOL_NAMES = new Set([
|
|
6
|
+
"paybond_submit_evidence",
|
|
7
|
+
"paybond_submit_spend_evidence",
|
|
8
|
+
"paybond_submit_sandbox_guardrail_evidence",
|
|
9
|
+
]);
|
|
10
|
+
export class McpEvidencePolicyError extends Error {
|
|
11
|
+
constructor(message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "McpEvidencePolicyError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function parseMcpEvidencePolicy(raw) {
|
|
17
|
+
const value = (raw ?? "").trim().toLowerCase();
|
|
18
|
+
if (!value) {
|
|
19
|
+
return DEFAULT_MCP_EVIDENCE_POLICY;
|
|
20
|
+
}
|
|
21
|
+
if (value === "strict" || value === "off") {
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
throw new Error("invalid PAYBOND_MCP_EVIDENCE_POLICY (expected strict|off)");
|
|
25
|
+
}
|
|
26
|
+
export function completionEvidenceValidationOk(report) {
|
|
27
|
+
return report.drift_kinds.length === 0;
|
|
28
|
+
}
|
|
29
|
+
export function evidenceValidationGateKey(input) {
|
|
30
|
+
const presetId = input.presetId.trim();
|
|
31
|
+
if (!presetId) {
|
|
32
|
+
throw new Error("completion preset id is required for evidence validation");
|
|
33
|
+
}
|
|
34
|
+
const digest = jsonValueDigest({
|
|
35
|
+
preset_id: presetId,
|
|
36
|
+
vendor_payload: input.vendorPayload,
|
|
37
|
+
canonical_payload: input.canonicalPayload,
|
|
38
|
+
});
|
|
39
|
+
return Buffer.from(digest).toString("hex");
|
|
40
|
+
}
|
|
41
|
+
export function extractHarborEvidenceValidationInput(body, completionPresetId) {
|
|
42
|
+
let presetId = (completionPresetId ?? "").trim();
|
|
43
|
+
if (!presetId) {
|
|
44
|
+
for (const key of ["completion_preset_id", "completion_preset"]) {
|
|
45
|
+
const raw = body[key];
|
|
46
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
47
|
+
presetId = raw.trim();
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const vendorRaw = body.vendor_payload;
|
|
53
|
+
const vendorPayload = vendorRaw !== undefined && typeof vendorRaw === "object" && vendorRaw !== null && !Array.isArray(vendorRaw)
|
|
54
|
+
? vendorRaw
|
|
55
|
+
: undefined;
|
|
56
|
+
const payloadRaw = body.payload;
|
|
57
|
+
const canonicalPayload = payloadRaw !== undefined && typeof payloadRaw === "object" && payloadRaw !== null && !Array.isArray(payloadRaw)
|
|
58
|
+
? payloadRaw
|
|
59
|
+
: undefined;
|
|
60
|
+
return { presetId, vendorPayload, canonicalPayload };
|
|
61
|
+
}
|
|
62
|
+
export function extractSandboxGuardrailValidationInput(input) {
|
|
63
|
+
const presetId = (input.completionPresetId ?? "").trim();
|
|
64
|
+
return {
|
|
65
|
+
presetId,
|
|
66
|
+
vendorPayload: input.payload,
|
|
67
|
+
canonicalPayload: input.payload,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export class McpEvidenceValidationGate {
|
|
71
|
+
policy;
|
|
72
|
+
passes = new Set();
|
|
73
|
+
constructor(policy = DEFAULT_MCP_EVIDENCE_POLICY) {
|
|
74
|
+
this.policy = policy;
|
|
75
|
+
}
|
|
76
|
+
recordPass(gateKey) {
|
|
77
|
+
this.passes.add(gateKey);
|
|
78
|
+
}
|
|
79
|
+
hasPass(gateKey) {
|
|
80
|
+
return this.passes.has(gateKey);
|
|
81
|
+
}
|
|
82
|
+
requirePass(input) {
|
|
83
|
+
if (this.policy === "off") {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const presetId = input.presetId.trim();
|
|
87
|
+
if (!presetId) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const gateKey = evidenceValidationGateKey({
|
|
91
|
+
presetId,
|
|
92
|
+
vendorPayload: input.vendorPayload,
|
|
93
|
+
canonicalPayload: input.canonicalPayload,
|
|
94
|
+
});
|
|
95
|
+
if (!this.hasPass(gateKey)) {
|
|
96
|
+
throw new McpEvidencePolicyError("completion evidence was not pre-validated; call paybond_validate_completion_evidence with the same preset and payload before submit (Harbor remains authoritative at submit time)");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
validateAndRecord(input) {
|
|
100
|
+
const report = validateCompletionEvidence({
|
|
101
|
+
presetId: input.presetId,
|
|
102
|
+
vendorPayload: input.vendorPayload,
|
|
103
|
+
canonicalPayload: input.canonicalPayload,
|
|
104
|
+
frozenVendorApiVersion: input.frozenVendorApiVersion,
|
|
105
|
+
frozenVendorSchemaDigestHex: input.frozenVendorSchemaDigestHex,
|
|
106
|
+
frozenCanonicalSchemaDigestHex: input.frozenCanonicalSchemaDigestHex,
|
|
107
|
+
});
|
|
108
|
+
if (completionEvidenceValidationOk(report)) {
|
|
109
|
+
this.recordPass(evidenceValidationGateKey({
|
|
110
|
+
presetId: input.presetId,
|
|
111
|
+
vendorPayload: input.vendorPayload,
|
|
112
|
+
canonicalPayload: input.canonicalPayload,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
return report;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { type PaybondPolicyReloadOptions, type PaybondPolicyReloadResult, type PolicyReloadHandle } from "./policy/reload.js";
|
|
2
|
+
import type { PaybondPolicySnapshot } from "./policy/snapshot.js";
|
|
3
|
+
import { type PolicyEffectiveResolveClient } from "./policy/load-effective.js";
|
|
4
|
+
import { type PolicyRemoteValidateClient } from "./policy/validate-remote.js";
|
|
5
|
+
export declare const MCP_POLICY_FILE_ENV = "PAYBOND_POLICY_FILE";
|
|
6
|
+
export declare const MCP_POLICY_RELOAD_ENV = "PAYBOND_POLICY_RELOAD";
|
|
7
|
+
export declare const MCP_POLICY_RELOAD_ALLOW_LOOSEN_ENV = "PAYBOND_POLICY_RELOAD_ALLOW_LOOSEN";
|
|
8
|
+
export type McpPolicyReloadMode = "off" | "watch" | "poll";
|
|
9
|
+
export type McpPolicyReloadConfig = {
|
|
10
|
+
policyFile: string;
|
|
11
|
+
reloadMode: McpPolicyReloadMode;
|
|
12
|
+
allowLoosen?: boolean;
|
|
13
|
+
watchDebounceMs?: number;
|
|
14
|
+
pollIntervalMs?: number;
|
|
15
|
+
};
|
|
16
|
+
export type McpPolicySpendGateInput = {
|
|
17
|
+
toolName?: string;
|
|
18
|
+
operation: string;
|
|
19
|
+
allowedTools: readonly string[];
|
|
20
|
+
arguments?: unknown;
|
|
21
|
+
requestedSpendCents?: number;
|
|
22
|
+
};
|
|
23
|
+
export type McpPolicySpendGateResult = {
|
|
24
|
+
operation: string;
|
|
25
|
+
requestedSpendCents: number;
|
|
26
|
+
policyDigest?: string;
|
|
27
|
+
};
|
|
28
|
+
export type McpPolicyReloadStatus = {
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
policy_file?: string;
|
|
31
|
+
policy_digest?: string;
|
|
32
|
+
policy_loaded_at?: string;
|
|
33
|
+
reload_mode: McpPolicyReloadMode;
|
|
34
|
+
last_reload_at?: string;
|
|
35
|
+
last_reload_error?: string;
|
|
36
|
+
};
|
|
37
|
+
export declare class McpPolicyReloadError extends Error {
|
|
38
|
+
constructor(message: string);
|
|
39
|
+
}
|
|
40
|
+
/** Gateway adapter for MCP poll reload with remote validation. */
|
|
41
|
+
export type McpPolicyGatewayClient = PolicyRemoteValidateClient & PolicyEffectiveResolveClient;
|
|
42
|
+
export declare function createMcpPolicyGatewayAdapter(client: {
|
|
43
|
+
postJSON(path: string, payload: Record<string, unknown>, extraHeaders?: Record<string, string>): Promise<Record<string, unknown>>;
|
|
44
|
+
}): McpPolicyGatewayClient;
|
|
45
|
+
export declare function parseMcpPolicyReloadMode(raw: string | undefined): McpPolicyReloadMode;
|
|
46
|
+
export declare function parseMcpPolicyReloadConfig(env: Record<string, string | undefined>): McpPolicyReloadConfig | null;
|
|
47
|
+
/**
|
|
48
|
+
* Long-lived MCP policy gate: versioned snapshot, safe reload, and spend-gate registry checks.
|
|
49
|
+
*/
|
|
50
|
+
export declare class McpPolicyReloadGate implements PolicyReloadHandle {
|
|
51
|
+
readonly config: McpPolicyReloadConfig;
|
|
52
|
+
private _snapshot?;
|
|
53
|
+
private _inFlightCount;
|
|
54
|
+
private _lastAllowedTools;
|
|
55
|
+
private _controller?;
|
|
56
|
+
private _reloadDefaults;
|
|
57
|
+
readonly policyFilePath: string;
|
|
58
|
+
lastReloadAt?: string;
|
|
59
|
+
lastReloadError?: string;
|
|
60
|
+
private constructor();
|
|
61
|
+
static open(config: McpPolicyReloadConfig, options?: {
|
|
62
|
+
gateway?: McpPolicyGatewayClient;
|
|
63
|
+
}): Promise<McpPolicyReloadGate>;
|
|
64
|
+
get currentSnapshot(): PaybondPolicySnapshot | undefined;
|
|
65
|
+
get policyDigest(): string | undefined;
|
|
66
|
+
get inFlightCount(): number;
|
|
67
|
+
get registry(): import("./index.js").PaybondToolRegistry;
|
|
68
|
+
applyPolicySnapshot(snapshot: PaybondPolicySnapshot): void;
|
|
69
|
+
reloadPolicy(options?: PaybondPolicyReloadOptions): Promise<PaybondPolicyReloadResult>;
|
|
70
|
+
beginToolCall(): void;
|
|
71
|
+
endToolCall(): void;
|
|
72
|
+
/**
|
|
73
|
+
* Enforce paybond.policy.yaml registry rules before Harbor spend authorization.
|
|
74
|
+
* Pins policy_digest for the current MCP tool invocation.
|
|
75
|
+
*/
|
|
76
|
+
assertSpendGate(input: McpPolicySpendGateInput): McpPolicySpendGateResult;
|
|
77
|
+
status(): McpPolicyReloadStatus;
|
|
78
|
+
stop(): void;
|
|
79
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { PaybondUnregisteredSideEffectingToolError } from "./agent/types.js";
|
|
3
|
+
import { loadPolicySnapshotFromFile, reloadPolicyOnHandle, } from "./policy/reload.js";
|
|
4
|
+
import { parsePolicyEffectiveResolveResponse, } from "./policy/load-effective.js";
|
|
5
|
+
import { parsePolicyRemoteValidateResponse, policyValidateQueryString, } from "./policy/validate-remote.js";
|
|
6
|
+
import { PaybondPolicyReloadController } from "./policy/watcher.js";
|
|
7
|
+
export const MCP_POLICY_FILE_ENV = "PAYBOND_POLICY_FILE";
|
|
8
|
+
export const MCP_POLICY_RELOAD_ENV = "PAYBOND_POLICY_RELOAD";
|
|
9
|
+
export const MCP_POLICY_RELOAD_ALLOW_LOOSEN_ENV = "PAYBOND_POLICY_RELOAD_ALLOW_LOOSEN";
|
|
10
|
+
export class McpPolicyReloadError extends Error {
|
|
11
|
+
constructor(message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "McpPolicyReloadError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function createMcpPolicyGatewayAdapter(client) {
|
|
17
|
+
return {
|
|
18
|
+
async validatePolicy(document, options) {
|
|
19
|
+
const qs = policyValidateQueryString(options ?? {});
|
|
20
|
+
const body = await client.postJSON(`/v1/policy/validate${qs}`, document);
|
|
21
|
+
return parsePolicyRemoteValidateResponse(body);
|
|
22
|
+
},
|
|
23
|
+
async resolvePolicyEffective(orgPolicyId, overlay, options) {
|
|
24
|
+
let path = `/v1/org-policies/${encodeURIComponent(orgPolicyId)}/effective`;
|
|
25
|
+
const currentDigest = options?.currentDigest?.trim();
|
|
26
|
+
if (currentDigest) {
|
|
27
|
+
path += `?digest=${encodeURIComponent(currentDigest)}`;
|
|
28
|
+
}
|
|
29
|
+
const body = await client.postJSON(path, overlay);
|
|
30
|
+
return parsePolicyEffectiveResolveResponse(body);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function parseMcpPolicyReloadMode(raw) {
|
|
35
|
+
const value = (raw ?? "").trim().toLowerCase();
|
|
36
|
+
if (!value || value === "off") {
|
|
37
|
+
return "off";
|
|
38
|
+
}
|
|
39
|
+
if (value === "watch" || value === "poll") {
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
throw new Error("invalid PAYBOND_POLICY_RELOAD (expected watch|poll|off)");
|
|
43
|
+
}
|
|
44
|
+
export function parseMcpPolicyReloadConfig(env) {
|
|
45
|
+
const policyFile = (env[MCP_POLICY_FILE_ENV] ?? "").trim();
|
|
46
|
+
if (!policyFile) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
policyFile: resolve(policyFile),
|
|
51
|
+
reloadMode: parseMcpPolicyReloadMode(env[MCP_POLICY_RELOAD_ENV]),
|
|
52
|
+
allowLoosen: env[MCP_POLICY_RELOAD_ALLOW_LOOSEN_ENV] === "1",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** MCP reload controller shim — delegates to {@link McpPolicyReloadGate}. */
|
|
56
|
+
class McpPolicyReloadRunner {
|
|
57
|
+
gate;
|
|
58
|
+
constructor(gate) {
|
|
59
|
+
this.gate = gate;
|
|
60
|
+
}
|
|
61
|
+
reloadPolicy(options) {
|
|
62
|
+
return this.gate.reloadPolicy(options);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Long-lived MCP policy gate: versioned snapshot, safe reload, and spend-gate registry checks.
|
|
67
|
+
*/
|
|
68
|
+
export class McpPolicyReloadGate {
|
|
69
|
+
config;
|
|
70
|
+
_snapshot;
|
|
71
|
+
_inFlightCount = 0;
|
|
72
|
+
_lastAllowedTools = [];
|
|
73
|
+
_controller;
|
|
74
|
+
_reloadDefaults = {};
|
|
75
|
+
policyFilePath;
|
|
76
|
+
lastReloadAt;
|
|
77
|
+
lastReloadError;
|
|
78
|
+
constructor(config, snapshot) {
|
|
79
|
+
this.config = config;
|
|
80
|
+
this.policyFilePath = config.policyFile;
|
|
81
|
+
this._snapshot = snapshot;
|
|
82
|
+
}
|
|
83
|
+
static async open(config, options) {
|
|
84
|
+
const snapshot = await loadPolicySnapshotFromFile(config.policyFile);
|
|
85
|
+
const gate = new McpPolicyReloadGate(config, snapshot);
|
|
86
|
+
const runner = new McpPolicyReloadRunner(gate);
|
|
87
|
+
gate._reloadDefaults = {
|
|
88
|
+
file: config.policyFile,
|
|
89
|
+
allowLoosen: config.allowLoosen,
|
|
90
|
+
gateway: options?.gateway,
|
|
91
|
+
};
|
|
92
|
+
if (config.reloadMode === "watch") {
|
|
93
|
+
gate._controller = PaybondPolicyReloadController.start(runner, { watch: { debounceMs: config.watchDebounceMs } }, config.policyFile);
|
|
94
|
+
}
|
|
95
|
+
else if (config.reloadMode === "poll") {
|
|
96
|
+
gate._reloadDefaults.remote = true;
|
|
97
|
+
gate._reloadDefaults.resolveInheritance = true;
|
|
98
|
+
gate._controller = PaybondPolicyReloadController.start(runner, {
|
|
99
|
+
poll: {
|
|
100
|
+
intervalMs: config.pollIntervalMs,
|
|
101
|
+
remote: true,
|
|
102
|
+
resolveInheritance: true,
|
|
103
|
+
gateway: options?.gateway,
|
|
104
|
+
},
|
|
105
|
+
}, config.policyFile);
|
|
106
|
+
}
|
|
107
|
+
return gate;
|
|
108
|
+
}
|
|
109
|
+
get currentSnapshot() {
|
|
110
|
+
return this._snapshot;
|
|
111
|
+
}
|
|
112
|
+
get policyDigest() {
|
|
113
|
+
return this._snapshot?.digest;
|
|
114
|
+
}
|
|
115
|
+
get inFlightCount() {
|
|
116
|
+
return this._inFlightCount;
|
|
117
|
+
}
|
|
118
|
+
get registry() {
|
|
119
|
+
const snapshot = this._snapshot;
|
|
120
|
+
if (!snapshot) {
|
|
121
|
+
throw new McpPolicyReloadError("policy snapshot is not loaded");
|
|
122
|
+
}
|
|
123
|
+
return snapshot.registry;
|
|
124
|
+
}
|
|
125
|
+
applyPolicySnapshot(snapshot) {
|
|
126
|
+
this._snapshot = snapshot;
|
|
127
|
+
}
|
|
128
|
+
async reloadPolicy(options = {}) {
|
|
129
|
+
try {
|
|
130
|
+
const result = await reloadPolicyOnHandle(this, {
|
|
131
|
+
...this._reloadDefaults,
|
|
132
|
+
...options,
|
|
133
|
+
allowedTools: this._lastAllowedTools,
|
|
134
|
+
});
|
|
135
|
+
if (result.applied) {
|
|
136
|
+
this.lastReloadAt = new Date().toISOString();
|
|
137
|
+
this.lastReloadError = undefined;
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
this.lastReloadError = err instanceof Error ? err.message : String(err);
|
|
143
|
+
throw err;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
beginToolCall() {
|
|
147
|
+
this._inFlightCount += 1;
|
|
148
|
+
}
|
|
149
|
+
endToolCall() {
|
|
150
|
+
this._inFlightCount = Math.max(0, this._inFlightCount - 1);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Enforce paybond.policy.yaml registry rules before Harbor spend authorization.
|
|
154
|
+
* Pins policy_digest for the current MCP tool invocation.
|
|
155
|
+
*/
|
|
156
|
+
assertSpendGate(input) {
|
|
157
|
+
const operation = input.operation.trim();
|
|
158
|
+
const toolName = (input.toolName ?? operation).trim();
|
|
159
|
+
if (!operation) {
|
|
160
|
+
throw new McpPolicyReloadError("operation must be non-empty");
|
|
161
|
+
}
|
|
162
|
+
this._lastAllowedTools = input.allowedTools;
|
|
163
|
+
const policyDigest = this._snapshot?.digest;
|
|
164
|
+
const resolution = this.registry.resolveTool(toolName, {
|
|
165
|
+
allowedTools: input.allowedTools,
|
|
166
|
+
});
|
|
167
|
+
if (resolution.kind === "passthrough") {
|
|
168
|
+
return { operation, requestedSpendCents: 0, policyDigest };
|
|
169
|
+
}
|
|
170
|
+
if (resolution.kind === "denied") {
|
|
171
|
+
throw new PaybondUnregisteredSideEffectingToolError(resolution.toolName, resolution.operation);
|
|
172
|
+
}
|
|
173
|
+
if (!input.allowedTools.includes(operation)) {
|
|
174
|
+
throw new McpPolicyReloadError(`operation "${operation}" is not in intent allowed_tools (${input.allowedTools.join(", ")})`);
|
|
175
|
+
}
|
|
176
|
+
const requestedSpendCents = input.requestedSpendCents ??
|
|
177
|
+
this.registry.resolveSpendCents(toolName, input.arguments) ??
|
|
178
|
+
0;
|
|
179
|
+
return {
|
|
180
|
+
operation: resolution.operation,
|
|
181
|
+
requestedSpendCents,
|
|
182
|
+
policyDigest,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
status() {
|
|
186
|
+
return {
|
|
187
|
+
enabled: true,
|
|
188
|
+
policy_file: this.policyFilePath,
|
|
189
|
+
policy_digest: this.policyDigest,
|
|
190
|
+
policy_loaded_at: this._snapshot?.loadedAt,
|
|
191
|
+
reload_mode: this.config.reloadMode,
|
|
192
|
+
last_reload_at: this.lastReloadAt ?? this._controller?.state.lastReloadAt,
|
|
193
|
+
last_reload_error: this.lastReloadError ?? this._controller?.state.lastReloadError,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
stop() {
|
|
197
|
+
this._controller?.stop();
|
|
198
|
+
this._controller = undefined;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps SEP-2828-style MCP decision/outcome execution records into artifact_attested evidence.
|
|
3
|
+
*
|
|
4
|
+
* Wire shapes follow the draft SEP-2828 pairing model: decision record (pre-side-effect) and
|
|
5
|
+
* outcome record (post-execution) linked via backLink and outcomeDerived.decisionDigest.
|
|
6
|
+
*/
|
|
7
|
+
export type Sep2828BackLink = {
|
|
8
|
+
attestationDigest: string;
|
|
9
|
+
attestationNonce?: string;
|
|
10
|
+
};
|
|
11
|
+
export type Sep2828DecisionRecord = {
|
|
12
|
+
backLink?: Sep2828BackLink;
|
|
13
|
+
decisionDerived?: {
|
|
14
|
+
decision?: "allow" | "block" | "escalate";
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export type Sep2828OutcomeRecord = {
|
|
18
|
+
backLink?: Sep2828BackLink;
|
|
19
|
+
outcomeDerived?: {
|
|
20
|
+
status?: "executed" | "refused" | "errored";
|
|
21
|
+
decisionDigest?: string;
|
|
22
|
+
resultCommitment?: string;
|
|
23
|
+
completedAt?: string;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export type ArtifactAttestedEvidence = {
|
|
27
|
+
artifact_blake3_hex: string[];
|
|
28
|
+
operation: string;
|
|
29
|
+
vendor_ref_id: string;
|
|
30
|
+
};
|
|
31
|
+
/** Strips sha256:/blake3: prefixes so digests fit artifact_blake3_hex entries. */
|
|
32
|
+
export declare function stripDigestPrefix(digest: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Converts paired SEP-2828 decision and outcome records into artifact_attested evidence fields.
|
|
35
|
+
*/
|
|
36
|
+
export declare function mapSep2828ReceiptsToArtifactAttestedEvidence(decisionInput: Record<string, unknown>, outcomeInput: Record<string, unknown>): ArtifactAttestedEvidence;
|