@antasphere/chassis-server 1.0.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/LICENSE +82 -0
- package/dist/accounts/deletion.d.ts +163 -0
- package/dist/accounts/deletion.d.ts.map +1 -0
- package/dist/accounts/deletion.js +360 -0
- package/dist/accounts/deletion.js.map +1 -0
- package/dist/accounts/erasure-log.d.ts +66 -0
- package/dist/accounts/erasure-log.d.ts.map +1 -0
- package/dist/accounts/erasure-log.js +117 -0
- package/dist/accounts/erasure-log.js.map +1 -0
- package/dist/accounts/index.d.ts +6 -0
- package/dist/accounts/index.d.ts.map +1 -0
- package/dist/accounts/index.js +6 -0
- package/dist/accounts/index.js.map +1 -0
- package/dist/accounts/mint-refusal.d.ts +47 -0
- package/dist/accounts/mint-refusal.d.ts.map +1 -0
- package/dist/accounts/mint-refusal.js +59 -0
- package/dist/accounts/mint-refusal.js.map +1 -0
- package/dist/accounts/signup-duplicate.d.ts +14 -0
- package/dist/accounts/signup-duplicate.d.ts.map +1 -0
- package/dist/accounts/signup-duplicate.js +25 -0
- package/dist/accounts/signup-duplicate.js.map +1 -0
- package/dist/accounts/superadmin.d.ts +27 -0
- package/dist/accounts/superadmin.d.ts.map +1 -0
- package/dist/accounts/superadmin.js +46 -0
- package/dist/accounts/superadmin.js.map +1 -0
- package/dist/api/apikeys.d.ts +14 -0
- package/dist/api/apikeys.d.ts.map +1 -0
- package/dist/api/apikeys.js +124 -0
- package/dist/api/apikeys.js.map +1 -0
- package/dist/api/audit.d.ts +4 -0
- package/dist/api/audit.d.ts.map +1 -0
- package/dist/api/audit.js +75 -0
- package/dist/api/audit.js.map +1 -0
- package/dist/api/break-glass.d.ts +48 -0
- package/dist/api/break-glass.d.ts.map +1 -0
- package/dist/api/break-glass.js +217 -0
- package/dist/api/break-glass.js.map +1 -0
- package/dist/api/cli-auth.d.ts +84 -0
- package/dist/api/cli-auth.d.ts.map +1 -0
- package/dist/api/cli-auth.js +177 -0
- package/dist/api/cli-auth.js.map +1 -0
- package/dist/api/create-api.d.ts +123 -0
- package/dist/api/create-api.d.ts.map +1 -0
- package/dist/api/create-api.js +1165 -0
- package/dist/api/create-api.js.map +1 -0
- package/dist/api/demo-passes.d.ts +45 -0
- package/dist/api/demo-passes.d.ts.map +1 -0
- package/dist/api/demo-passes.js +143 -0
- package/dist/api/demo-passes.js.map +1 -0
- package/dist/api/errors.d.ts +5 -0
- package/dist/api/errors.d.ts.map +1 -0
- package/dist/api/errors.js +5 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/export.d.ts +63 -0
- package/dist/api/export.d.ts.map +1 -0
- package/dist/api/export.js +393 -0
- package/dist/api/export.js.map +1 -0
- package/dist/api/files.d.ts +40 -0
- package/dist/api/files.d.ts.map +1 -0
- package/dist/api/files.js +150 -0
- package/dist/api/files.js.map +1 -0
- package/dist/api/index.d.ts +17 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +17 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/invitations.d.ts +50 -0
- package/dist/api/invitations.d.ts.map +1 -0
- package/dist/api/invitations.js +313 -0
- package/dist/api/invitations.js.map +1 -0
- package/dist/api/members.d.ts +25 -0
- package/dist/api/members.d.ts.map +1 -0
- package/dist/api/members.js +522 -0
- package/dist/api/members.js.map +1 -0
- package/dist/api/onboarding.d.ts +26 -0
- package/dist/api/onboarding.d.ts.map +1 -0
- package/dist/api/onboarding.js +23 -0
- package/dist/api/onboarding.js.map +1 -0
- package/dist/api/openapi-doc.d.ts +21 -0
- package/dist/api/openapi-doc.d.ts.map +1 -0
- package/dist/api/openapi-doc.js +25 -0
- package/dist/api/openapi-doc.js.map +1 -0
- package/dist/api/projects.d.ts +24 -0
- package/dist/api/projects.d.ts.map +1 -0
- package/dist/api/projects.js +624 -0
- package/dist/api/projects.js.map +1 -0
- package/dist/api/scope-routes.d.ts +12 -0
- package/dist/api/scope-routes.d.ts.map +1 -0
- package/dist/api/scope-routes.js +2 -0
- package/dist/api/scope-routes.js.map +1 -0
- package/dist/api/sso-connect.d.ts +70 -0
- package/dist/api/sso-connect.d.ts.map +1 -0
- package/dist/api/sso-connect.js +164 -0
- package/dist/api/sso-connect.js.map +1 -0
- package/dist/api/sso-logout.d.ts +41 -0
- package/dist/api/sso-logout.d.ts.map +1 -0
- package/dist/api/sso-logout.js +34 -0
- package/dist/api/sso-logout.js.map +1 -0
- package/dist/api/teams.d.ts +43 -0
- package/dist/api/teams.d.ts.map +1 -0
- package/dist/api/teams.js +447 -0
- package/dist/api/teams.js.map +1 -0
- package/dist/api/workspaces.d.ts +114 -0
- package/dist/api/workspaces.d.ts.map +1 -0
- package/dist/api/workspaces.js +462 -0
- package/dist/api/workspaces.js.map +1 -0
- package/dist/apikeys/index.d.ts +3 -0
- package/dist/apikeys/index.d.ts.map +1 -0
- package/dist/apikeys/index.js +3 -0
- package/dist/apikeys/index.js.map +1 -0
- package/dist/apikeys/peppers.d.ts +53 -0
- package/dist/apikeys/peppers.d.ts.map +1 -0
- package/dist/apikeys/peppers.js +97 -0
- package/dist/apikeys/peppers.js.map +1 -0
- package/dist/apikeys/service.d.ts +56 -0
- package/dist/apikeys/service.d.ts.map +1 -0
- package/dist/apikeys/service.js +196 -0
- package/dist/apikeys/service.js.map +1 -0
- package/dist/app.d.ts +65 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +142 -0
- package/dist/app.js.map +1 -0
- package/dist/audit/filters.d.ts +38 -0
- package/dist/audit/filters.d.ts.map +1 -0
- package/dist/audit/filters.js +97 -0
- package/dist/audit/filters.js.map +1 -0
- package/dist/audit/index.d.ts +3 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +3 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/service.d.ts +65 -0
- package/dist/audit/service.d.ts.map +1 -0
- package/dist/audit/service.js +103 -0
- package/dist/audit/service.js.map +1 -0
- package/dist/boot.d.ts +8 -0
- package/dist/boot.d.ts.map +1 -0
- package/dist/boot.js +822 -0
- package/dist/boot.js.map +1 -0
- package/dist/constant-time.d.ts +3 -0
- package/dist/constant-time.d.ts.map +1 -0
- package/dist/constant-time.js +10 -0
- package/dist/constant-time.js.map +1 -0
- package/dist/email/driver.d.ts +16 -0
- package/dist/email/driver.d.ts.map +1 -0
- package/dist/email/driver.js +136 -0
- package/dist/email/driver.js.map +1 -0
- package/dist/email/index.d.ts +4 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +4 -0
- package/dist/email/index.js.map +1 -0
- package/dist/email/shell.d.ts +72 -0
- package/dist/email/shell.d.ts.map +1 -0
- package/dist/email/shell.js +146 -0
- package/dist/email/shell.js.map +1 -0
- package/dist/email/templates.d.ts +83 -0
- package/dist/email/templates.d.ts.map +1 -0
- package/dist/email/templates.js +96 -0
- package/dist/email/templates.js.map +1 -0
- package/dist/entitlements/check.d.ts +140 -0
- package/dist/entitlements/check.d.ts.map +1 -0
- package/dist/entitlements/check.js +276 -0
- package/dist/entitlements/check.js.map +1 -0
- package/dist/entitlements/clock-skew.d.ts +27 -0
- package/dist/entitlements/clock-skew.d.ts.map +1 -0
- package/dist/entitlements/clock-skew.js +58 -0
- package/dist/entitlements/clock-skew.js.map +1 -0
- package/dist/entitlements/gate.d.ts +113 -0
- package/dist/entitlements/gate.d.ts.map +1 -0
- package/dist/entitlements/gate.js +430 -0
- package/dist/entitlements/gate.js.map +1 -0
- package/dist/entitlements/hub-machine-token.d.ts +83 -0
- package/dist/entitlements/hub-machine-token.d.ts.map +1 -0
- package/dist/entitlements/hub-machine-token.js +175 -0
- package/dist/entitlements/hub-machine-token.js.map +1 -0
- package/dist/entitlements/hub-subject.d.ts +32 -0
- package/dist/entitlements/hub-subject.d.ts.map +1 -0
- package/dist/entitlements/hub-subject.js +68 -0
- package/dist/entitlements/hub-subject.js.map +1 -0
- package/dist/entitlements/index.d.ts +9 -0
- package/dist/entitlements/index.d.ts.map +1 -0
- package/dist/entitlements/index.js +9 -0
- package/dist/entitlements/index.js.map +1 -0
- package/dist/entitlements/poster.d.ts +81 -0
- package/dist/entitlements/poster.d.ts.map +1 -0
- package/dist/entitlements/poster.js +169 -0
- package/dist/entitlements/poster.js.map +1 -0
- package/dist/entitlements/profiles.d.ts +121 -0
- package/dist/entitlements/profiles.d.ts.map +1 -0
- package/dist/entitlements/profiles.js +212 -0
- package/dist/entitlements/profiles.js.map +1 -0
- package/dist/entitlements/slot.d.ts +33 -0
- package/dist/entitlements/slot.d.ts.map +1 -0
- package/dist/entitlements/slot.js +75 -0
- package/dist/entitlements/slot.js.map +1 -0
- package/dist/env.d.ts +293 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +383 -0
- package/dist/env.js.map +1 -0
- package/dist/files/http.d.ts +23 -0
- package/dist/files/http.d.ts.map +1 -0
- package/dist/files/http.js +66 -0
- package/dist/files/http.js.map +1 -0
- package/dist/files/index.d.ts +5 -0
- package/dist/files/index.d.ts.map +1 -0
- package/dist/files/index.js +5 -0
- package/dist/files/index.js.map +1 -0
- package/dist/files/serve.d.ts +43 -0
- package/dist/files/serve.d.ts.map +1 -0
- package/dist/files/serve.js +71 -0
- package/dist/files/serve.js.map +1 -0
- package/dist/files/service.d.ts +69 -0
- package/dist/files/service.d.ts.map +1 -0
- package/dist/files/service.js +188 -0
- package/dist/files/service.js.map +1 -0
- package/dist/files/spool.d.ts +21 -0
- package/dist/files/spool.d.ts.map +1 -0
- package/dist/files/spool.js +47 -0
- package/dist/files/spool.js.map +1 -0
- package/dist/identity/better-auth.d.ts +3927 -0
- package/dist/identity/better-auth.d.ts.map +1 -0
- package/dist/identity/better-auth.js +896 -0
- package/dist/identity/better-auth.js.map +1 -0
- package/dist/identity/demo-pass-plugin.d.ts +29 -0
- package/dist/identity/demo-pass-plugin.d.ts.map +1 -0
- package/dist/identity/demo-pass-plugin.js +88 -0
- package/dist/identity/demo-pass-plugin.js.map +1 -0
- package/dist/identity/demo-pass-rules.d.ts +84 -0
- package/dist/identity/demo-pass-rules.d.ts.map +1 -0
- package/dist/identity/demo-pass-rules.js +223 -0
- package/dist/identity/demo-pass-rules.js.map +1 -0
- package/dist/identity/demo-pass.d.ts +159 -0
- package/dist/identity/demo-pass.d.ts.map +1 -0
- package/dist/identity/demo-pass.js +319 -0
- package/dist/identity/demo-pass.js.map +1 -0
- package/dist/identity/hub-grant.d.ts +182 -0
- package/dist/identity/hub-grant.d.ts.map +1 -0
- package/dist/identity/hub-grant.js +594 -0
- package/dist/identity/hub-grant.js.map +1 -0
- package/dist/identity/hub-jwt.d.ts +22 -0
- package/dist/identity/hub-jwt.d.ts.map +1 -0
- package/dist/identity/hub-jwt.js +77 -0
- package/dist/identity/hub-jwt.js.map +1 -0
- package/dist/identity/hub-live-gate.d.ts +17 -0
- package/dist/identity/hub-live-gate.d.ts.map +1 -0
- package/dist/identity/hub-live-gate.js +146 -0
- package/dist/identity/hub-live-gate.js.map +1 -0
- package/dist/identity/hub-logout.d.ts +88 -0
- package/dist/identity/hub-logout.d.ts.map +1 -0
- package/dist/identity/hub-logout.js +158 -0
- package/dist/identity/hub-logout.js.map +1 -0
- package/dist/identity/hub-projection.d.ts +103 -0
- package/dist/identity/hub-projection.d.ts.map +1 -0
- package/dist/identity/hub-projection.js +130 -0
- package/dist/identity/hub-projection.js.map +1 -0
- package/dist/identity/hub-reconcile.d.ts +151 -0
- package/dist/identity/hub-reconcile.d.ts.map +1 -0
- package/dist/identity/hub-reconcile.js +400 -0
- package/dist/identity/hub-reconcile.js.map +1 -0
- package/dist/identity/hub-sso.d.ts +363 -0
- package/dist/identity/hub-sso.d.ts.map +1 -0
- package/dist/identity/hub-sso.js +536 -0
- package/dist/identity/hub-sso.js.map +1 -0
- package/dist/identity/hub-user-client.d.ts +222 -0
- package/dist/identity/hub-user-client.d.ts.map +1 -0
- package/dist/identity/hub-user-client.js +406 -0
- package/dist/identity/hub-user-client.js.map +1 -0
- package/dist/identity/index.d.ts +13 -0
- package/dist/identity/index.d.ts.map +1 -0
- package/dist/identity/index.js +13 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/identity/oauth-jwt.d.ts +32 -0
- package/dist/identity/oauth-jwt.d.ts.map +1 -0
- package/dist/identity/oauth-jwt.js +122 -0
- package/dist/identity/oauth-jwt.js.map +1 -0
- package/dist/identity/resolve-membership.d.ts +28 -0
- package/dist/identity/resolve-membership.d.ts.map +1 -0
- package/dist/identity/resolve-membership.js +69 -0
- package/dist/identity/resolve-membership.js.map +1 -0
- package/dist/identity/signing-key.d.ts +49 -0
- package/dist/identity/signing-key.d.ts.map +1 -0
- package/dist/identity/signing-key.js +144 -0
- package/dist/identity/signing-key.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/invitations/index.d.ts +2 -0
- package/dist/invitations/index.d.ts.map +1 -0
- package/dist/invitations/index.js +2 -0
- package/dist/invitations/index.js.map +1 -0
- package/dist/invitations/service.d.ts +36 -0
- package/dist/invitations/service.d.ts.map +1 -0
- package/dist/invitations/service.js +122 -0
- package/dist/invitations/service.js.map +1 -0
- package/dist/jobs/index.d.ts +3 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +3 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/jobs/pgboss.d.ts +119 -0
- package/dist/jobs/pgboss.d.ts.map +1 -0
- package/dist/jobs/pgboss.js +521 -0
- package/dist/jobs/pgboss.js.map +1 -0
- package/dist/jobs/timers.d.ts +127 -0
- package/dist/jobs/timers.d.ts.map +1 -0
- package/dist/jobs/timers.js +228 -0
- package/dist/jobs/timers.js.map +1 -0
- package/dist/logger.d.ts +17 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +64 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/errors.d.ts +37 -0
- package/dist/mcp/errors.d.ts.map +1 -0
- package/dist/mcp/errors.js +77 -0
- package/dist/mcp/errors.js.map +1 -0
- package/dist/mcp/http.d.ts +35 -0
- package/dist/mcp/http.d.ts.map +1 -0
- package/dist/mcp/http.js +80 -0
- package/dist/mcp/http.js.map +1 -0
- package/dist/mcp/index.d.ts +8 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +8 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/inputs.d.ts +19 -0
- package/dist/mcp/inputs.d.ts.map +1 -0
- package/dist/mcp/inputs.js +28 -0
- package/dist/mcp/inputs.js.map +1 -0
- package/dist/mcp/projects.d.ts +31 -0
- package/dist/mcp/projects.d.ts.map +1 -0
- package/dist/mcp/projects.js +315 -0
- package/dist/mcp/projects.js.map +1 -0
- package/dist/mcp/server.d.ts +52 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +93 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/teams.d.ts +7 -0
- package/dist/mcp/teams.d.ts.map +1 -0
- package/dist/mcp/teams.js +62 -0
- package/dist/mcp/teams.js.map +1 -0
- package/dist/mcp/tool-kit.d.ts +67 -0
- package/dist/mcp/tool-kit.d.ts.map +1 -0
- package/dist/mcp/tool-kit.js +74 -0
- package/dist/mcp/tool-kit.js.map +1 -0
- package/dist/members/removal.d.ts +95 -0
- package/dist/members/removal.d.ts.map +1 -0
- package/dist/members/removal.js +143 -0
- package/dist/members/removal.js.map +1 -0
- package/dist/middleware/auth-body.d.ts +25 -0
- package/dist/middleware/auth-body.d.ts.map +1 -0
- package/dist/middleware/auth-body.js +55 -0
- package/dist/middleware/auth-body.js.map +1 -0
- package/dist/middleware/auth-context.d.ts +170 -0
- package/dist/middleware/auth-context.d.ts.map +1 -0
- package/dist/middleware/auth-context.js +251 -0
- package/dist/middleware/auth-context.js.map +1 -0
- package/dist/middleware/body-cap.d.ts +17 -0
- package/dist/middleware/body-cap.d.ts.map +1 -0
- package/dist/middleware/body-cap.js +31 -0
- package/dist/middleware/body-cap.js.map +1 -0
- package/dist/middleware/body-refusal.d.ts +20 -0
- package/dist/middleware/body-refusal.d.ts.map +1 -0
- package/dist/middleware/body-refusal.js +5 -0
- package/dist/middleware/body-refusal.js.map +1 -0
- package/dist/middleware/cross-site.d.ts +61 -0
- package/dist/middleware/cross-site.d.ts.map +1 -0
- package/dist/middleware/cross-site.js +59 -0
- package/dist/middleware/cross-site.js.map +1 -0
- package/dist/middleware/hub-managed.d.ts +45 -0
- package/dist/middleware/hub-managed.d.ts.map +1 -0
- package/dist/middleware/hub-managed.js +56 -0
- package/dist/middleware/hub-managed.js.map +1 -0
- package/dist/middleware/idempotency.d.ts +14 -0
- package/dist/middleware/idempotency.d.ts.map +1 -0
- package/dist/middleware/idempotency.js +222 -0
- package/dist/middleware/idempotency.js.map +1 -0
- package/dist/middleware/index.d.ts +12 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +12 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/json-depth.d.ts +32 -0
- package/dist/middleware/json-depth.d.ts.map +1 -0
- package/dist/middleware/json-depth.js +80 -0
- package/dist/middleware/json-depth.js.map +1 -0
- package/dist/middleware/no-store.d.ts +21 -0
- package/dist/middleware/no-store.d.ts.map +1 -0
- package/dist/middleware/no-store.js +32 -0
- package/dist/middleware/no-store.js.map +1 -0
- package/dist/middleware/oauth-public.d.ts +16 -0
- package/dist/middleware/oauth-public.d.ts.map +1 -0
- package/dist/middleware/oauth-public.js +50 -0
- package/dist/middleware/oauth-public.js.map +1 -0
- package/dist/middleware/rate-limit.d.ts +182 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.js +277 -0
- package/dist/middleware/rate-limit.js.map +1 -0
- package/dist/middleware/request-id.d.ts +10 -0
- package/dist/middleware/request-id.d.ts.map +1 -0
- package/dist/middleware/request-id.js +42 -0
- package/dist/middleware/request-id.js.map +1 -0
- package/dist/middleware/scopes.d.ts +33 -0
- package/dist/middleware/scopes.d.ts.map +1 -0
- package/dist/middleware/scopes.js +139 -0
- package/dist/middleware/scopes.js.map +1 -0
- package/dist/middleware/security-headers.d.ts +53 -0
- package/dist/middleware/security-headers.d.ts.map +1 -0
- package/dist/middleware/security-headers.js +96 -0
- package/dist/middleware/security-headers.js.map +1 -0
- package/dist/observability/index.d.ts +3 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +3 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/metrics.d.ts +17 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +82 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/observability/otel.d.ts +20 -0
- package/dist/observability/otel.d.ts.map +1 -0
- package/dist/observability/otel.js +54 -0
- package/dist/observability/otel.js.map +1 -0
- package/dist/pagination.d.ts +57 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +90 -0
- package/dist/pagination.js.map +1 -0
- package/dist/platform/edition.d.ts +57 -0
- package/dist/platform/edition.d.ts.map +1 -0
- package/dist/platform/edition.js +90 -0
- package/dist/platform/edition.js.map +1 -0
- package/dist/platform/entitlements.d.ts +26 -0
- package/dist/platform/entitlements.d.ts.map +1 -0
- package/dist/platform/entitlements.js +28 -0
- package/dist/platform/entitlements.js.map +1 -0
- package/dist/platform/events.d.ts +87 -0
- package/dist/platform/events.d.ts.map +1 -0
- package/dist/platform/events.js +32 -0
- package/dist/platform/events.js.map +1 -0
- package/dist/platform/index.d.ts +8 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/index.js +8 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/local-identity.d.ts +39 -0
- package/dist/platform/local-identity.d.ts.map +1 -0
- package/dist/platform/local-identity.js +87 -0
- package/dist/platform/local-identity.js.map +1 -0
- package/dist/platform/registry.d.ts +23 -0
- package/dist/platform/registry.d.ts.map +1 -0
- package/dist/platform/registry.js +5 -0
- package/dist/platform/registry.js.map +1 -0
- package/dist/platform/usage.d.ts +11 -0
- package/dist/platform/usage.d.ts.map +1 -0
- package/dist/platform/usage.js +12 -0
- package/dist/platform/usage.js.map +1 -0
- package/dist/platform/workspaces.d.ts +25 -0
- package/dist/platform/workspaces.d.ts.map +1 -0
- package/dist/platform/workspaces.js +44 -0
- package/dist/platform/workspaces.js.map +1 -0
- package/dist/projects/access.d.ts +40 -0
- package/dist/projects/access.d.ts.map +1 -0
- package/dist/projects/access.js +133 -0
- package/dist/projects/access.js.map +1 -0
- package/dist/projects/index.d.ts +2 -0
- package/dist/projects/index.d.ts.map +1 -0
- package/dist/projects/index.js +2 -0
- package/dist/projects/index.js.map +1 -0
- package/dist/route-label.d.ts +23 -0
- package/dist/route-label.d.ts.map +1 -0
- package/dist/route-label.js +29 -0
- package/dist/route-label.js.map +1 -0
- package/dist/routes/health.d.ts +30 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +54 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/index.d.ts +3 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +3 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/wellknown.d.ts +11 -0
- package/dist/routes/wellknown.d.ts.map +1 -0
- package/dist/routes/wellknown.js +45 -0
- package/dist/routes/wellknown.js.map +1 -0
- package/dist/secret.d.ts +30 -0
- package/dist/secret.d.ts.map +1 -0
- package/dist/secret.js +97 -0
- package/dist/secret.js.map +1 -0
- package/dist/setup-transport.d.ts +23 -0
- package/dist/setup-transport.d.ts.map +1 -0
- package/dist/setup-transport.js +52 -0
- package/dist/setup-transport.js.map +1 -0
- package/dist/state.d.ts +21 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +4 -0
- package/dist/state.js.map +1 -0
- package/dist/storage/driver.d.ts +38 -0
- package/dist/storage/driver.d.ts.map +1 -0
- package/dist/storage/driver.js +14 -0
- package/dist/storage/driver.js.map +1 -0
- package/dist/storage/factory.d.ts +4 -0
- package/dist/storage/factory.d.ts.map +1 -0
- package/dist/storage/factory.js +20 -0
- package/dist/storage/factory.js.map +1 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +4 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/local.d.ts +21 -0
- package/dist/storage/local.d.ts.map +1 -0
- package/dist/storage/local.js +88 -0
- package/dist/storage/local.js.map +1 -0
- package/dist/storage/s3.d.ts +29 -0
- package/dist/storage/s3.d.ts.map +1 -0
- package/dist/storage/s3.js +82 -0
- package/dist/storage/s3.js.map +1 -0
- package/dist/testing/fake-hub.d.ts +425 -0
- package/dist/testing/fake-hub.d.ts.map +1 -0
- package/dist/testing/fake-hub.js +1074 -0
- package/dist/testing/fake-hub.js.map +1 -0
- package/dist/testing/helpers.d.ts +124 -0
- package/dist/testing/helpers.d.ts.map +1 -0
- package/dist/testing/helpers.js +174 -0
- package/dist/testing/helpers.js.map +1 -0
- package/dist/testing/index.d.ts +12 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +12 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/setup-origins.d.ts +21 -0
- package/dist/testing/setup-origins.d.ts.map +1 -0
- package/dist/testing/setup-origins.js +57 -0
- package/dist/testing/setup-origins.js.map +1 -0
- package/dist/testing/sso-helpers.d.ts +43 -0
- package/dist/testing/sso-helpers.d.ts.map +1 -0
- package/dist/testing/sso-helpers.js +159 -0
- package/dist/testing/sso-helpers.js.map +1 -0
- package/dist/tool-definition.d.ts +382 -0
- package/dist/tool-definition.d.ts.map +1 -0
- package/dist/tool-definition.js +46 -0
- package/dist/tool-definition.js.map +1 -0
- package/dist/util/index.d.ts +8 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +8 -0
- package/dist/util/index.js.map +1 -0
- package/package.json +161 -0
- package/src/accounts/deletion.ts +389 -0
- package/src/accounts/erasure-log.ts +140 -0
- package/src/accounts/index.ts +5 -0
- package/src/accounts/mint-refusal.ts +67 -0
- package/src/accounts/signup-duplicate.ts +21 -0
- package/src/accounts/superadmin.ts +46 -0
- package/src/api/apikeys.ts +147 -0
- package/src/api/audit.ts +83 -0
- package/src/api/break-glass.ts +294 -0
- package/src/api/cli-auth.ts +308 -0
- package/src/api/create-api.ts +1403 -0
- package/src/api/demo-passes.ts +207 -0
- package/src/api/errors.ts +13 -0
- package/src/api/export.ts +482 -0
- package/src/api/files.ts +200 -0
- package/src/api/index.ts +29 -0
- package/src/api/invitations.ts +396 -0
- package/src/api/members.ts +617 -0
- package/src/api/onboarding.ts +50 -0
- package/src/api/openapi-doc.ts +34 -0
- package/src/api/projects.ts +788 -0
- package/src/api/scope-routes.ts +12 -0
- package/src/api/sso-connect.ts +246 -0
- package/src/api/sso-logout.ts +76 -0
- package/src/api/teams.ts +575 -0
- package/src/api/workspaces.ts +649 -0
- package/src/apikeys/index.ts +2 -0
- package/src/apikeys/peppers.ts +118 -0
- package/src/apikeys/service.ts +223 -0
- package/src/app.ts +228 -0
- package/src/audit/filters.ts +101 -0
- package/src/audit/index.ts +9 -0
- package/src/audit/service.ts +154 -0
- package/src/boot.ts +953 -0
- package/src/constant-time.ts +9 -0
- package/src/email/driver.ts +139 -0
- package/src/email/index.ts +26 -0
- package/src/email/shell.ts +201 -0
- package/src/email/templates.ts +184 -0
- package/src/entitlements/check.ts +435 -0
- package/src/entitlements/clock-skew.ts +58 -0
- package/src/entitlements/gate.ts +636 -0
- package/src/entitlements/hub-machine-token.ts +205 -0
- package/src/entitlements/hub-subject.ts +77 -0
- package/src/entitlements/index.ts +37 -0
- package/src/entitlements/poster.ts +265 -0
- package/src/entitlements/profiles.ts +303 -0
- package/src/entitlements/slot.ts +105 -0
- package/src/env.ts +456 -0
- package/src/files/http.ts +77 -0
- package/src/files/index.ts +4 -0
- package/src/files/serve.ts +115 -0
- package/src/files/service.ts +209 -0
- package/src/files/spool.ts +58 -0
- package/src/identity/better-auth.ts +1103 -0
- package/src/identity/demo-pass-plugin.ts +121 -0
- package/src/identity/demo-pass-rules.ts +229 -0
- package/src/identity/demo-pass.ts +390 -0
- package/src/identity/hub-grant.ts +704 -0
- package/src/identity/hub-jwt.ts +78 -0
- package/src/identity/hub-live-gate.ts +167 -0
- package/src/identity/hub-logout.ts +174 -0
- package/src/identity/hub-projection.ts +251 -0
- package/src/identity/hub-reconcile.ts +572 -0
- package/src/identity/hub-sso.ts +696 -0
- package/src/identity/hub-user-client.ts +554 -0
- package/src/identity/index.ts +56 -0
- package/src/identity/oauth-jwt.ts +128 -0
- package/src/identity/resolve-membership.ts +104 -0
- package/src/identity/signing-key.ts +164 -0
- package/src/index.ts +65 -0
- package/src/invitations/index.ts +1 -0
- package/src/invitations/service.ts +171 -0
- package/src/jobs/index.ts +25 -0
- package/src/jobs/pgboss.ts +594 -0
- package/src/jobs/timers.ts +287 -0
- package/src/logger.ts +67 -0
- package/src/mcp/errors.ts +111 -0
- package/src/mcp/http.ts +129 -0
- package/src/mcp/index.ts +28 -0
- package/src/mcp/inputs.ts +33 -0
- package/src/mcp/projects.ts +480 -0
- package/src/mcp/server.ts +174 -0
- package/src/mcp/teams.ts +97 -0
- package/src/mcp/tool-kit.ts +148 -0
- package/src/members/removal.ts +216 -0
- package/src/middleware/auth-body.ts +58 -0
- package/src/middleware/auth-context.ts +384 -0
- package/src/middleware/body-cap.ts +33 -0
- package/src/middleware/body-refusal.ts +23 -0
- package/src/middleware/cross-site.ts +122 -0
- package/src/middleware/hub-managed.ts +61 -0
- package/src/middleware/idempotency.ts +264 -0
- package/src/middleware/index.ts +33 -0
- package/src/middleware/json-depth.ts +74 -0
- package/src/middleware/no-store.ts +30 -0
- package/src/middleware/oauth-public.ts +54 -0
- package/src/middleware/rate-limit.ts +432 -0
- package/src/middleware/request-id.ts +54 -0
- package/src/middleware/scopes.ts +150 -0
- package/src/middleware/security-headers.ts +129 -0
- package/src/observability/index.ts +2 -0
- package/src/observability/metrics.ts +102 -0
- package/src/observability/otel.ts +79 -0
- package/src/pagination.ts +118 -0
- package/src/platform/edition.ts +140 -0
- package/src/platform/entitlements.ts +47 -0
- package/src/platform/events.ts +71 -0
- package/src/platform/index.ts +7 -0
- package/src/platform/local-identity.ts +90 -0
- package/src/platform/registry.ts +28 -0
- package/src/platform/usage.ts +13 -0
- package/src/platform/workspaces.ts +41 -0
- package/src/projects/access.ts +160 -0
- package/src/projects/index.ts +7 -0
- package/src/route-label.ts +29 -0
- package/src/routes/health.ts +79 -0
- package/src/routes/index.ts +2 -0
- package/src/routes/wellknown.ts +67 -0
- package/src/secret.ts +115 -0
- package/src/setup-transport.ts +46 -0
- package/src/state.ts +23 -0
- package/src/storage/driver.ts +48 -0
- package/src/storage/factory.ts +34 -0
- package/src/storage/index.ts +3 -0
- package/src/storage/local.ts +93 -0
- package/src/storage/s3.ts +109 -0
- package/src/testing/fake-hub.ts +1316 -0
- package/src/testing/helpers.ts +254 -0
- package/src/testing/index.ts +11 -0
- package/src/testing/setup-origins.ts +58 -0
- package/src/testing/sso-helpers.ts +178 -0
- package/src/tool-definition.ts +463 -0
- package/src/util/index.ts +17 -0
- package/test/fixtures/onboarding-backfill.sql +13 -0
- package/test/fixtures/operator-user-id-backfill.sql +18 -0
- package/test/host/dr-lib.sh +253 -0
- package/test/host/drizzle/0000_chassis_baseline.sql +438 -0
- package/test/host/drizzle/0001_last_owner_guard.sql +42 -0
- package/test/host/drizzle/meta/0000_snapshot.json +3566 -0
- package/test/host/drizzle/meta/_journal.json +20 -0
- package/test/host/drizzle.config.ts +17 -0
- package/test/host/identity.ts +41 -0
- package/test/host/minimal-host.ts +35 -0
- package/test/host/minimal-tool.ts +123 -0
- package/test/integration/account-oracle-uniformity.test.ts +284 -0
- package/test/integration/account-recovery.test.ts +236 -0
- package/test/integration/account.test.ts +120 -0
- package/test/integration/api-quota.test.ts +208 -0
- package/test/integration/apikey-expiry.test.ts +178 -0
- package/test/integration/apikey-pepper-rotation.test.ts +190 -0
- package/test/integration/boot-posture.test.ts +169 -0
- package/test/integration/break-glass.test.ts +484 -0
- package/test/integration/cloud-lifecycle.test.ts +233 -0
- package/test/integration/credential-boundaries.test.ts +195 -0
- package/test/integration/default-workspace.test.ts +414 -0
- package/test/integration/demo-pass-rules.test.ts +332 -0
- package/test/integration/demo-pass.test.ts +1222 -0
- package/test/integration/dr-verify-real-dump.test.ts +154 -0
- package/test/integration/edition.test.ts +868 -0
- package/test/integration/email-change.test.ts +394 -0
- package/test/integration/empty-tool.test.ts +267 -0
- package/test/integration/entitlements-null-hook.test.ts +187 -0
- package/test/integration/entitlements.test.ts +693 -0
- package/test/integration/export-entries.test.ts +321 -0
- package/test/integration/files.test.ts +320 -0
- package/test/integration/first-boot-claim.test.ts +131 -0
- package/test/integration/gdpr.test.ts +532 -0
- package/test/integration/helpers.ts +29 -0
- package/test/integration/hub-grant.test.ts +505 -0
- package/test/integration/hub-live-gate.test.ts +612 -0
- package/test/integration/hub-managed-membership.test.ts +559 -0
- package/test/integration/hub-org-selector.test.ts +281 -0
- package/test/integration/hub-reconcile.test.ts +646 -0
- package/test/integration/hub-sso.test.ts +704 -0
- package/test/integration/hub-teams.test.ts +771 -0
- package/test/integration/idempotency.test.ts +261 -0
- package/test/integration/invite-verification.test.ts +210 -0
- package/test/integration/last-owner-race.test.ts +263 -0
- package/test/integration/m9-fixes.test.ts +290 -0
- package/test/integration/mcp-projects.test.ts +463 -0
- package/test/integration/member-removal-race.test.ts +466 -0
- package/test/integration/member-removal.test.ts +794 -0
- package/test/integration/oauth-mcp.test.ts +477 -0
- package/test/integration/oauth-workspace.test.ts +371 -0
- package/test/integration/observability.test.ts +183 -0
- package/test/integration/onboarding.test.ts +268 -0
- package/test/integration/orphan-purge.test.ts +451 -0
- package/test/integration/pagination.test.ts +344 -0
- package/test/integration/platform-core.test.ts +305 -0
- package/test/integration/platform.test.ts +246 -0
- package/test/integration/pool-survives-restart.test.ts +80 -0
- package/test/integration/projects-cloud.test.ts +193 -0
- package/test/integration/projects.test.ts +1310 -0
- package/test/integration/security-fixes.test.ts +190 -0
- package/test/integration/setup-transport.test.ts +118 -0
- package/test/integration/signin-wall.test.ts +103 -0
- package/test/integration/signing-key-rotation.test.ts +349 -0
- package/test/integration/sso-helpers.ts +15 -0
- package/test/integration/sso-logout.test.ts +283 -0
- package/test/integration/teams-cloud.test.ts +194 -0
- package/test/integration/teams.test.ts +551 -0
- package/test/integration/timers.test.ts +377 -0
- package/test/integration/two-factor.test.ts +301 -0
- package/test/integration/usage-window.test.ts +161 -0
- package/test/integration/workspace-create-cloud.test.ts +523 -0
- package/test/integration/workspace-create.test.ts +510 -0
- package/test/integration/workspace-scoping.test.ts +530 -0
- package/test/integration/zz-adv-replay-owner.test.ts +205 -0
- package/test/unit/apikey-peppers.test.ts +110 -0
- package/test/unit/apikey-prefix.test.ts +34 -0
- package/test/unit/audit-filters.test.ts +135 -0
- package/test/unit/auth-origins.test.ts +92 -0
- package/test/unit/body-cap.test.ts +84 -0
- package/test/unit/clock-skew.test.ts +68 -0
- package/test/unit/cross-site.test.ts +166 -0
- package/test/unit/declared-credits.test.ts +13 -0
- package/test/unit/demo-pass-rules.test.ts +192 -0
- package/test/unit/email-driver.test.ts +127 -0
- package/test/unit/end-pool.test.ts +181 -0
- package/test/unit/entitlement-check.test.ts +492 -0
- package/test/unit/entitlement-gate.test.ts +1333 -0
- package/test/unit/entitlement-profiles.test.ts +289 -0
- package/test/unit/erasure-log.test.ts +72 -0
- package/test/unit/error-mapping.test.ts +89 -0
- package/test/unit/export-entries.test.ts +85 -0
- package/test/unit/export-sanitize.test.ts +27 -0
- package/test/unit/files-head-route.test.ts +155 -0
- package/test/unit/files-http.test.ts +97 -0
- package/test/unit/head-rewrite.test.ts +72 -0
- package/test/unit/hub-create-org.test.ts +181 -0
- package/test/unit/hub-jwt.test.ts +93 -0
- package/test/unit/hub-sso-params.test.ts +39 -0
- package/test/unit/hub-subject.test.ts +83 -0
- package/test/unit/idempotency-crypto.test.ts +45 -0
- package/test/unit/json-depth.test.ts +88 -0
- package/test/unit/logger-redaction.test.ts +66 -0
- package/test/unit/mcp-errors.test.ts +110 -0
- package/test/unit/mcp-inputs.test.ts +106 -0
- package/test/unit/mcp-project-hints.test.ts +26 -0
- package/test/unit/no-store.test.ts +49 -0
- package/test/unit/no-tool-migration-filename.test.ts +70 -0
- package/test/unit/observability.test.ts +64 -0
- package/test/unit/openapi-doc.test.ts +93 -0
- package/test/unit/rate-limit-consume-on.test.ts +76 -0
- package/test/unit/rate-limit.test.ts +39 -0
- package/test/unit/readyz-storage.test.ts +157 -0
- package/test/unit/request-quota.test.ts +146 -0
- package/test/unit/scopes.test.ts +66 -0
- package/test/unit/security-headers.test.ts +131 -0
- package/test/unit/serve-content-type.test.ts +74 -0
- package/test/unit/setup-transport.test.ts +29 -0
- package/test/unit/storage-local.test.ts +53 -0
- package/test/unit/superadmin.test.ts +32 -0
- package/test/unit/timers.test.ts +287 -0
- package/test/unit/tool-definition-guards.test.ts +166 -0
- package/test/unit/tool-entitlements-guard.test.ts +168 -0
- package/test/unit/usage-poster.test.ts +542 -0
- package/test/unit/usage-window.test.ts +48 -0
- package/test/unit/workspace-create-audit.test.ts +48 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
2
|
+
import { projects } from '@antasphere/chassis-db';
|
|
3
|
+
/**
|
|
4
|
+
* THE project access rule, stated once. A tool links its own resources to
|
|
5
|
+
* projects through a table of its own, and asks ONE question of the chassis:
|
|
6
|
+
* "does this principal hold a grant of at least `<role>` on the project in
|
|
7
|
+
* this column?". The chassis routes (`api/projects.ts`) ask the same question
|
|
8
|
+
* through the same builder, so a tool cannot drift from them.
|
|
9
|
+
*
|
|
10
|
+
* What the predicate carries, and every clause is load-bearing:
|
|
11
|
+
*
|
|
12
|
+
* - **The guest refusal.** An `origin='guest'` membership exists for
|
|
13
|
+
* principal resolution only (D2): it is never a project member. Refused on
|
|
14
|
+
* the PRINCIPAL (`false`, no query at all) AND on the membership row the
|
|
15
|
+
* grant rides on (`origin <> 'guest'`), so a stray row is inert.
|
|
16
|
+
* - **The live membership.** The grant is read THROUGH its
|
|
17
|
+
* `workspace_members` row: same user, same workspace as the request,
|
|
18
|
+
* `is_active`. A deleted membership took the grant with it (the foreign
|
|
19
|
+
* key's cascade); a deactivated one resolves no principal at all.
|
|
20
|
+
* - **One workspace.** The project belongs to the request's workspace and to
|
|
21
|
+
* the membership's. A request never spans workspaces (ADR 014).
|
|
22
|
+
* - **The role ladder.** `manager` contains `editor` contains `viewer`.
|
|
23
|
+
* - **A team's grant (PRDCT-2794).** A person seated in a team that holds a
|
|
24
|
+
* place on the project holds the team's role, on the same live membership
|
|
25
|
+
* row; their effective role is the highest of their own grant and their
|
|
26
|
+
* teams'. A seat or a grant removed is felt on the next request.
|
|
27
|
+
* - **The operator view.** A workspace owner or admin acts as a manager on
|
|
28
|
+
* every project of the workspace (ADR 006), which is why a project with no
|
|
29
|
+
* manager stays manageable and there is no last-manager guard.
|
|
30
|
+
* - **The archived-write rule.** `access: 'write'` is off while the project
|
|
31
|
+
* is archived, for everyone, the operator included. A READ stays.
|
|
32
|
+
*
|
|
33
|
+
* Callers answer 404, never 403, when a READ predicate is false: a project a
|
|
34
|
+
* principal cannot read must not reveal its existence.
|
|
35
|
+
*/
|
|
36
|
+
const LADDER = {
|
|
37
|
+
viewer: ['viewer', 'editor', 'manager'],
|
|
38
|
+
editor: ['editor', 'manager'],
|
|
39
|
+
manager: ['manager']
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* A boolean SQL expression over `projectId`, a column (or expression) of the
|
|
43
|
+
* CALLER's query that holds a project id: the tool's link table column, or
|
|
44
|
+
* `projects.id` itself. The aliases are prefixed so they cannot collide with
|
|
45
|
+
* the ones of the query the predicate is embedded in.
|
|
46
|
+
*
|
|
47
|
+
* **Pass a QUALIFIED reference when the predicate lands in a SELECT LIST.**
|
|
48
|
+
* drizzle renders a column object of a single-table select WITHOUT its table
|
|
49
|
+
* name there (`"id"`), and inside this subquery a bare `"id"` binds to the
|
|
50
|
+
* subquery's own tables: ambiguous at best, always-true at worst. A raw
|
|
51
|
+
* `sql\`"link_table"."project_id"\`` (or `PROJECTS_ID` below) is immune; a
|
|
52
|
+
* column object is safe in a WHERE, where drizzle always qualifies it.
|
|
53
|
+
*/
|
|
54
|
+
export function projectGrantPredicate(principal, projectId, opts) {
|
|
55
|
+
if (principal.origin === 'guest')
|
|
56
|
+
return sql `false`;
|
|
57
|
+
const live = opts.access === 'write' ? sql `AND prj_pr.archived_at IS NULL` : sql ``;
|
|
58
|
+
if (principal.role === 'owner' || principal.role === 'admin') {
|
|
59
|
+
return sql `EXISTS (
|
|
60
|
+
SELECT 1 FROM projects prj_pr
|
|
61
|
+
WHERE prj_pr.id = ${projectId}
|
|
62
|
+
AND prj_pr.workspace_id = ${principal.workspaceId}
|
|
63
|
+
${live}
|
|
64
|
+
)`;
|
|
65
|
+
}
|
|
66
|
+
const roles = sql.join(LADDER[opts.atLeast].map((role) => sql `${role}`), sql `, `);
|
|
67
|
+
// Two ways to hold a grant, judged on the SAME live membership row: the
|
|
68
|
+
// person's own entry (`project_members`), or the entry of a team the person
|
|
69
|
+
// is seated in (`project_teams` through `workspace_team_members`, PRDCT-2794).
|
|
70
|
+
// The team's workspace is checked against the membership's like the
|
|
71
|
+
// project's, so a seat can never reach across workspaces; the effective
|
|
72
|
+
// role is the highest of the two, which the ladder's IN list yields.
|
|
73
|
+
return sql `EXISTS (
|
|
74
|
+
SELECT 1
|
|
75
|
+
FROM workspace_members prj_wm
|
|
76
|
+
JOIN projects prj_pr ON prj_pr.workspace_id = prj_wm.workspace_id
|
|
77
|
+
WHERE prj_pr.id = ${projectId}
|
|
78
|
+
AND prj_wm.user_id = ${principal.userId}
|
|
79
|
+
AND prj_wm.workspace_id = ${principal.workspaceId}
|
|
80
|
+
AND prj_wm.is_active
|
|
81
|
+
AND prj_wm.origin <> 'guest'
|
|
82
|
+
${live}
|
|
83
|
+
AND (
|
|
84
|
+
EXISTS (
|
|
85
|
+
SELECT 1 FROM project_members prj_pm
|
|
86
|
+
WHERE prj_pm.project_id = prj_pr.id
|
|
87
|
+
AND prj_pm.member_id = prj_wm.id
|
|
88
|
+
AND prj_pm.role IN (${roles})
|
|
89
|
+
)
|
|
90
|
+
OR EXISTS (
|
|
91
|
+
SELECT 1
|
|
92
|
+
FROM project_teams prj_pt
|
|
93
|
+
JOIN workspace_team_members prj_tm ON prj_tm.team_id = prj_pt.team_id
|
|
94
|
+
JOIN workspace_teams prj_t ON prj_t.id = prj_pt.team_id
|
|
95
|
+
WHERE prj_pt.project_id = prj_pr.id
|
|
96
|
+
AND prj_tm.member_id = prj_wm.id
|
|
97
|
+
AND prj_t.workspace_id = prj_wm.workspace_id
|
|
98
|
+
AND prj_pt.role IN (${roles})
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
)`;
|
|
102
|
+
}
|
|
103
|
+
/** `projects.id`, always qualified: safe in a select list as in a WHERE (see above). */
|
|
104
|
+
export const PROJECTS_ID = sql.raw('"projects"."id"');
|
|
105
|
+
/**
|
|
106
|
+
* The caller's effective role on a project AS A SQL EXPRESSION over a project
|
|
107
|
+
* id column: `manager`, `editor`, `viewer`, or NULL (no read). Built from the
|
|
108
|
+
* predicate above, never beside it. Archive-blind on purpose: a role is a
|
|
109
|
+
* READ fact, and whether an act is allowed on an archived project is the
|
|
110
|
+
* act's own question (`access: 'write'`, or the route's 409).
|
|
111
|
+
*/
|
|
112
|
+
export function projectRoleExpression(principal, projectId) {
|
|
113
|
+
const has = (atLeast) => projectGrantPredicate(principal, projectId, { atLeast, access: 'read' });
|
|
114
|
+
return sql `CASE
|
|
115
|
+
WHEN ${has('manager')} THEN 'manager'
|
|
116
|
+
WHEN ${has('editor')} THEN 'editor'
|
|
117
|
+
WHEN ${has('viewer')} THEN 'viewer'
|
|
118
|
+
END`;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The effective role of `principal` on one project of the request's
|
|
122
|
+
* workspace, or null. **null = 404**: no such project here, or a project the
|
|
123
|
+
* principal cannot read; the two must stay indistinguishable to the caller.
|
|
124
|
+
*/
|
|
125
|
+
export async function projectRole(conn, principal, projectId) {
|
|
126
|
+
const rows = await conn
|
|
127
|
+
.select({ role: projectRoleExpression(principal, PROJECTS_ID) })
|
|
128
|
+
.from(projects)
|
|
129
|
+
.where(sql `${projects.id} = ${projectId} AND ${projects.workspaceId} = ${principal.workspaceId}`)
|
|
130
|
+
.limit(1);
|
|
131
|
+
return rows[0]?.role ?? null;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=access.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access.js","sourceRoot":"","sources":["../../src/projects/access.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAA6B,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAe,MAAM,wBAAwB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,MAAM,MAAM,GAAgD;IAC1D,MAAM,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC;IACvC,MAAM,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,OAAO,EAAE,CAAC,SAAS,CAAC;CACrB,CAAC;AASF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,qBAAqB,CACnC,SAAwE,EACxE,SAAqB,EACrB,IAAyB;IAEzB,IAAI,SAAS,CAAC,MAAM,KAAK,OAAO;QAAE,OAAO,GAAG,CAAA,OAAO,CAAC;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAA,gCAAgC,CAAC,CAAC,CAAC,GAAG,CAAA,EAAE,CAAC;IACnF,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC7D,OAAO,GAAG,CAAA;;0BAEY,SAAS;oCACC,SAAS,CAAC,WAAW;UAC/C,IAAI;MACR,CAAC;IACL,CAAC;IACD,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CACpB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAA,GAAG,IAAI,EAAE,CAAC,EAChD,GAAG,CAAA,IAAI,CACR,CAAC;IACF,wEAAwE;IACxE,4EAA4E;IAC5E,+EAA+E;IAC/E,oEAAoE;IACpE,wEAAwE;IACxE,qEAAqE;IACrE,OAAO,GAAG,CAAA;;;;wBAIY,SAAS;6BACJ,SAAS,CAAC,MAAM;kCACX,SAAS,CAAC,WAAW;;;QAG/C,IAAI;;;;;;kCAMsB,KAAK;;;;;;;;;;kCAUL,KAAK;;;IAGnC,CAAC;AACL,CAAC;AAED,wFAAwF;AACxF,MAAM,CAAC,MAAM,WAAW,GAAQ,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAE3D;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,SAAwE,EACxE,SAAqB;IAErB,MAAM,GAAG,GAAG,CAAC,OAAoB,EAAE,EAAE,CACnC,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3E,OAAO,GAAG,CAAoB;WACrB,GAAG,CAAC,SAAS,CAAC;WACd,GAAG,CAAC,QAAQ,CAAC;WACb,GAAG,CAAC,QAAQ,CAAC;MAClB,CAAC;AACP,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAY,EACZ,SAAwE,EACxE,SAAiB;IAEjB,MAAM,IAAI,GAAG,MAAM,IAAI;SACpB,MAAM,CAAC,EAAE,IAAI,EAAE,qBAAqB,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;SAC/D,IAAI,CAAC,QAAQ,CAAC;SACd,KAAK,CAAC,GAAG,CAAA,GAAG,QAAQ,CAAC,EAAE,MAAM,SAAS,QAAQ,QAAQ,CAAC,WAAW,MAAM,SAAS,CAAC,WAAW,EAAE,CAAC;SAChG,KAAK,CAAC,CAAC,CAAC,CAAC;IACZ,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/projects/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,WAAW,EACX,qBAAqB,EACrB,KAAK,mBAAmB,EACzB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/projects/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,WAAW,EACX,qBAAqB,EAEtB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Context } from 'hono';
|
|
2
|
+
/**
|
|
3
|
+
* The low-cardinality, secret-free label for a request, used by BOTH the
|
|
4
|
+
* completion log line and the trace span.
|
|
5
|
+
*
|
|
6
|
+
* The raw `c.req.path` must never reach the log stream or a span attribute.
|
|
7
|
+
* Path segments are request data like any other: the moment a route puts a
|
|
8
|
+
* capability in the URL — a share secret, a one-time token, an invitation
|
|
9
|
+
* code — every log sink, every trace backend, and every operator with
|
|
10
|
+
* `docker logs` holds a working credential, and the redaction list cannot
|
|
11
|
+
* help (it keys off object properties, and `path` is one opaque string).
|
|
12
|
+
* Logging the MATCHED ROUTE PATTERN instead (`/v/:secret`, not
|
|
13
|
+
* `/v/9f3c…`) keeps the line just as useful for debugging and cardinality
|
|
14
|
+
* bounded, and it is secret-free by construction for every route that will
|
|
15
|
+
* ever be added.
|
|
16
|
+
*
|
|
17
|
+
* `routePath` is only populated once routing has run, so callers must read
|
|
18
|
+
* this AFTER `await next()`. Unmatched requests have no pattern to report:
|
|
19
|
+
* they get the literal `(unmatched)` rather than the attacker-controlled URL
|
|
20
|
+
* they probed with.
|
|
21
|
+
*/
|
|
22
|
+
export declare function routeLabel(c: Context): string;
|
|
23
|
+
//# sourceMappingURL=route-label.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-label.d.ts","sourceRoot":"","sources":["../src/route-label.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAM7C"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The low-cardinality, secret-free label for a request, used by BOTH the
|
|
3
|
+
* completion log line and the trace span.
|
|
4
|
+
*
|
|
5
|
+
* The raw `c.req.path` must never reach the log stream or a span attribute.
|
|
6
|
+
* Path segments are request data like any other: the moment a route puts a
|
|
7
|
+
* capability in the URL — a share secret, a one-time token, an invitation
|
|
8
|
+
* code — every log sink, every trace backend, and every operator with
|
|
9
|
+
* `docker logs` holds a working credential, and the redaction list cannot
|
|
10
|
+
* help (it keys off object properties, and `path` is one opaque string).
|
|
11
|
+
* Logging the MATCHED ROUTE PATTERN instead (`/v/:secret`, not
|
|
12
|
+
* `/v/9f3c…`) keeps the line just as useful for debugging and cardinality
|
|
13
|
+
* bounded, and it is secret-free by construction for every route that will
|
|
14
|
+
* ever be added.
|
|
15
|
+
*
|
|
16
|
+
* `routePath` is only populated once routing has run, so callers must read
|
|
17
|
+
* this AFTER `await next()`. Unmatched requests have no pattern to report:
|
|
18
|
+
* they get the literal `(unmatched)` rather than the attacker-controlled URL
|
|
19
|
+
* they probed with.
|
|
20
|
+
*/
|
|
21
|
+
export function routeLabel(c) {
|
|
22
|
+
const matched = c.req.routePath;
|
|
23
|
+
// Hono answers '/*' for a catch-all match and for no match at all; neither
|
|
24
|
+
// says anything the pattern doesn't, and both are safe to report as-is.
|
|
25
|
+
if (!matched)
|
|
26
|
+
return '(unmatched)';
|
|
27
|
+
return matched;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=route-label.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-label.js","sourceRoot":"","sources":["../src/route-label.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,UAAU,CAAC,CAAU;IACnC,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC;IAChC,2EAA2E;IAC3E,wEAAwE;IACxE,IAAI,CAAC,OAAO;QAAE,OAAO,aAAa,CAAC;IACnC,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import type { RuntimeState } from '../state.js';
|
|
3
|
+
/**
|
|
4
|
+
* /healthz — liveness. No dependencies: answers 200 whenever the event loop
|
|
5
|
+
* runs, so orchestrators never restart a replica that is merely waiting on
|
|
6
|
+
* the database.
|
|
7
|
+
*
|
|
8
|
+
* /readyz — readiness. 503 until env is parsed, migrations are applied (or
|
|
9
|
+
* confirmed current), and the DB is reachable; 503 again while draining; and
|
|
10
|
+
* 503 whenever the backing store stops being writable.
|
|
11
|
+
*
|
|
12
|
+
* That last clause is the whole point of `probeStorage`. Readiness used to be
|
|
13
|
+
* a boot-time boolean, so the storage probe ran exactly once, at startup: an
|
|
14
|
+
* instance whose /data volume was emptied, unmounted or turned read-only
|
|
15
|
+
* after boot — the state a failed restore leaves behind — kept answering 200
|
|
16
|
+
* and kept taking traffic it could not serve. Readiness has to be a live
|
|
17
|
+
* claim about the dependencies, not a memory of them.
|
|
18
|
+
*/
|
|
19
|
+
export interface HealthDeps {
|
|
20
|
+
/** Re-probe the backing store. Must throw when it is not writable. */
|
|
21
|
+
probeStorage?: () => Promise<void>;
|
|
22
|
+
/** How long a SUCCESSFUL probe is trusted before it re-runs. */
|
|
23
|
+
storageProbeTtlMs?: number;
|
|
24
|
+
/** Called with the probe failure so it lands in the logs. */
|
|
25
|
+
onStorageFailure?: (err: unknown) => void;
|
|
26
|
+
/** Injectable clock (tests). */
|
|
27
|
+
now?: () => number;
|
|
28
|
+
}
|
|
29
|
+
export declare function healthRoutes(state: RuntimeState, deps?: HealthDeps): Hono;
|
|
30
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AASD,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,GAAE,UAAe,GAAG,IAAI,CAyC7E"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
/**
|
|
3
|
+
* Successes are cached briefly so a fast readiness poll does not become a
|
|
4
|
+
* PUT+DELETE per second against S3. Failures are NEVER cached: the next
|
|
5
|
+
* request re-probes, so recovery is observed immediately.
|
|
6
|
+
*/
|
|
7
|
+
const DEFAULT_STORAGE_PROBE_TTL_MS = 10_000;
|
|
8
|
+
export function healthRoutes(state, deps = {}) {
|
|
9
|
+
const app = new Hono();
|
|
10
|
+
const { probeStorage, onStorageFailure } = deps;
|
|
11
|
+
const ttlMs = deps.storageProbeTtlMs ?? DEFAULT_STORAGE_PROBE_TTL_MS;
|
|
12
|
+
const now = deps.now ?? (() => Date.now());
|
|
13
|
+
let trustedUntil = 0;
|
|
14
|
+
let inflight = null;
|
|
15
|
+
/** Resolves to the failure, or null when storage is reachable. */
|
|
16
|
+
function checkStorage() {
|
|
17
|
+
if (!probeStorage)
|
|
18
|
+
return Promise.resolve(null);
|
|
19
|
+
if (now() < trustedUntil)
|
|
20
|
+
return Promise.resolve(null);
|
|
21
|
+
// One probe at a time: a burst of readiness polls must not fan out into a
|
|
22
|
+
// burst of writes against the store.
|
|
23
|
+
const pending = (inflight ??= (async () => {
|
|
24
|
+
try {
|
|
25
|
+
await probeStorage();
|
|
26
|
+
trustedUntil = now() + ttlMs;
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
trustedUntil = 0;
|
|
31
|
+
onStorageFailure?.(err);
|
|
32
|
+
return err ?? new Error('storage probe failed');
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
inflight = null;
|
|
36
|
+
}
|
|
37
|
+
})());
|
|
38
|
+
return pending;
|
|
39
|
+
}
|
|
40
|
+
app.get('/healthz', (c) => c.json({ status: 'ok' }));
|
|
41
|
+
app.get('/readyz', async (c) => {
|
|
42
|
+
if (state.draining)
|
|
43
|
+
return c.json({ status: 'unavailable', reason: 'draining' }, 503);
|
|
44
|
+
if (!state.ready)
|
|
45
|
+
return c.json({ status: 'unavailable', reason: state.reason }, 503);
|
|
46
|
+
// The reason stays coarse on purpose: /readyz is unauthenticated and a
|
|
47
|
+
// driver's error text carries bucket names and filesystem paths.
|
|
48
|
+
if (await checkStorage())
|
|
49
|
+
return c.json({ status: 'unavailable', reason: 'storage' }, 503);
|
|
50
|
+
return c.json({ status: 'ready' });
|
|
51
|
+
});
|
|
52
|
+
return app;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AA8B5B;;;;GAIG;AACH,MAAM,4BAA4B,GAAG,MAAM,CAAC;AAE5C,MAAM,UAAU,YAAY,CAAC,KAAmB,EAAE,OAAmB,EAAE;IACrE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC;IAChD,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,IAAI,4BAA4B,CAAC;IACrE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAE3C,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,QAAQ,GAA4B,IAAI,CAAC;IAE7C,kEAAkE;IAClE,SAAS,YAAY;QACnB,IAAI,CAAC,YAAY;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,GAAG,EAAE,GAAG,YAAY;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvD,0EAA0E;QAC1E,qCAAqC;QACrC,MAAM,OAAO,GAAG,CAAC,QAAQ,KAAK,CAAC,KAAK,IAAI,EAAE;YACxC,IAAI,CAAC;gBACH,MAAM,YAAY,EAAE,CAAC;gBACrB,YAAY,GAAG,GAAG,EAAE,GAAG,KAAK,CAAC;gBAC7B,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,YAAY,GAAG,CAAC,CAAC;gBACjB,gBAAgB,EAAE,CAAC,GAAG,CAAC,CAAC;gBACxB,OAAO,GAAG,IAAI,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;YAClD,CAAC;oBAAS,CAAC;gBACT,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;QACH,CAAC,CAAC,EAAE,CAAC,CAAC;QACN,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACrD,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC7B,IAAI,KAAK,CAAC,QAAQ;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,GAAG,CAAC,CAAC;QACtF,IAAI,CAAC,KAAK,CAAC,KAAK;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC;QACtF,uEAAuE;QACvE,iEAAiE;QACjE,IAAI,MAAM,YAAY,EAAE;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,GAAG,CAAC,CAAC;QAC3F,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { type Auth } from '../identity/better-auth.js';
|
|
3
|
+
export interface WellKnownDeps {
|
|
4
|
+
auth: Auth;
|
|
5
|
+
publicBaseUrl: string;
|
|
6
|
+
instanceName?: string;
|
|
7
|
+
/** The tool's OAuth scope list, as registered with the provider: what `scopes_supported` advertises. */
|
|
8
|
+
oauthScopes: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
export declare function wellKnownRoutes({ auth, publicBaseUrl, oauthScopes }: WellKnownDeps): Hono;
|
|
11
|
+
//# sourceMappingURL=wellknown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wellknown.d.ts","sourceRoot":"","sources":["../../src/routes/wellknown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAK1C,OAAO,EAAkB,KAAK,IAAI,EAAE,MAAM,4BAA4B,CAAC;AAoBvE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wGAAwG;IACxG,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAED,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,EAAE,aAAa,GAAG,IAAI,CAiCzF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { oauthProviderAuthServerMetadata, oauthProviderOpenIdConfigMetadata } from '@better-auth/oauth-provider';
|
|
3
|
+
import { mcpResourceUrl } from '../identity/better-auth.js';
|
|
4
|
+
/**
|
|
5
|
+
* Root-level OAuth discovery surface.
|
|
6
|
+
*
|
|
7
|
+
* The oauthProvider plugin serves RFC 8414 / OIDC discovery under the
|
|
8
|
+
* /api/v1/auth base path, but clients resolve discovery from the ISSUER (the
|
|
9
|
+
* bare origin — jwt.issuer in identity/better-auth.ts), so the same documents
|
|
10
|
+
* must exist at the origin root. RFC 9728 protected-resource metadata is ours:
|
|
11
|
+
* it points the 401-challenged MCP client at this same origin as its
|
|
12
|
+
* authorization server. All documents are public by design and fetched
|
|
13
|
+
* cross-origin by browser-based MCP hosts — wide-open CORS is correct.
|
|
14
|
+
*/
|
|
15
|
+
const CORS_HEADERS = {
|
|
16
|
+
'Access-Control-Allow-Origin': '*',
|
|
17
|
+
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
|
18
|
+
'Access-Control-Allow-Headers': 'Content-Type, Authorization, mcp-protocol-version',
|
|
19
|
+
'Access-Control-Max-Age': '86400'
|
|
20
|
+
};
|
|
21
|
+
export function wellKnownRoutes({ auth, publicBaseUrl, oauthScopes }) {
|
|
22
|
+
const app = new Hono();
|
|
23
|
+
const asMetadata = oauthProviderAuthServerMetadata(auth, {
|
|
24
|
+
headers: { ...CORS_HEADERS, 'Cache-Control': 'public, max-age=3600' }
|
|
25
|
+
});
|
|
26
|
+
const oidcMetadata = oauthProviderOpenIdConfigMetadata(auth, {
|
|
27
|
+
headers: { ...CORS_HEADERS, 'Cache-Control': 'public, max-age=3600' }
|
|
28
|
+
});
|
|
29
|
+
app.get('/.well-known/oauth-authorization-server', (c) => asMetadata(c.req.raw));
|
|
30
|
+
app.get('/.well-known/openid-configuration', (c) => oidcMetadata(c.req.raw));
|
|
31
|
+
// RFC 9728: served at the origin level AND at the path-aware derivation
|
|
32
|
+
// (clients insert /.well-known/oauth-protected-resource between origin and
|
|
33
|
+
// the resource path /mcp) — both return the same document.
|
|
34
|
+
const protectedResource = (c) => c.json({
|
|
35
|
+
resource: mcpResourceUrl(publicBaseUrl),
|
|
36
|
+
authorization_servers: [publicBaseUrl],
|
|
37
|
+
scopes_supported: [...oauthScopes],
|
|
38
|
+
bearer_methods_supported: ['header']
|
|
39
|
+
}, 200, { ...CORS_HEADERS, 'Cache-Control': 'public, max-age=3600' });
|
|
40
|
+
app.get('/.well-known/oauth-protected-resource', (c) => protectedResource(c));
|
|
41
|
+
app.get('/.well-known/oauth-protected-resource/mcp', (c) => protectedResource(c));
|
|
42
|
+
app.options('/.well-known/*', (c) => c.body(null, 204, { ...CORS_HEADERS }));
|
|
43
|
+
return app;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=wellknown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wellknown.js","sourceRoot":"","sources":["../../src/routes/wellknown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAC1C,OAAO,EACL,+BAA+B,EAC/B,iCAAiC,EAClC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,cAAc,EAAa,MAAM,4BAA4B,CAAC;AAEvE;;;;;;;;;;GAUG;AACH,MAAM,YAAY,GAAG;IACnB,6BAA6B,EAAE,GAAG;IAClC,8BAA8B,EAAE,cAAc;IAC9C,8BAA8B,EAAE,mDAAmD;IACnF,wBAAwB,EAAE,OAAO;CACzB,CAAC;AAUX,MAAM,UAAU,eAAe,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAiB;IACjF,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,MAAM,UAAU,GAAG,+BAA+B,CAAC,IAAI,EAAE;QACvD,OAAO,EAAE,EAAE,GAAG,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE;KACtE,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,iCAAiC,CAAC,IAAI,EAAE;QAC3D,OAAO,EAAE,EAAE,GAAG,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE;KACtE,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,yCAAyC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACjF,GAAG,CAAC,GAAG,CAAC,mCAAmC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAE7E,wEAAwE;IACxE,2EAA2E;IAC3E,2DAA2D;IAC3D,MAAM,iBAAiB,GAAG,CAAC,CAAU,EAAE,EAAE,CACvC,CAAC,CAAC,IAAI,CACJ;QACE,QAAQ,EAAE,cAAc,CAAC,aAAa,CAAC;QACvC,qBAAqB,EAAE,CAAC,aAAa,CAAC;QACtC,gBAAgB,EAAE,CAAC,GAAG,WAAW,CAAC;QAClC,wBAAwB,EAAE,CAAC,QAAQ,CAAC;KACrC,EACD,GAAG,EACH,EAAE,GAAG,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,CAC7D,CAAC;IACJ,GAAG,CAAC,GAAG,CAAC,uCAAuC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,GAAG,CAAC,GAAG,CAAC,2CAA2C,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;IAElF,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,GAAG,YAAY,EAAE,CAAC,CAAC,CAAC;IAE7E,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/secret.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Logger } from './logger.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the auth secret: prefer AUTH_SECRET from the environment; otherwise
|
|
4
|
+
* persist a generated one under DATA_DIR (n8n-style zero-config first run).
|
|
5
|
+
* The file is written 0600 and reused on every subsequent boot, so sessions
|
|
6
|
+
* survive restarts even when the operator never set a secret.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveAuthSecret(envSecret: string | undefined, dataDir: string, log: Logger): Promise<string>;
|
|
9
|
+
/** Where a boot-generated setup token lives until the instance is claimed. */
|
|
10
|
+
export declare function generatedSetupTokenPath(dataDir: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* The credential POST /api/v1/setup REQUIRES (PRDCT-1347, audit A7). The
|
|
13
|
+
* first-boot claim decides who owns the instance, so it can never be free:
|
|
14
|
+
*
|
|
15
|
+
* - `SETUP_TOKEN` set → that is the token (setup.sh writes one);
|
|
16
|
+
* - instance already set up → nothing to claim, no token needed (null);
|
|
17
|
+
* - otherwise → a token is generated ONCE into `$DATA_DIR/setup-token`
|
|
18
|
+
* (0600, atomic write, reused on every later boot until the claim) and
|
|
19
|
+
* printed to the container log, so the `docker run` / plain
|
|
20
|
+
* `docker compose up` paths — which never go through setup.sh — still
|
|
21
|
+
* produce an instance claimable only with a secret. The file is removed
|
|
22
|
+
* once setup completes (see clearGeneratedSetupToken).
|
|
23
|
+
*
|
|
24
|
+
* Optional-when-set was the hole: a minimal-env container answered the
|
|
25
|
+
* claim with 201 and no credential at all.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveSetupToken(envToken: string | undefined, dataDir: string, alreadySetUp: boolean, log: Logger): Promise<string | null>;
|
|
28
|
+
/** Best-effort removal of the generated token once the claim has succeeded. */
|
|
29
|
+
export declare function clearGeneratedSetupToken(dataDir: string): Promise<void>;
|
|
30
|
+
//# sourceMappingURL=secret.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret.d.ts","sourceRoot":"","sources":["../src/secret.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CA8BjB;AAED,8EAA8E;AAC9E,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,OAAO,EACrB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoCxB;AAED,+EAA+E;AAC/E,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE7E"}
|
package/dist/secret.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the auth secret: prefer AUTH_SECRET from the environment; otherwise
|
|
6
|
+
* persist a generated one under DATA_DIR (n8n-style zero-config first run).
|
|
7
|
+
* The file is written 0600 and reused on every subsequent boot, so sessions
|
|
8
|
+
* survive restarts even when the operator never set a secret.
|
|
9
|
+
*/
|
|
10
|
+
export async function resolveAuthSecret(envSecret, dataDir, log) {
|
|
11
|
+
if (envSecret)
|
|
12
|
+
return envSecret;
|
|
13
|
+
const secretPath = join(dataDir, 'secret');
|
|
14
|
+
try {
|
|
15
|
+
const existing = (await readFile(secretPath, 'utf8')).trim();
|
|
16
|
+
if (existing.length >= 32)
|
|
17
|
+
return existing;
|
|
18
|
+
log.warn({ secretPath }, 'existing secret file is too short — regenerating');
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// no secret file yet
|
|
22
|
+
}
|
|
23
|
+
const secret = randomBytes(32).toString('hex');
|
|
24
|
+
await mkdir(dataDir, { recursive: true });
|
|
25
|
+
// Write + rename (same dir → atomic) so a crash mid-write never leaves a
|
|
26
|
+
// truncated secret that a later boot would accept and lock everyone out.
|
|
27
|
+
const tmpPath = join(dataDir, `.secret.${randomBytes(6).toString('hex')}.tmp`);
|
|
28
|
+
try {
|
|
29
|
+
await writeFile(tmpPath, secret + '\n', { mode: 0o600 });
|
|
30
|
+
await rename(tmpPath, secretPath);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
await rm(tmpPath, { force: true });
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
36
|
+
log.warn({ secretPath }, 'AUTH_SECRET was not set — generated one into the data volume. ' +
|
|
37
|
+
'Set AUTH_SECRET explicitly for multi-replica deployments; all replicas must share it.');
|
|
38
|
+
return secret;
|
|
39
|
+
}
|
|
40
|
+
/** Where a boot-generated setup token lives until the instance is claimed. */
|
|
41
|
+
export function generatedSetupTokenPath(dataDir) {
|
|
42
|
+
return join(dataDir, 'setup-token');
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The credential POST /api/v1/setup REQUIRES (PRDCT-1347, audit A7). The
|
|
46
|
+
* first-boot claim decides who owns the instance, so it can never be free:
|
|
47
|
+
*
|
|
48
|
+
* - `SETUP_TOKEN` set → that is the token (setup.sh writes one);
|
|
49
|
+
* - instance already set up → nothing to claim, no token needed (null);
|
|
50
|
+
* - otherwise → a token is generated ONCE into `$DATA_DIR/setup-token`
|
|
51
|
+
* (0600, atomic write, reused on every later boot until the claim) and
|
|
52
|
+
* printed to the container log, so the `docker run` / plain
|
|
53
|
+
* `docker compose up` paths — which never go through setup.sh — still
|
|
54
|
+
* produce an instance claimable only with a secret. The file is removed
|
|
55
|
+
* once setup completes (see clearGeneratedSetupToken).
|
|
56
|
+
*
|
|
57
|
+
* Optional-when-set was the hole: a minimal-env container answered the
|
|
58
|
+
* claim with 201 and no credential at all.
|
|
59
|
+
*/
|
|
60
|
+
export async function resolveSetupToken(envToken, dataDir, alreadySetUp, log) {
|
|
61
|
+
if (envToken)
|
|
62
|
+
return envToken;
|
|
63
|
+
if (alreadySetUp)
|
|
64
|
+
return null;
|
|
65
|
+
const tokenPath = generatedSetupTokenPath(dataDir);
|
|
66
|
+
try {
|
|
67
|
+
const existing = (await readFile(tokenPath, 'utf8')).trim();
|
|
68
|
+
if (existing.length >= 16) {
|
|
69
|
+
log.warn({ tokenPath }, `SETUP_TOKEN is not set — the setup wizard requires the token generated at first boot: ${existing}`);
|
|
70
|
+
return existing;
|
|
71
|
+
}
|
|
72
|
+
log.warn({ tokenPath }, 'existing setup-token file is too short — regenerating');
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// no token file yet
|
|
76
|
+
}
|
|
77
|
+
const token = randomBytes(16).toString('hex');
|
|
78
|
+
await mkdir(dataDir, { recursive: true });
|
|
79
|
+
const tmpPath = join(dataDir, `.setup-token.${randomBytes(6).toString('hex')}.tmp`);
|
|
80
|
+
try {
|
|
81
|
+
await writeFile(tmpPath, token + '\n', { mode: 0o600 });
|
|
82
|
+
await rename(tmpPath, tokenPath);
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
await rm(tmpPath, { force: true });
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
log.warn({ tokenPath }, 'SETUP_TOKEN was not set — generated one for the first-boot setup wizard. ' +
|
|
89
|
+
`Use this token to claim the instance: ${token} ` +
|
|
90
|
+
'(also readable inside the container at that path; set SETUP_TOKEN explicitly to choose your own)');
|
|
91
|
+
return token;
|
|
92
|
+
}
|
|
93
|
+
/** Best-effort removal of the generated token once the claim has succeeded. */
|
|
94
|
+
export async function clearGeneratedSetupToken(dataDir) {
|
|
95
|
+
await rm(generatedSetupTokenPath(dataDir), { force: true });
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=secret.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret.js","sourceRoot":"","sources":["../src/secret.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,SAA6B,EAC7B,OAAe,EACf,GAAW;IAEX,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IAEhC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7D,IAAI,QAAQ,CAAC,MAAM,IAAI,EAAE;YAAE,OAAO,QAAQ,CAAC;QAC3C,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,EAAE,kDAAkD,CAAC,CAAC;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,qBAAqB;IACvB,CAAC;IAED,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,yEAAyE;IACzE,yEAAyE;IACzE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/E,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACzD,MAAM,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnC,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,GAAG,CAAC,IAAI,CACN,EAAE,UAAU,EAAE,EACd,gEAAgE;QAC9D,uFAAuF,CAC1F,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,uBAAuB,CAAC,OAAe;IACrD,OAAO,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAA4B,EAC5B,OAAe,EACf,YAAqB,EACrB,GAAW;IAEX,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,IAAI,YAAY;QAAE,OAAO,IAAI,CAAC;IAE9B,MAAM,SAAS,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACnD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5D,IAAI,QAAQ,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;YAC1B,GAAG,CAAC,IAAI,CACN,EAAE,SAAS,EAAE,EACb,yFAAyF,QAAQ,EAAE,CACpG,CAAC;YACF,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,uDAAuD,CAAC,CAAC;IACnF,CAAC;IAAC,MAAM,CAAC;QACP,oBAAoB;IACtB,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,gBAAgB,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACpF,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,OAAO,EAAE,KAAK,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACxD,MAAM,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnC,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,GAAG,CAAC,IAAI,CACN,EAAE,SAAS,EAAE,EACb,2EAA2E;QACzE,yCAAyC,KAAK,IAAI;QAClD,kGAAkG,CACrG,CAAC;IACF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,OAAe;IAC5D,MAAM,EAAE,CAAC,uBAAuB,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport guard for the one-shot first-boot wizard (PLT-10).
|
|
3
|
+
*
|
|
4
|
+
* `POST /api/v1/setup` carries the owner's password and the setup token. Over
|
|
5
|
+
* plaintext HTTP to a non-loopback origin both cross the network in the clear
|
|
6
|
+
* — and this is the single request that decides who owns the instance. The
|
|
7
|
+
* documented no-domain install path used to walk operators straight into
|
|
8
|
+
* exactly that, so the server refuses instead of trusting the runbook.
|
|
9
|
+
*
|
|
10
|
+
* Loopback is fine: nothing leaves the host, which is what makes the
|
|
11
|
+
* `ssh -L` tunnel a legitimate way to finish setup on a server with no TLS
|
|
12
|
+
* yet. `https` is fine anywhere. Everything else needs the conscious
|
|
13
|
+
* `ALLOW_INSECURE_SETUP=true` opt-in.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isSecureSetupOrigin(publicBaseUrl: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* `URL.hostname` KEEPS the brackets around an IPv6 literal (`[::1]`), so they
|
|
18
|
+
* are stripped here. IPv4 loopback is the whole 127.0.0.0/8 block, not just
|
|
19
|
+
* 127.0.0.1. Exported for the demo sign-in's host rule
|
|
20
|
+
* (identity/demo-pass-rules.ts): one loopback test for the whole server.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isLoopbackHost(hostname: string): boolean;
|
|
23
|
+
//# sourceMappingURL=setup-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-transport.d.ts","sourceRoot":"","sources":["../src/setup-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAWlE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAYxD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport guard for the one-shot first-boot wizard (PLT-10).
|
|
3
|
+
*
|
|
4
|
+
* `POST /api/v1/setup` carries the owner's password and the setup token. Over
|
|
5
|
+
* plaintext HTTP to a non-loopback origin both cross the network in the clear
|
|
6
|
+
* — and this is the single request that decides who owns the instance. The
|
|
7
|
+
* documented no-domain install path used to walk operators straight into
|
|
8
|
+
* exactly that, so the server refuses instead of trusting the runbook.
|
|
9
|
+
*
|
|
10
|
+
* Loopback is fine: nothing leaves the host, which is what makes the
|
|
11
|
+
* `ssh -L` tunnel a legitimate way to finish setup on a server with no TLS
|
|
12
|
+
* yet. `https` is fine anywhere. Everything else needs the conscious
|
|
13
|
+
* `ALLOW_INSECURE_SETUP=true` opt-in.
|
|
14
|
+
*/
|
|
15
|
+
export function isSecureSetupOrigin(publicBaseUrl) {
|
|
16
|
+
let url;
|
|
17
|
+
try {
|
|
18
|
+
url = new URL(publicBaseUrl);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Unparseable never reaches here (the env schema validates a URL), and a
|
|
22
|
+
// guard that cannot read the origin must fail closed.
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
if (url.protocol === 'https:')
|
|
26
|
+
return true;
|
|
27
|
+
return isLoopbackHost(url.hostname);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* `URL.hostname` KEEPS the brackets around an IPv6 literal (`[::1]`), so they
|
|
31
|
+
* are stripped here. IPv4 loopback is the whole 127.0.0.0/8 block, not just
|
|
32
|
+
* 127.0.0.1. Exported for the demo sign-in's host rule
|
|
33
|
+
* (identity/demo-pass-rules.ts): one loopback test for the whole server.
|
|
34
|
+
*/
|
|
35
|
+
export function isLoopbackHost(hostname) {
|
|
36
|
+
let host = hostname.toLowerCase();
|
|
37
|
+
if (host.startsWith('[') && host.endsWith(']'))
|
|
38
|
+
host = host.slice(1, -1);
|
|
39
|
+
if (host === 'localhost' || host.endsWith('.localhost'))
|
|
40
|
+
return true;
|
|
41
|
+
if (host === '::1' || host === '0:0:0:0:0:0:0:1')
|
|
42
|
+
return true;
|
|
43
|
+
const v4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
|
|
44
|
+
if (v4) {
|
|
45
|
+
const octets = v4.slice(1).map(Number);
|
|
46
|
+
if (octets.some((o) => o > 255))
|
|
47
|
+
return false;
|
|
48
|
+
return octets[0] === 127;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=setup-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-transport.js","sourceRoot":"","sources":["../src/setup-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,mBAAmB,CAAC,aAAqB;IACvD,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;QACzE,sDAAsD;QACtD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3C,OAAO,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,IAAI,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IAClC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACzE,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,OAAO,IAAI,CAAC;IACrE,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAC;IAC9D,MAAM,EAAE,GAAG,8CAA8C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrE,IAAI,EAAE,EAAE,CAAC;QACP,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QAC9C,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;IAC3B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|