@wardby/cli 0.1.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/.env.example +131 -0
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +282 -0
- package/bin/wardby.js +3 -0
- package/deploy/local/docker-compose.yml +19 -0
- package/dist/claude-coding-worker/driver.d.ts +70 -0
- package/dist/claude-coding-worker/driver.js +128 -0
- package/dist/claude-coding-worker/main.d.ts +2 -0
- package/dist/claude-coding-worker/main.js +41 -0
- package/dist/claude-coding-worker/sdk.d.ts +4 -0
- package/dist/claude-coding-worker/sdk.js +43 -0
- package/dist/claude-coding-worker/tool-relay.d.ts +1 -0
- package/dist/claude-coding-worker/tool-relay.js +9 -0
- package/dist/cli-help.d.ts +1 -0
- package/dist/cli-help.js +20 -0
- package/dist/cli.d.ts +18 -0
- package/dist/cli.js +629 -0
- package/dist/coding/observability.d.ts +59 -0
- package/dist/coding/observability.js +77 -0
- package/dist/coding/profile.d.ts +88 -0
- package/dist/coding/profile.js +137 -0
- package/dist/coding/protocol.d.ts +345 -0
- package/dist/coding/protocol.js +445 -0
- package/dist/coding/provider.d.ts +4 -0
- package/dist/coding/provider.js +18 -0
- package/dist/coding-proxy/main.d.ts +1 -0
- package/dist/coding-proxy/main.js +51 -0
- package/dist/coding-worker/artifact.d.ts +16 -0
- package/dist/coding-worker/artifact.js +37 -0
- package/dist/coding-worker/driver.d.ts +46 -0
- package/dist/coding-worker/driver.js +158 -0
- package/dist/coding-worker/errors.d.ts +1 -0
- package/dist/coding-worker/errors.js +23 -0
- package/dist/coding-worker/isolation-probe.d.ts +1 -0
- package/dist/coding-worker/isolation-probe.js +146 -0
- package/dist/coding-worker/keeper.d.ts +4 -0
- package/dist/coding-worker/keeper.js +29 -0
- package/dist/coding-worker/main.d.ts +2 -0
- package/dist/coding-worker/main.js +43 -0
- package/dist/coding-worker/sdk.d.ts +26 -0
- package/dist/coding-worker/sdk.js +28 -0
- package/dist/coding-worker/types.d.ts +64 -0
- package/dist/coding-worker/types.js +1 -0
- package/dist/config/providers.d.ts +158 -0
- package/dist/config/providers.js +162 -0
- package/dist/core/budget-groups.d.ts +72 -0
- package/dist/core/budget-groups.js +149 -0
- package/dist/core/budget.d.ts +63 -0
- package/dist/core/budget.js +69 -0
- package/dist/core/coding-queue.d.ts +32 -0
- package/dist/core/coding-queue.js +54 -0
- package/dist/core/cron.d.ts +31 -0
- package/dist/core/cron.js +43 -0
- package/dist/core/datastores.d.ts +41 -0
- package/dist/core/datastores.js +105 -0
- package/dist/core/db.d.ts +2 -0
- package/dist/core/db.js +2 -0
- package/dist/core/dispatch.d.ts +81 -0
- package/dist/core/dispatch.js +184 -0
- package/dist/core/engine-native.d.ts +29 -0
- package/dist/core/engine-native.js +259 -0
- package/dist/core/http-runtime.d.ts +7 -0
- package/dist/core/http-runtime.js +101 -0
- package/dist/core/lease.d.ts +13 -0
- package/dist/core/lease.js +22 -0
- package/dist/core/logger.d.ts +13 -0
- package/dist/core/logger.js +45 -0
- package/dist/core/memory-tools.d.ts +11 -0
- package/dist/core/memory-tools.js +122 -0
- package/dist/core/reconciler.d.ts +45 -0
- package/dist/core/reconciler.js +152 -0
- package/dist/core/runner.d.ts +87 -0
- package/dist/core/runner.js +529 -0
- package/dist/core/scheduler.d.ts +47 -0
- package/dist/core/scheduler.js +121 -0
- package/dist/core/secrets.d.ts +46 -0
- package/dist/core/secrets.js +100 -0
- package/dist/core/subagent-memory-tools.d.ts +18 -0
- package/dist/core/subagent-memory-tools.js +121 -0
- package/dist/core/timing.d.ts +7 -0
- package/dist/core/timing.js +7 -0
- package/dist/core/webhooks.d.ts +23 -0
- package/dist/core/webhooks.js +113 -0
- package/dist/env.d.ts +11 -0
- package/dist/env.js +13 -0
- package/dist/import/budgets.d.ts +16 -0
- package/dist/import/budgets.js +21 -0
- package/dist/import/bundle.d.ts +16 -0
- package/dist/import/bundle.js +61 -0
- package/dist/import/cli-args.d.ts +2 -0
- package/dist/import/cli-args.js +44 -0
- package/dist/import/create.d.ts +34 -0
- package/dist/import/create.js +363 -0
- package/dist/import/index.d.ts +25 -0
- package/dist/import/index.js +130 -0
- package/dist/import/model-gate.d.ts +1 -0
- package/dist/import/model-gate.js +3 -0
- package/dist/import/neutral-schema.d.ts +369 -0
- package/dist/import/neutral-schema.js +109 -0
- package/dist/import/preflight.d.ts +41 -0
- package/dist/import/preflight.js +71 -0
- package/dist/import/report.d.ts +5 -0
- package/dist/import/report.js +98 -0
- package/dist/import/tool-scan.d.ts +8 -0
- package/dist/import/tool-scan.js +20 -0
- package/dist/mcp/auth/ownership.d.ts +113 -0
- package/dist/mcp/auth/ownership.js +87 -0
- package/dist/mcp/auth/principal.d.ts +9 -0
- package/dist/mcp/auth/principal.js +9 -0
- package/dist/mcp/auth/resource-server.d.ts +47 -0
- package/dist/mcp/auth/resource-server.js +82 -0
- package/dist/mcp/auth/self-hosted/browser.d.ts +3 -0
- package/dist/mcp/auth/self-hosted/browser.js +273 -0
- package/dist/mcp/auth/self-hosted/cli.d.ts +2 -0
- package/dist/mcp/auth/self-hosted/cli.js +39 -0
- package/dist/mcp/auth/self-hosted/credentials.d.ts +58 -0
- package/dist/mcp/auth/self-hosted/credentials.js +106 -0
- package/dist/mcp/auth/self-hosted/rate-limit.d.ts +13 -0
- package/dist/mcp/auth/self-hosted/rate-limit.js +20 -0
- package/dist/mcp/auth/self-hosted/session.d.ts +36 -0
- package/dist/mcp/auth/self-hosted/session.js +110 -0
- package/dist/mcp/capabilities.d.ts +11 -0
- package/dist/mcp/capabilities.js +10 -0
- package/dist/mcp/context.d.ts +46 -0
- package/dist/mcp/context.js +1 -0
- package/dist/mcp/errors.d.ts +13 -0
- package/dist/mcp/errors.js +22 -0
- package/dist/mcp/index.d.ts +32 -0
- package/dist/mcp/index.js +187 -0
- package/dist/mcp/jsonrpc.d.ts +8 -0
- package/dist/mcp/jsonrpc.js +1 -0
- package/dist/mcp/server.d.ts +107 -0
- package/dist/mcp/server.js +203 -0
- package/dist/mcp/tasks/manager.d.ts +63 -0
- package/dist/mcp/tasks/manager.js +103 -0
- package/dist/mcp/tools/agents.d.ts +2 -0
- package/dist/mcp/tools/agents.js +375 -0
- package/dist/mcp/tools/budget-groups.d.ts +2 -0
- package/dist/mcp/tools/budget-groups.js +136 -0
- package/dist/mcp/tools/datastore.d.ts +2 -0
- package/dist/mcp/tools/datastore.js +217 -0
- package/dist/mcp/tools/memory.d.ts +3 -0
- package/dist/mcp/tools/memory.js +60 -0
- package/dist/mcp/tools/models.d.ts +8 -0
- package/dist/mcp/tools/models.js +15 -0
- package/dist/mcp/tools/runs.d.ts +2 -0
- package/dist/mcp/tools/runs.js +61 -0
- package/dist/mcp/tools/scheduling.d.ts +2 -0
- package/dist/mcp/tools/scheduling.js +48 -0
- package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -0
- package/dist/mcp/tools/secret-elicitation-form.js +93 -0
- package/dist/mcp/tools/secret-elicitation-server.d.ts +5 -0
- package/dist/mcp/tools/secret-elicitation-server.js +57 -0
- package/dist/mcp/tools/secret-elicitation.d.ts +38 -0
- package/dist/mcp/tools/secret-elicitation.js +52 -0
- package/dist/mcp/tools/secrets.d.ts +13 -0
- package/dist/mcp/tools/secrets.js +124 -0
- package/dist/mcp/tools/subagents.d.ts +2 -0
- package/dist/mcp/tools/subagents.js +133 -0
- package/dist/mcp/tools/text-result.d.ts +6 -0
- package/dist/mcp/tools/text-result.js +3 -0
- package/dist/mcp/tools/tools.d.ts +2 -0
- package/dist/mcp/tools/tools.js +211 -0
- package/dist/mcp/tools/trigger.d.ts +2 -0
- package/dist/mcp/tools/trigger.js +120 -0
- package/dist/mcp/tools/webhooks.d.ts +2 -0
- package/dist/mcp/tools/webhooks.js +34 -0
- package/dist/mcp/transport/http-limits.d.ts +17 -0
- package/dist/mcp/transport/http-limits.js +92 -0
- package/dist/mcp/transport/stdio.d.ts +23 -0
- package/dist/mcp/transport/stdio.js +6 -0
- package/dist/mcp/transport/streamable-http.d.ts +34 -0
- package/dist/mcp/transport/streamable-http.js +158 -0
- package/dist/mcp/unattended-schedules.d.ts +15 -0
- package/dist/mcp/unattended-schedules.js +21 -0
- package/dist/mcp/webhooks/ingress.d.ts +17 -0
- package/dist/mcp/webhooks/ingress.js +33 -0
- package/dist/observability/config.d.ts +6 -0
- package/dist/observability/config.js +20 -0
- package/dist/observability/metrics-server.d.ts +11 -0
- package/dist/observability/metrics-server.js +47 -0
- package/dist/observability/metrics.d.ts +36 -0
- package/dist/observability/metrics.js +158 -0
- package/dist/providers/auth/authorization-server.d.ts +41 -0
- package/dist/providers/auth/authorization-server.js +1 -0
- package/dist/providers/auth/delegating.d.ts +44 -0
- package/dist/providers/auth/delegating.js +105 -0
- package/dist/providers/auth/index.d.ts +11 -0
- package/dist/providers/auth/index.js +20 -0
- package/dist/providers/auth/release-gate.d.ts +1 -0
- package/dist/providers/auth/release-gate.js +4 -0
- package/dist/providers/auth/self-hosted.d.ts +78 -0
- package/dist/providers/auth/self-hosted.js +377 -0
- package/dist/providers/auth/subject.d.ts +1 -0
- package/dist/providers/auth/subject.js +6 -0
- package/dist/providers/auth/types.d.ts +63 -0
- package/dist/providers/auth/types.js +22 -0
- package/dist/providers/coding-proxy/deny-port.d.ts +5 -0
- package/dist/providers/coding-proxy/deny-port.js +45 -0
- package/dist/providers/coding-proxy/environment-credentials.d.ts +7 -0
- package/dist/providers/coding-proxy/environment-credentials.js +16 -0
- package/dist/providers/coding-proxy/index.d.ts +7 -0
- package/dist/providers/coding-proxy/index.js +7 -0
- package/dist/providers/coding-proxy/memory-ledger.d.ts +17 -0
- package/dist/providers/coding-proxy/memory-ledger.js +103 -0
- package/dist/providers/coding-proxy/metering.d.ts +20 -0
- package/dist/providers/coding-proxy/metering.js +161 -0
- package/dist/providers/coding-proxy/prisma-ledger.d.ts +15 -0
- package/dist/providers/coding-proxy/prisma-ledger.js +213 -0
- package/dist/providers/coding-proxy/proxy.d.ts +75 -0
- package/dist/providers/coding-proxy/proxy.js +721 -0
- package/dist/providers/coding-proxy/runtime.d.ts +18 -0
- package/dist/providers/coding-proxy/runtime.js +39 -0
- package/dist/providers/coding-proxy/secure-fetch.d.ts +9 -0
- package/dist/providers/coding-proxy/secure-fetch.js +72 -0
- package/dist/providers/coding-proxy/server.d.ts +17 -0
- package/dist/providers/coding-proxy/server.js +139 -0
- package/dist/providers/coding-proxy/types.d.ts +99 -0
- package/dist/providers/coding-proxy/types.js +1 -0
- package/dist/providers/datastore/index.d.ts +2 -0
- package/dist/providers/datastore/index.js +2 -0
- package/dist/providers/datastore/postgres.d.ts +20 -0
- package/dist/providers/datastore/postgres.js +130 -0
- package/dist/providers/datastore/scoped.d.ts +10 -0
- package/dist/providers/datastore/scoped.js +46 -0
- package/dist/providers/datastore/types.d.ts +31 -0
- package/dist/providers/datastore/types.js +7 -0
- package/dist/providers/email/types.d.ts +46 -0
- package/dist/providers/email/types.js +8 -0
- package/dist/providers/engine/index.d.ts +1 -0
- package/dist/providers/engine/index.js +1 -0
- package/dist/providers/engine/types.d.ts +67 -0
- package/dist/providers/engine/types.js +16 -0
- package/dist/providers/executor/build.d.ts +6 -0
- package/dist/providers/executor/build.js +15 -0
- package/dist/providers/executor/composition.d.ts +14 -0
- package/dist/providers/executor/composition.js +123 -0
- package/dist/providers/executor/container.d.ts +184 -0
- package/dist/providers/executor/container.js +936 -0
- package/dist/providers/executor/dbos-status.d.ts +50 -0
- package/dist/providers/executor/dbos-status.js +64 -0
- package/dist/providers/executor/dbos.d.ts +53 -0
- package/dist/providers/executor/dbos.js +269 -0
- package/dist/providers/executor/in-process.d.ts +18 -0
- package/dist/providers/executor/in-process.js +38 -0
- package/dist/providers/executor/index.d.ts +8 -0
- package/dist/providers/executor/index.js +8 -0
- package/dist/providers/executor/routing.d.ts +48 -0
- package/dist/providers/executor/routing.js +70 -0
- package/dist/providers/executor/types.d.ts +55 -0
- package/dist/providers/executor/types.js +1 -0
- package/dist/providers/index.d.ts +43 -0
- package/dist/providers/index.js +18 -0
- package/dist/providers/jobs/docker-isolation.d.ts +166 -0
- package/dist/providers/jobs/docker-isolation.js +724 -0
- package/dist/providers/jobs/docker.d.ts +127 -0
- package/dist/providers/jobs/docker.js +1027 -0
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +98 -0
- package/dist/providers/jobs/fake-kubernetes-api.js +142 -0
- package/dist/providers/jobs/fake.d.ts +23 -0
- package/dist/providers/jobs/fake.js +132 -0
- package/dist/providers/jobs/kubernetes-api.d.ts +60 -0
- package/dist/providers/jobs/kubernetes-api.js +20 -0
- package/dist/providers/jobs/kubernetes-client.d.ts +36 -0
- package/dist/providers/jobs/kubernetes-client.js +171 -0
- package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +49 -0
- package/dist/providers/jobs/kubernetes-dry-run-fixture.js +141 -0
- package/dist/providers/jobs/kubernetes-isolation.d.ts +147 -0
- package/dist/providers/jobs/kubernetes-isolation.js +607 -0
- package/dist/providers/jobs/kubernetes-platform.d.ts +177 -0
- package/dist/providers/jobs/kubernetes-platform.js +280 -0
- package/dist/providers/jobs/kubernetes-preflight.d.ts +59 -0
- package/dist/providers/jobs/kubernetes-preflight.js +339 -0
- package/dist/providers/jobs/kubernetes-witness.d.ts +10 -0
- package/dist/providers/jobs/kubernetes-witness.js +193 -0
- package/dist/providers/jobs/kubernetes.d.ts +127 -0
- package/dist/providers/jobs/kubernetes.js +874 -0
- package/dist/providers/jobs/safe-extract.d.ts +9 -0
- package/dist/providers/jobs/safe-extract.js +325 -0
- package/dist/providers/jobs/types.d.ts +78 -0
- package/dist/providers/jobs/types.js +6 -0
- package/dist/providers/jobs/workspace-swap.d.ts +2 -0
- package/dist/providers/jobs/workspace-swap.js +47 -0
- package/dist/providers/llm/anthropic.d.ts +13 -0
- package/dist/providers/llm/anthropic.js +21 -0
- package/dist/providers/llm/bedrock.d.ts +19 -0
- package/dist/providers/llm/bedrock.js +33 -0
- package/dist/providers/llm/claude-messages.d.ts +106 -0
- package/dist/providers/llm/claude-messages.js +157 -0
- package/dist/providers/llm/claude-provider.d.ts +40 -0
- package/dist/providers/llm/claude-provider.js +31 -0
- package/dist/providers/llm/index.d.ts +10 -0
- package/dist/providers/llm/index.js +10 -0
- package/dist/providers/llm/openai.d.ts +23 -0
- package/dist/providers/llm/openai.js +156 -0
- package/dist/providers/llm/pricing-anthropic.d.ts +4 -0
- package/dist/providers/llm/pricing-anthropic.js +30 -0
- package/dist/providers/llm/pricing-bedrock-claude.d.ts +12 -0
- package/dist/providers/llm/pricing-bedrock-claude.js +37 -0
- package/dist/providers/llm/pricing-core.d.ts +26 -0
- package/dist/providers/llm/pricing-core.js +17 -0
- package/dist/providers/llm/pricing.d.ts +30 -0
- package/dist/providers/llm/pricing.js +74 -0
- package/dist/providers/llm/registration.d.ts +8 -0
- package/dist/providers/llm/registration.js +39 -0
- package/dist/providers/llm/routing.d.ts +25 -0
- package/dist/providers/llm/routing.js +32 -0
- package/dist/providers/llm/types.d.ts +85 -0
- package/dist/providers/llm/types.js +12 -0
- package/dist/providers/memory/index.d.ts +2 -0
- package/dist/providers/memory/index.js +2 -0
- package/dist/providers/memory/postgres.d.ts +20 -0
- package/dist/providers/memory/postgres.js +72 -0
- package/dist/providers/memory/types.d.ts +32 -0
- package/dist/providers/memory/types.js +17 -0
- package/dist/providers/secrets/app-key.d.ts +8 -0
- package/dist/providers/secrets/app-key.js +50 -0
- package/dist/providers/secrets/index.d.ts +10 -0
- package/dist/providers/secrets/index.js +13 -0
- package/dist/providers/secrets/transfer-envelope.d.ts +12 -0
- package/dist/providers/secrets/transfer-envelope.js +35 -0
- package/dist/providers/secrets/types.d.ts +18 -0
- package/dist/providers/secrets/types.js +12 -0
- package/dist/providers/storage/types.d.ts +18 -0
- package/dist/providers/storage/types.js +7 -0
- package/dist/providers/vcs/git.d.ts +105 -0
- package/dist/providers/vcs/git.js +710 -0
- package/dist/providers/vcs/github.d.ts +105 -0
- package/dist/providers/vcs/github.js +394 -0
- package/dist/providers/vcs/index.d.ts +6 -0
- package/dist/providers/vcs/index.js +26 -0
- package/dist/providers/vcs/types.d.ts +118 -0
- package/dist/providers/vcs/types.js +1 -0
- package/dist/sandbox/bounded-json.d.ts +2 -0
- package/dist/sandbox/bounded-json.js +36 -0
- package/dist/sandbox/bridge.d.ts +15 -0
- package/dist/sandbox/bridge.js +78 -0
- package/dist/sandbox/eval-core.d.ts +37 -0
- package/dist/sandbox/eval-core.js +159 -0
- package/dist/sandbox/fetch-policy.d.ts +24 -0
- package/dist/sandbox/fetch-policy.js +96 -0
- package/dist/sandbox/generated/zod-to-json-schema.bundle.js +5 -0
- package/dist/sandbox/generated/zod.bundle.js +1 -0
- package/dist/sandbox/host-functions.d.ts +29 -0
- package/dist/sandbox/host-functions.js +168 -0
- package/dist/sandbox/limits.d.ts +39 -0
- package/dist/sandbox/limits.js +39 -0
- package/dist/sandbox/parser-worker/__fixtures__/crash.d.ts +1 -0
- package/dist/sandbox/parser-worker/__fixtures__/crash.js +6 -0
- package/dist/sandbox/parser-worker/__fixtures__/echo.d.ts +1 -0
- package/dist/sandbox/parser-worker/__fixtures__/echo.js +5 -0
- package/dist/sandbox/parser-worker/__fixtures__/reject.d.ts +1 -0
- package/dist/sandbox/parser-worker/__fixtures__/reject.js +5 -0
- package/dist/sandbox/parser-worker/__fixtures__/spin-forever.d.ts +1 -0
- package/dist/sandbox/parser-worker/__fixtures__/spin-forever.js +11 -0
- package/dist/sandbox/parser-worker/pool.d.ts +13 -0
- package/dist/sandbox/parser-worker/pool.js +111 -0
- package/dist/sandbox/parser-worker/worker.d.ts +14 -0
- package/dist/sandbox/parser-worker/worker.js +63 -0
- package/dist/sandbox/pii-redaction.d.ts +1 -0
- package/dist/sandbox/pii-redaction.js +29 -0
- package/dist/sandbox/prelude.d.ts +26 -0
- package/dist/sandbox/prelude.js +408 -0
- package/dist/sandbox/quickjs-module.d.ts +13 -0
- package/dist/sandbox/quickjs-module.js +19 -0
- package/dist/sandbox/run-in-sandbox.d.ts +34 -0
- package/dist/sandbox/run-in-sandbox.js +53 -0
- package/dist/sandbox/safe-fetch.d.ts +26 -0
- package/dist/sandbox/safe-fetch.js +140 -0
- package/dist/sandbox/tool-capabilities.d.ts +66 -0
- package/dist/sandbox/tool-capabilities.js +103 -0
- package/dist/sandbox/zod-params.d.ts +22 -0
- package/dist/sandbox/zod-params.js +60 -0
- package/dist/serve.d.ts +14 -0
- package/dist/serve.js +54 -0
- package/dist/wardby-bin.d.ts +2 -0
- package/dist/wardby-bin.js +20 -0
- package/package.json +123 -0
- package/prisma/migrations/20260905000000_init/migration.sql +34 -0
- package/prisma/migrations/20260905010000_scheduler_durability/migration.sql +31 -0
- package/prisma/migrations/20260905020000_tools_multiturn/migration.sql +47 -0
- package/prisma/migrations/20260905030000_cache_tool_json_schema/migration.sql +13 -0
- package/prisma/migrations/20260906000000_mcp_phase4/migration.sql +115 -0
- package/prisma/migrations/20260906010000_run_final_text/migration.sql +7 -0
- package/prisma/migrations/20260906020000_run_turns/migration.sql +6 -0
- package/prisma/migrations/20260906030000_task_principal_id/migration.sql +5 -0
- package/prisma/migrations/20260906040000_secure_self_hosted_oauth/migration.sql +67 -0
- package/prisma/migrations/20260906050000_phase5_coding_agents/migration.sql +52 -0
- package/prisma/migrations/20260906060000_tool_capability_scoping/migration.sql +22 -0
- package/prisma/migrations/20260906070000_datastore_pii_flag/migration.sql +6 -0
- package/prisma/migrations/20260906080000_secret_elicitation_outcomes/migration.sql +13 -0
- package/prisma/migrations/20260907010000_coding_proxy_ledger/migration.sql +57 -0
- package/prisma/migrations/20260907020000_budget_groups/migration.sql +24 -0
- package/prisma/migrations/20260907030000_coding_webhook_task_override/migration.sql +4 -0
- package/prisma/migrations/20260908010000_run_execution_backend/migration.sql +2 -0
- package/prisma/migrations/20260908020000_coding_run_audit_metadata/migration.sql +7 -0
- package/prisma/migrations/20260910010000_agent_secret_bound_name/migration.sql +16 -0
- package/prisma/migrations/20260911010000_coding_worker_toolchains/migration.sql +5 -0
- package/prisma/migrations/20260912010000_coding_provider_contract/migration.sql +24 -0
- package/prisma/migrations/20260912020000_coding_proxy_protocol/migration.sql +10 -0
- package/prisma/migrations/20260912030000_agent_memory/migration.sql +18 -0
- package/prisma/migrations/20260912040000_named_shared_datastores/migration.sql +68 -0
- package/prisma/migrations/20260913000000_run_trigger_webhook/migration.sql +2 -0
- package/prisma/migrations/20260913010000_agent_sub_agent/migration.sql +32 -0
- package/prisma/migrations/20260913020000_run_task_override/migration.sql +5 -0
- package/prisma/migrations/20260913030000_coding_run_root/migration.sql +11 -0
- package/prisma/migrations/20260922010000_coding_run_queued_at/migration.sql +8 -0
- package/prisma/migrations/20260922020000_coding_workspace_disk/migration.sql +8 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +723 -0
- package/scripts/git-askpass.sh +11 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
/** Serve the Prometheus exposition endpoint on an explicitly private listener. */
|
|
3
|
+
export async function startMetricsServer(registry, config) {
|
|
4
|
+
const server = createServer({ maxHeaderSize: 8 * 1024, requireHostHeader: false }, (request, response) => {
|
|
5
|
+
void (async () => {
|
|
6
|
+
if (request.method === "GET" && request.url === "/healthz") {
|
|
7
|
+
response
|
|
8
|
+
.writeHead(200, { "cache-control": "no-store", "content-type": "text/plain; charset=utf-8" })
|
|
9
|
+
.end("ok\n");
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (request.method === "GET" && request.url === "/metrics") {
|
|
13
|
+
response
|
|
14
|
+
.writeHead(200, { "cache-control": "no-store", "content-type": registry.contentType })
|
|
15
|
+
.end(await registry.metrics());
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
response
|
|
19
|
+
.writeHead(404, { "cache-control": "no-store", "content-type": "text/plain; charset=utf-8" })
|
|
20
|
+
.end("not found\n");
|
|
21
|
+
})().catch(() => {
|
|
22
|
+
if (!response.headersSent) {
|
|
23
|
+
response
|
|
24
|
+
.writeHead(500, { "cache-control": "no-store", "content-type": "text/plain; charset=utf-8" })
|
|
25
|
+
.end("internal error\n");
|
|
26
|
+
}
|
|
27
|
+
else if (!response.destroyed) {
|
|
28
|
+
response.destroy();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
server.requestTimeout = 10_000;
|
|
33
|
+
server.headersTimeout = 10_000;
|
|
34
|
+
server.keepAliveTimeout = 5_000;
|
|
35
|
+
await new Promise((resolve, reject) => {
|
|
36
|
+
server.once("error", reject);
|
|
37
|
+
server.listen(config.port, config.host, resolve);
|
|
38
|
+
});
|
|
39
|
+
const address = server.address();
|
|
40
|
+
return {
|
|
41
|
+
port: typeof address === "object" && address ? address.port : config.port,
|
|
42
|
+
close: () => new Promise((resolve, reject) => {
|
|
43
|
+
server.close((error) => (error ? reject(error) : resolve()));
|
|
44
|
+
server.closeIdleConnections();
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Registry } from "@prometheus-io/client";
|
|
2
|
+
import type { CodingLifecycleEvent, CodingRunObserver } from "../coding/observability.js";
|
|
3
|
+
import type { ProxyAuditEvent } from "../providers/coding-proxy/types.js";
|
|
4
|
+
type ProxyProtocolLabel = "openai-responses" | "anthropic-messages" | "other";
|
|
5
|
+
export interface ProxyHttpMetricEvent {
|
|
6
|
+
protocol: ProxyProtocolLabel;
|
|
7
|
+
status: number;
|
|
8
|
+
durationMs: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Prometheus adapter for the metadata-only lifecycle and proxy audit signals.
|
|
12
|
+
* Labels are deliberately finite enums: run IDs, request IDs, models, reasons,
|
|
13
|
+
* credentials, and untrusted input never enter the metrics registry.
|
|
14
|
+
*/
|
|
15
|
+
export declare class WardbyMetrics implements CodingRunObserver {
|
|
16
|
+
readonly registry: Registry;
|
|
17
|
+
private readonly lifecycleEvents;
|
|
18
|
+
private readonly terminalRuns;
|
|
19
|
+
private readonly activeJobs;
|
|
20
|
+
private readonly cleanupFailures;
|
|
21
|
+
private readonly budgetReserved;
|
|
22
|
+
private readonly budgetActual;
|
|
23
|
+
private readonly runDuration;
|
|
24
|
+
private readonly proxyAuditEvents;
|
|
25
|
+
private readonly proxyRequests;
|
|
26
|
+
private readonly proxyRequestDuration;
|
|
27
|
+
private readonly proxyBudgetReserved;
|
|
28
|
+
private readonly proxyCost;
|
|
29
|
+
private readonly proxyTokens;
|
|
30
|
+
private activeJobCount;
|
|
31
|
+
constructor(registry?: Registry<import("@prometheus-io/client").RegistryContentType>);
|
|
32
|
+
emit(event: CodingLifecycleEvent): void;
|
|
33
|
+
observeProxyAudit: (event: ProxyAuditEvent) => void;
|
|
34
|
+
observeProxyRequest(event: ProxyHttpMetricEvent): void;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { Counter, Gauge, Histogram, Registry, collectDefaultMetrics } from "@prometheus-io/client";
|
|
2
|
+
function statusClass(status) {
|
|
3
|
+
if (status >= 100 && status < 200)
|
|
4
|
+
return "1xx";
|
|
5
|
+
if (status >= 200 && status < 300)
|
|
6
|
+
return "2xx";
|
|
7
|
+
if (status >= 300 && status < 400)
|
|
8
|
+
return "3xx";
|
|
9
|
+
if (status >= 400 && status < 500)
|
|
10
|
+
return "4xx";
|
|
11
|
+
if (status >= 500 && status < 600)
|
|
12
|
+
return "5xx";
|
|
13
|
+
return "other";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Prometheus adapter for the metadata-only lifecycle and proxy audit signals.
|
|
17
|
+
* Labels are deliberately finite enums: run IDs, request IDs, models, reasons,
|
|
18
|
+
* credentials, and untrusted input never enter the metrics registry.
|
|
19
|
+
*/
|
|
20
|
+
export class WardbyMetrics {
|
|
21
|
+
registry;
|
|
22
|
+
lifecycleEvents;
|
|
23
|
+
terminalRuns;
|
|
24
|
+
activeJobs;
|
|
25
|
+
cleanupFailures;
|
|
26
|
+
budgetReserved;
|
|
27
|
+
budgetActual;
|
|
28
|
+
runDuration;
|
|
29
|
+
proxyAuditEvents;
|
|
30
|
+
proxyRequests;
|
|
31
|
+
proxyRequestDuration;
|
|
32
|
+
proxyBudgetReserved;
|
|
33
|
+
proxyCost;
|
|
34
|
+
proxyTokens;
|
|
35
|
+
activeJobCount = 0;
|
|
36
|
+
constructor(registry = new Registry()) {
|
|
37
|
+
this.registry = registry;
|
|
38
|
+
collectDefaultMetrics({ register: registry, prefix: "wardby_nodejs_" });
|
|
39
|
+
this.lifecycleEvents = new Counter({
|
|
40
|
+
name: "wardby_coding_lifecycle_events_total",
|
|
41
|
+
help: "Coding lifecycle events by finite stage.",
|
|
42
|
+
labelNames: ["stage"],
|
|
43
|
+
registers: [registry],
|
|
44
|
+
});
|
|
45
|
+
this.terminalRuns = new Counter({
|
|
46
|
+
name: "wardby_coding_runs_terminal_total",
|
|
47
|
+
help: "Completed coding runs by terminal outcome.",
|
|
48
|
+
labelNames: ["outcome"],
|
|
49
|
+
registers: [registry],
|
|
50
|
+
});
|
|
51
|
+
this.activeJobs = new Gauge({
|
|
52
|
+
name: "wardby_coding_active_jobs",
|
|
53
|
+
help: "Coding jobs launched by this process that have not completed cleanup.",
|
|
54
|
+
registers: [registry],
|
|
55
|
+
});
|
|
56
|
+
this.cleanupFailures = new Counter({
|
|
57
|
+
name: "wardby_coding_cleanup_failures_total",
|
|
58
|
+
help: "Coding cleanup attempts that failed.",
|
|
59
|
+
registers: [registry],
|
|
60
|
+
});
|
|
61
|
+
this.budgetReserved = new Counter({
|
|
62
|
+
name: "wardby_coding_budget_reserved_usd_total",
|
|
63
|
+
help: "USD budget reserved for coding runs.",
|
|
64
|
+
registers: [registry],
|
|
65
|
+
});
|
|
66
|
+
this.budgetActual = new Counter({
|
|
67
|
+
name: "wardby_coding_budget_actual_usd_total",
|
|
68
|
+
help: "USD budget charged for coding runs.",
|
|
69
|
+
registers: [registry],
|
|
70
|
+
});
|
|
71
|
+
this.runDuration = new Histogram({
|
|
72
|
+
name: "wardby_coding_run_duration_seconds",
|
|
73
|
+
help: "Observed coding run duration in seconds.",
|
|
74
|
+
buckets: [1, 10, 30, 60, 300, 900, 1800, 3600],
|
|
75
|
+
registers: [registry],
|
|
76
|
+
});
|
|
77
|
+
this.proxyAuditEvents = new Counter({
|
|
78
|
+
name: "wardby_proxy_audit_events_total",
|
|
79
|
+
help: "Trusted coding proxy audit events by finite event type.",
|
|
80
|
+
labelNames: ["event"],
|
|
81
|
+
registers: [registry],
|
|
82
|
+
});
|
|
83
|
+
this.proxyRequests = new Counter({
|
|
84
|
+
name: "wardby_proxy_http_requests_total",
|
|
85
|
+
help: "Coding proxy HTTP requests by protocol and status class.",
|
|
86
|
+
labelNames: ["protocol", "status_class"],
|
|
87
|
+
registers: [registry],
|
|
88
|
+
});
|
|
89
|
+
this.proxyRequestDuration = new Histogram({
|
|
90
|
+
name: "wardby_proxy_http_request_duration_seconds",
|
|
91
|
+
help: "Coding proxy HTTP request duration by protocol and status class.",
|
|
92
|
+
labelNames: ["protocol", "status_class"],
|
|
93
|
+
buckets: [0.01, 0.05, 0.1, 0.5, 1, 5, 15, 60, 300],
|
|
94
|
+
registers: [registry],
|
|
95
|
+
});
|
|
96
|
+
this.proxyBudgetReserved = new Counter({
|
|
97
|
+
name: "wardby_proxy_budget_reserved_usd_total",
|
|
98
|
+
help: "USD budget reserved by trusted coding proxy requests.",
|
|
99
|
+
registers: [registry],
|
|
100
|
+
});
|
|
101
|
+
this.proxyCost = new Counter({
|
|
102
|
+
name: "wardby_proxy_cost_usd_total",
|
|
103
|
+
help: "USD cost reported by completed upstream proxy responses.",
|
|
104
|
+
registers: [registry],
|
|
105
|
+
});
|
|
106
|
+
this.proxyTokens = new Counter({
|
|
107
|
+
name: "wardby_proxy_tokens_total",
|
|
108
|
+
help: "Token usage reported by completed upstream proxy responses by token kind.",
|
|
109
|
+
labelNames: ["kind"],
|
|
110
|
+
registers: [registry],
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
emit(event) {
|
|
114
|
+
this.lifecycleEvents.inc({ stage: event.stage });
|
|
115
|
+
if (event.stage === "launched") {
|
|
116
|
+
this.activeJobCount += 1;
|
|
117
|
+
this.activeJobs.set(this.activeJobCount);
|
|
118
|
+
}
|
|
119
|
+
if (event.stage === "cleanup") {
|
|
120
|
+
this.activeJobCount = Math.max(0, this.activeJobCount - 1);
|
|
121
|
+
this.activeJobs.set(this.activeJobCount);
|
|
122
|
+
if (event.cleanupSucceeded === false)
|
|
123
|
+
this.cleanupFailures.inc();
|
|
124
|
+
}
|
|
125
|
+
if (event.stage === "terminal" && event.outcome)
|
|
126
|
+
this.terminalRuns.inc({ outcome: event.outcome });
|
|
127
|
+
if (event.budgetReservedUsd !== undefined)
|
|
128
|
+
this.budgetReserved.inc(event.budgetReservedUsd);
|
|
129
|
+
if (event.budgetActualUsd !== undefined)
|
|
130
|
+
this.budgetActual.inc(event.budgetActualUsd);
|
|
131
|
+
if (event.durationMs !== undefined)
|
|
132
|
+
this.runDuration.observe(event.durationMs / 1_000);
|
|
133
|
+
}
|
|
134
|
+
observeProxyAudit = (event) => {
|
|
135
|
+
this.proxyAuditEvents.inc({ event: event.type });
|
|
136
|
+
if (event.reservationUsd !== undefined)
|
|
137
|
+
this.proxyBudgetReserved.inc(event.reservationUsd);
|
|
138
|
+
if (event.type !== "response.completed")
|
|
139
|
+
return;
|
|
140
|
+
if (event.costUsd !== undefined)
|
|
141
|
+
this.proxyCost.inc(event.costUsd);
|
|
142
|
+
if (event.inputTokens !== undefined)
|
|
143
|
+
this.proxyTokens.inc({ kind: "input" }, event.inputTokens);
|
|
144
|
+
if (event.outputTokens !== undefined)
|
|
145
|
+
this.proxyTokens.inc({ kind: "output" }, event.outputTokens);
|
|
146
|
+
if (event.cachedInputTokens !== undefined)
|
|
147
|
+
this.proxyTokens.inc({ kind: "cached_input" }, event.cachedInputTokens);
|
|
148
|
+
if (event.cacheWriteTokens !== undefined)
|
|
149
|
+
this.proxyTokens.inc({ kind: "cache_write" }, event.cacheWriteTokens);
|
|
150
|
+
if (event.reasoningTokens !== undefined)
|
|
151
|
+
this.proxyTokens.inc({ kind: "reasoning" }, event.reasoningTokens);
|
|
152
|
+
};
|
|
153
|
+
observeProxyRequest(event) {
|
|
154
|
+
const labels = { protocol: event.protocol, status_class: statusClass(event.status) };
|
|
155
|
+
this.proxyRequests.inc(labels);
|
|
156
|
+
this.proxyRequestDuration.observe(labels, event.durationMs / 1_000);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface SelfHostedAuthConfig {
|
|
2
|
+
canonicalUri: string;
|
|
3
|
+
signingKey: string;
|
|
4
|
+
credentialHashKey: string;
|
|
5
|
+
maxClients?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface RegisterClientParams {
|
|
8
|
+
redirectUris: string[];
|
|
9
|
+
clientName?: string;
|
|
10
|
+
grantTypes?: string[];
|
|
11
|
+
tokenEndpointAuthMethod?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface AuthorizeParams {
|
|
14
|
+
clientId: string;
|
|
15
|
+
redirectUri: string;
|
|
16
|
+
codeChallenge: string;
|
|
17
|
+
codeChallengeMethod: string;
|
|
18
|
+
scope: string;
|
|
19
|
+
resource: string;
|
|
20
|
+
state?: string;
|
|
21
|
+
}
|
|
22
|
+
export type TokenParams = {
|
|
23
|
+
grantType: "authorization_code";
|
|
24
|
+
code: string;
|
|
25
|
+
codeVerifier: string;
|
|
26
|
+
redirectUri: string;
|
|
27
|
+
clientId: string;
|
|
28
|
+
resource?: string;
|
|
29
|
+
} | {
|
|
30
|
+
grantType: "refresh_token";
|
|
31
|
+
refreshToken: string;
|
|
32
|
+
clientId: string;
|
|
33
|
+
resource?: string;
|
|
34
|
+
};
|
|
35
|
+
export interface TokenResult {
|
|
36
|
+
accessToken: string;
|
|
37
|
+
tokenType: "Bearer";
|
|
38
|
+
expiresIn: number;
|
|
39
|
+
refreshToken: string;
|
|
40
|
+
scope: string;
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource-server-only AuthProvider: wardby never issues tokens itself, an
|
|
3
|
+
* external OIDC/OAuth IdP is the authorization server. verifyBearer is the
|
|
4
|
+
* whole job — validate a caller-supplied access token (signature via JWKS,
|
|
5
|
+
* audience, expiry, issuer) and map its claims to a VerifiedToken (subject
|
|
6
|
+
* + per-token scopes). The auth-code flow methods (authorizeUrl/
|
|
7
|
+
* exchangeCode/refresh) belong to the external IdP, not to wardby, so they
|
|
8
|
+
* throw rather than half-implement a flow this adapter doesn't own.
|
|
9
|
+
*/
|
|
10
|
+
import { type JWTVerifyGetKey } from "jose";
|
|
11
|
+
import type { AuthProfile, AuthProvider, AuthTokens, VerifiedToken } from "./types.js";
|
|
12
|
+
export interface DelegatingAuthConfig {
|
|
13
|
+
issuer?: string;
|
|
14
|
+
audience?: string;
|
|
15
|
+
jwksUri?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Every spelling of the configured audience a token may legitimately carry.
|
|
19
|
+
*
|
|
20
|
+
* `aud` is compared as an exact string, but for an http(s) URI an empty path
|
|
21
|
+
* and "/" denote the same resource (RFC 3986 §6.2.3) — and the two halves of
|
|
22
|
+
* this system disagree about which spelling to use. The protected-resource
|
|
23
|
+
* metadata advertises the normalized ("/") form, so a spec-compliant client
|
|
24
|
+
* asks its IdP for that; an IdP whose audience is configured from a
|
|
25
|
+
* hand-written identifier (Auth0's API Identifier, say) echoes back whatever
|
|
26
|
+
* the operator typed, usually without the slash. Matching only one form
|
|
27
|
+
* rejects real tokens from the other, and the startup check in
|
|
28
|
+
* mcp/index.ts normalizes both sides, so the misconfiguration passes
|
|
29
|
+
* validation and only surfaces as an opaque invalid_token at request time.
|
|
30
|
+
*
|
|
31
|
+
* A non-URL audience (some IdPs use opaque identifiers) has exactly one form.
|
|
32
|
+
*/
|
|
33
|
+
export declare function audienceCandidates(audience: string): string[];
|
|
34
|
+
export declare class DelegatingAuthProvider implements AuthProvider {
|
|
35
|
+
private readonly config;
|
|
36
|
+
private readonly audiences;
|
|
37
|
+
private readonly jwks;
|
|
38
|
+
constructor(config: DelegatingAuthConfig, jwks?: JWTVerifyGetKey);
|
|
39
|
+
verifyBearer(token: string): Promise<VerifiedToken>;
|
|
40
|
+
profile(idToken: string): Promise<AuthProfile>;
|
|
41
|
+
authorizeUrl(_state: string, _redirectUri: string): string;
|
|
42
|
+
exchangeCode(_code: string, _redirectUri: string): Promise<AuthTokens>;
|
|
43
|
+
refresh(_refreshToken: string): Promise<AuthTokens>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource-server-only AuthProvider: wardby never issues tokens itself, an
|
|
3
|
+
* external OIDC/OAuth IdP is the authorization server. verifyBearer is the
|
|
4
|
+
* whole job — validate a caller-supplied access token (signature via JWKS,
|
|
5
|
+
* audience, expiry, issuer) and map its claims to a VerifiedToken (subject
|
|
6
|
+
* + per-token scopes). The auth-code flow methods (authorizeUrl/
|
|
7
|
+
* exchangeCode/refresh) belong to the external IdP, not to wardby, so they
|
|
8
|
+
* throw rather than half-implement a flow this adapter doesn't own.
|
|
9
|
+
*/
|
|
10
|
+
import { createRemoteJWKSet, jwtVerify, errors as joseErrors } from "jose";
|
|
11
|
+
import { AudienceError, NotSupportedError } from "./types.js";
|
|
12
|
+
import { requireSubject } from "./subject.js";
|
|
13
|
+
/**
|
|
14
|
+
* Every spelling of the configured audience a token may legitimately carry.
|
|
15
|
+
*
|
|
16
|
+
* `aud` is compared as an exact string, but for an http(s) URI an empty path
|
|
17
|
+
* and "/" denote the same resource (RFC 3986 §6.2.3) — and the two halves of
|
|
18
|
+
* this system disagree about which spelling to use. The protected-resource
|
|
19
|
+
* metadata advertises the normalized ("/") form, so a spec-compliant client
|
|
20
|
+
* asks its IdP for that; an IdP whose audience is configured from a
|
|
21
|
+
* hand-written identifier (Auth0's API Identifier, say) echoes back whatever
|
|
22
|
+
* the operator typed, usually without the slash. Matching only one form
|
|
23
|
+
* rejects real tokens from the other, and the startup check in
|
|
24
|
+
* mcp/index.ts normalizes both sides, so the misconfiguration passes
|
|
25
|
+
* validation and only surfaces as an opaque invalid_token at request time.
|
|
26
|
+
*
|
|
27
|
+
* A non-URL audience (some IdPs use opaque identifiers) has exactly one form.
|
|
28
|
+
*/
|
|
29
|
+
export function audienceCandidates(audience) {
|
|
30
|
+
try {
|
|
31
|
+
const url = new URL(audience);
|
|
32
|
+
const forms = [audience, url.href];
|
|
33
|
+
// Only an empty path is interchangeable with "/". A trailing slash on a
|
|
34
|
+
// non-empty path ("…/mcp/" vs "…/mcp") is significant, so those stay
|
|
35
|
+
// distinct resources and keep matching strictly.
|
|
36
|
+
if (url.pathname === "/")
|
|
37
|
+
forms.push(url.href.replace(/\/$/, ""));
|
|
38
|
+
return [...new Set(forms)];
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return [audience];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Splits an OAuth `scope`/`scp` claim (space-delimited string, or already an array) into scopes. */
|
|
45
|
+
function scopesFromClaim(claim) {
|
|
46
|
+
if (Array.isArray(claim))
|
|
47
|
+
return claim.map(String);
|
|
48
|
+
if (typeof claim === "string")
|
|
49
|
+
return claim.split(/\s+/).filter(Boolean);
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
export class DelegatingAuthProvider {
|
|
53
|
+
config;
|
|
54
|
+
audiences;
|
|
55
|
+
jwks;
|
|
56
|
+
constructor(config, jwks) {
|
|
57
|
+
if (!config.issuer || !config.audience)
|
|
58
|
+
throw new Error("AUTH_ISSUER and AUTH_AUDIENCE are required.");
|
|
59
|
+
this.config = config;
|
|
60
|
+
this.audiences = audienceCandidates(config.audience);
|
|
61
|
+
if (jwks) {
|
|
62
|
+
this.jwks = jwks;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
if (!config.jwksUri) {
|
|
66
|
+
throw new Error("AUTH_JWKS_URI is not set — required by the delegating AuthProvider adapter.");
|
|
67
|
+
}
|
|
68
|
+
this.jwks = createRemoteJWKSet(new URL(config.jwksUri));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async verifyBearer(token) {
|
|
72
|
+
try {
|
|
73
|
+
const { payload } = await jwtVerify(token, this.jwks, {
|
|
74
|
+
issuer: this.config.issuer,
|
|
75
|
+
audience: this.audiences,
|
|
76
|
+
requiredClaims: ["sub", "exp", "iss", "aud"],
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
subject: requireSubject(payload.sub),
|
|
80
|
+
email: typeof payload.email === "string" ? payload.email : undefined,
|
|
81
|
+
roles: Array.isArray(payload.roles) ? payload.roles.map(String) : [],
|
|
82
|
+
scopes: scopesFromClaim(payload.scope ?? payload.scp),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
if (err instanceof joseErrors.JWTClaimValidationFailed && err.claim === "aud") {
|
|
87
|
+
throw new AudienceError(`Token audience does not match the configured resource ("${this.config.audience}").`);
|
|
88
|
+
}
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async profile(idToken) {
|
|
93
|
+
const verified = await this.verifyBearer(idToken);
|
|
94
|
+
return { subject: verified.subject, email: verified.email, roles: verified.roles ?? [] };
|
|
95
|
+
}
|
|
96
|
+
authorizeUrl(_state, _redirectUri) {
|
|
97
|
+
throw new NotSupportedError("DelegatingAuthProvider is resource-server-only; the external IdP's own authorization endpoint issues tokens.");
|
|
98
|
+
}
|
|
99
|
+
async exchangeCode(_code, _redirectUri) {
|
|
100
|
+
throw new NotSupportedError("DelegatingAuthProvider is resource-server-only; the external IdP's own token endpoint issues tokens.");
|
|
101
|
+
}
|
|
102
|
+
async refresh(_refreshToken) {
|
|
103
|
+
throw new NotSupportedError("DelegatingAuthProvider is resource-server-only; the external IdP's own token endpoint handles refresh.");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuthProvider selector — builds the adapter for the configured AUTH_PROVIDER
|
|
3
|
+
* kind. Both adapters implement the same AuthProvider (incl. verifyBearer),
|
|
4
|
+
* so the resource-server middleware and tool handlers never branch on mode.
|
|
5
|
+
*/
|
|
6
|
+
import type { PrismaClient } from "@prisma/client";
|
|
7
|
+
import type { AuthProviderKind, AuthConfig } from "../../config/providers.js";
|
|
8
|
+
import type { AuthProvider } from "./types.js";
|
|
9
|
+
export { DelegatingAuthProvider } from "./delegating.js";
|
|
10
|
+
export { SelfHostedAuthProvider } from "./self-hosted.js";
|
|
11
|
+
export declare function buildAuthProvider(kind: AuthProviderKind, config: AuthConfig, db: PrismaClient): AuthProvider;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DelegatingAuthProvider } from "./delegating.js";
|
|
2
|
+
import { SelfHostedAuthProvider } from "./self-hosted.js";
|
|
3
|
+
export { DelegatingAuthProvider } from "./delegating.js";
|
|
4
|
+
export { SelfHostedAuthProvider } from "./self-hosted.js";
|
|
5
|
+
export function buildAuthProvider(kind, config, db) {
|
|
6
|
+
if (kind === "self-hosted") {
|
|
7
|
+
if (!config.audience || !config.signingKey || !config.credentialHashKey) {
|
|
8
|
+
throw new Error("AUTH_AUDIENCE, AUTH_SIGNING_KEY, and AUTH_CREDENTIAL_HASH_KEY are required.");
|
|
9
|
+
}
|
|
10
|
+
if (config.credentialHashKey.toLowerCase() === process.env.SECRET_APP_KEY?.toLowerCase())
|
|
11
|
+
throw new Error("Credential and encryption keys must be distinct.");
|
|
12
|
+
return new SelfHostedAuthProvider({
|
|
13
|
+
canonicalUri: config.audience,
|
|
14
|
+
signingKey: config.signingKey,
|
|
15
|
+
credentialHashKey: config.credentialHashKey,
|
|
16
|
+
maxClients: config.maxClients,
|
|
17
|
+
}, db);
|
|
18
|
+
}
|
|
19
|
+
return new DelegatingAuthProvider(config);
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function assertSelfHostedReleased(): void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { PrismaClient } from "@prisma/client";
|
|
2
|
+
import type { AuthProfile, AuthProvider, AuthTokens, VerifiedToken } from "./types.js";
|
|
3
|
+
import { Credentials } from "../../mcp/auth/self-hosted/credentials.js";
|
|
4
|
+
import { Sessions } from "../../mcp/auth/self-hosted/session.js";
|
|
5
|
+
import type { AuthorizeParams, RegisterClientParams, SelfHostedAuthConfig, TokenParams, TokenResult } from "./authorization-server.js";
|
|
6
|
+
export type { AuthorizeParams, RegisterClientParams, SelfHostedAuthConfig, TokenParams, TokenResult, } from "./authorization-server.js";
|
|
7
|
+
export declare class SelfHostedAuthProvider implements AuthProvider {
|
|
8
|
+
readonly db: PrismaClient;
|
|
9
|
+
readonly credentials: Credentials;
|
|
10
|
+
readonly sessions: Sessions;
|
|
11
|
+
readonly config: SelfHostedAuthConfig;
|
|
12
|
+
private readonly key;
|
|
13
|
+
constructor(config: SelfHostedAuthConfig, db: PrismaClient);
|
|
14
|
+
asMetadata(): {
|
|
15
|
+
issuer: string;
|
|
16
|
+
authorization_endpoint: string;
|
|
17
|
+
token_endpoint: string;
|
|
18
|
+
registration_endpoint: string;
|
|
19
|
+
revocation_endpoint: string;
|
|
20
|
+
response_types_supported: string[];
|
|
21
|
+
grant_types_supported: string[];
|
|
22
|
+
code_challenge_methods_supported: string[];
|
|
23
|
+
token_endpoint_auth_methods_supported: string[];
|
|
24
|
+
revocation_endpoint_auth_methods_supported: string[];
|
|
25
|
+
scopes_supported: string[];
|
|
26
|
+
authorization_response_iss_parameter_supported: boolean;
|
|
27
|
+
};
|
|
28
|
+
registerClient(params: RegisterClientParams): Promise<{
|
|
29
|
+
clientId: `${string}-${string}-${string}-${string}-${string}`;
|
|
30
|
+
}>;
|
|
31
|
+
handleAuthorize(input: AuthorizeParams): Promise<{
|
|
32
|
+
interactionId: string;
|
|
33
|
+
}>;
|
|
34
|
+
consentPage(sessionToken: string, interactionId: string): Promise<{
|
|
35
|
+
interaction: {
|
|
36
|
+
client: {
|
|
37
|
+
metadata: import("@prisma/client/runtime/library").JsonValue;
|
|
38
|
+
createdAt: Date;
|
|
39
|
+
clientId: string;
|
|
40
|
+
};
|
|
41
|
+
} & {
|
|
42
|
+
id: string;
|
|
43
|
+
createdAt: Date;
|
|
44
|
+
state: string | null;
|
|
45
|
+
expiresAt: Date;
|
|
46
|
+
resource: string;
|
|
47
|
+
clientId: string;
|
|
48
|
+
consumedAt: Date | null;
|
|
49
|
+
redirectUri: string;
|
|
50
|
+
codeChallenge: string;
|
|
51
|
+
requestedScope: string;
|
|
52
|
+
};
|
|
53
|
+
challenge: string;
|
|
54
|
+
}>;
|
|
55
|
+
consent(sessionToken: string, interactionId: string, challenge: string, approve: boolean): Promise<string>;
|
|
56
|
+
handleToken(params: TokenParams): Promise<TokenResult>;
|
|
57
|
+
/**
|
|
58
|
+
* Whether a token request's `resource` names this server: the canonical URI
|
|
59
|
+
* itself, or a URL beneath it. The MCP SDK sends the metadata's canonical
|
|
60
|
+
* URI when it has it, but falls back to the MCP endpoint URL (e.g. `/mcp`
|
|
61
|
+
* under a root canonical URI) on refresh - rejecting that logged every
|
|
62
|
+
* Claude Code session out after one access-token lifetime. The issued
|
|
63
|
+
* token's audience still comes from the grant (code.resource /
|
|
64
|
+
* family.resource), never from this parameter.
|
|
65
|
+
*/
|
|
66
|
+
private withinCanonical;
|
|
67
|
+
private exchange;
|
|
68
|
+
private rotate;
|
|
69
|
+
private issue;
|
|
70
|
+
private revokeFamily;
|
|
71
|
+
revoke(token: string, clientId: string): Promise<void>;
|
|
72
|
+
verifyBearer(token: string): Promise<VerifiedToken>;
|
|
73
|
+
cleanup(): Promise<void>;
|
|
74
|
+
profile(token: string): Promise<AuthProfile>;
|
|
75
|
+
authorizeUrl(): string;
|
|
76
|
+
exchangeCode(): Promise<AuthTokens>;
|
|
77
|
+
refresh(): Promise<AuthTokens>;
|
|
78
|
+
}
|