@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,190 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
2
|
+
import type { StartedPostgreSqlContainer } from '@testcontainers/postgresql';
|
|
3
|
+
import {
|
|
4
|
+
createDatabase,
|
|
5
|
+
createTestApp,
|
|
6
|
+
extractCookie,
|
|
7
|
+
readJson,
|
|
8
|
+
startPostgres,
|
|
9
|
+
type TestApp,
|
|
10
|
+
host
|
|
11
|
+
} from './helpers.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The security-fix regression battery (audit merge, milestone A):
|
|
15
|
+
* - login rate limit holds per-account under a shared/rotating IP;
|
|
16
|
+
* - the /mcp endpoint has a rate-limit wall;
|
|
17
|
+
* - an audit-write failure never fails the audited mutation.
|
|
18
|
+
* XFF is trusted in tests (helpers set TRUST_PROXY=true), so each request can
|
|
19
|
+
* own its bucket by setting x-forwarded-for.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const OWNER = { email: 'owner@sec.test', name: 'Sec Owner', password: 'sec-owner-password-123' };
|
|
23
|
+
|
|
24
|
+
let container: StartedPostgreSqlContainer;
|
|
25
|
+
let app: TestApp;
|
|
26
|
+
// Captured before any rate-limit spamming below exhausts the owner's login bucket.
|
|
27
|
+
let ownerCookie: string;
|
|
28
|
+
|
|
29
|
+
const json = (body: unknown) => ({
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'content-type': 'application/json' },
|
|
32
|
+
body: JSON.stringify(body)
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
beforeAll(async () => {
|
|
36
|
+
container = await startPostgres();
|
|
37
|
+
app = await createTestApp(await createDatabase(container, 'sec'));
|
|
38
|
+
await app.app.request(
|
|
39
|
+
'/api/v1/setup',
|
|
40
|
+
json({ setupToken: 'integration-test-setup-token', instanceName: 'Sec', owner: OWNER })
|
|
41
|
+
);
|
|
42
|
+
const signIn = await app.app.request(
|
|
43
|
+
'/api/v1/auth/sign-in/email',
|
|
44
|
+
json({ email: OWNER.email, password: OWNER.password })
|
|
45
|
+
);
|
|
46
|
+
ownerCookie = extractCookie(signIn);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
afterAll(async () => {
|
|
50
|
+
await app?.stop();
|
|
51
|
+
await container?.stop();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('login rate limit is keyed per-account, not only per-IP', () => {
|
|
55
|
+
it('trips for one victim email even as the IP rotates every request', async () => {
|
|
56
|
+
const badLogin = (email: string, xff: string) =>
|
|
57
|
+
app.app.request('/api/v1/auth/sign-in/email', {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: { 'content-type': 'application/json', 'x-forwarded-for': xff },
|
|
60
|
+
body: JSON.stringify({ email, password: 'wrong-password-entirely' })
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Rotate the IP on every attempt so the per-IP key never accumulates; only
|
|
64
|
+
// the per-email key can trip. The login bucket is 10 per window.
|
|
65
|
+
let sawVictimRateLimit = false;
|
|
66
|
+
for (let i = 0; i < 15 && !sawVictimRateLimit; i++) {
|
|
67
|
+
const r = await badLogin(OWNER.email, `203.0.113.${i + 1}`);
|
|
68
|
+
if (r.status === 429) sawVictimRateLimit = true;
|
|
69
|
+
else expect(r.status).toBe(401);
|
|
70
|
+
}
|
|
71
|
+
expect(sawVictimRateLimit).toBe(true);
|
|
72
|
+
|
|
73
|
+
// A DIFFERENT account from a fresh IP is unaffected (its own email bucket).
|
|
74
|
+
const other = await badLogin('someone-else@sec.test', '198.51.100.42');
|
|
75
|
+
expect(other.status).toBe(401);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('/mcp rate-limit wall', () => {
|
|
80
|
+
it('rejects an unauthenticated flood from one IP with 429 after the limit', async () => {
|
|
81
|
+
const flood = () =>
|
|
82
|
+
app.app.request('/mcp', { method: 'POST', headers: { 'x-forwarded-for': '192.0.2.200' } });
|
|
83
|
+
|
|
84
|
+
// Before the wall trips, unauthenticated requests are 401 (RFC 9728).
|
|
85
|
+
const first = await flood();
|
|
86
|
+
expect(first.status).toBe(401);
|
|
87
|
+
|
|
88
|
+
// The mcp bucket is 1200/min (sized for an event's room); hammer past it and assert a 429 appears.
|
|
89
|
+
let sawRateLimit = false;
|
|
90
|
+
for (let i = 0; i < 1300 && !sawRateLimit; i++) {
|
|
91
|
+
const r = await flood();
|
|
92
|
+
if (r.status === 429) sawRateLimit = true;
|
|
93
|
+
else expect(r.status).toBe(401);
|
|
94
|
+
}
|
|
95
|
+
expect(sawRateLimit).toBe(true);
|
|
96
|
+
|
|
97
|
+
// The wall is per-IP: a different address still gets the normal 401.
|
|
98
|
+
const other = await app.app.request('/mcp', {
|
|
99
|
+
method: 'POST',
|
|
100
|
+
headers: { 'x-forwarded-for': '192.0.2.201' }
|
|
101
|
+
});
|
|
102
|
+
expect(other.status).toBe(401);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe('request body size cap', () => {
|
|
107
|
+
it('rejects an oversized JSON body with 413', async () => {
|
|
108
|
+
const huge = 'x'.repeat(2 * 1024 * 1024); // 2 MiB > the 1 MiB JSON cap
|
|
109
|
+
const res = await app.app.request('/api/v1/api-keys', {
|
|
110
|
+
method: 'POST',
|
|
111
|
+
headers: { 'content-type': 'application/json', cookie: ownerCookie },
|
|
112
|
+
body: JSON.stringify({ name: huge, scopes: [host.scopes.read] })
|
|
113
|
+
});
|
|
114
|
+
expect(res.status).toBe(413);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('does NOT cap file uploads (they stream with their own limit)', async () => {
|
|
118
|
+
// 1.5 MiB — above the JSON cap, well under MAX_FILE_SIZE_MB (100).
|
|
119
|
+
const body = 'a'.repeat(Math.floor(1.5 * 1024 * 1024));
|
|
120
|
+
const res = await app.app.request('/api/v1/files?name=big.bin', {
|
|
121
|
+
method: 'POST',
|
|
122
|
+
headers: { 'content-type': 'application/octet-stream', cookie: ownerCookie },
|
|
123
|
+
body
|
|
124
|
+
});
|
|
125
|
+
expect(res.status).toBe(201);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe('audit retention purge', () => {
|
|
130
|
+
it('deletes rows older than the retention window and keeps recent ones', async () => {
|
|
131
|
+
const wsRes = await app.db.pool.query<{ id: string }>('SELECT id FROM workspaces LIMIT 1');
|
|
132
|
+
const workspaceId = wsRes.rows[0]?.id;
|
|
133
|
+
expect(workspaceId).toBeTruthy();
|
|
134
|
+
|
|
135
|
+
const countAncient = async () =>
|
|
136
|
+
(
|
|
137
|
+
await app.db.pool.query<{ n: number }>(
|
|
138
|
+
`SELECT count(*)::int AS n FROM audit_log WHERE action = 'ancient.event'`
|
|
139
|
+
)
|
|
140
|
+
).rows[0]?.n ?? 0;
|
|
141
|
+
|
|
142
|
+
await app.db.pool.query(
|
|
143
|
+
`INSERT INTO audit_log (workspace_id, actor_via, action, resource_type, created_at)
|
|
144
|
+
VALUES ($1, 'system', 'ancient.event', 'test', now() - interval '400 days')`,
|
|
145
|
+
[workspaceId]
|
|
146
|
+
);
|
|
147
|
+
expect(await countAncient()).toBe(1);
|
|
148
|
+
|
|
149
|
+
// Trigger the worker's purge handler out of band (the schedule is 03:00).
|
|
150
|
+
await app.jobs.boss.send('audit-purge', {});
|
|
151
|
+
|
|
152
|
+
const deadline = Date.now() + 15_000;
|
|
153
|
+
let ancient = 1;
|
|
154
|
+
while (ancient > 0 && Date.now() < deadline) {
|
|
155
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
156
|
+
ancient = await countAncient();
|
|
157
|
+
}
|
|
158
|
+
expect(ancient).toBe(0);
|
|
159
|
+
|
|
160
|
+
// Recent rows (created by earlier tests in this file) are untouched.
|
|
161
|
+
const recent = await app.db.pool.query<{ n: number }>(
|
|
162
|
+
`SELECT count(*)::int AS n FROM audit_log WHERE created_at > now() - interval '1 day'`
|
|
163
|
+
);
|
|
164
|
+
expect(recent.rows[0]?.n ?? 0).toBeGreaterThan(0);
|
|
165
|
+
}, 30_000);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe('audit writes are best-effort (a committed mutation must not 500)', () => {
|
|
169
|
+
it('returns 201 and persists the mutation even when the audit insert fails', async () => {
|
|
170
|
+
// Break the audit sink out from under the request lifecycle.
|
|
171
|
+
await app.db.pool.query('ALTER TABLE audit_log RENAME TO audit_log_broken');
|
|
172
|
+
try {
|
|
173
|
+
const res = await app.app.request('/api/v1/api-keys', {
|
|
174
|
+
...json({ name: 'survives-audit-outage', scopes: [host.scopes.read] }),
|
|
175
|
+
headers: { 'content-type': 'application/json', cookie: ownerCookie }
|
|
176
|
+
});
|
|
177
|
+
// The mutation committed; the failed audit write is logged, not fatal.
|
|
178
|
+
expect(res.status).toBe(201);
|
|
179
|
+
const body = await readJson(res);
|
|
180
|
+
expect(body.apiKey.name).toBe('survives-audit-outage');
|
|
181
|
+
|
|
182
|
+
// And it is really persisted (listable) despite the audit failure.
|
|
183
|
+
const list = await app.app.request('/api/v1/api-keys', { headers: { cookie: ownerCookie } });
|
|
184
|
+
const listBody = await readJson(list);
|
|
185
|
+
expect(listBody.apiKeys.map((k: { name: string }) => k.name)).toContain('survives-audit-outage');
|
|
186
|
+
} finally {
|
|
187
|
+
await app.db.pool.query('ALTER TABLE audit_log_broken RENAME TO audit_log');
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
2
|
+
import type { StartedPostgreSqlContainer } from '@testcontainers/postgresql';
|
|
3
|
+
import { createDatabase, createTestApp, startPostgres, type TestApp, SETUP_TOKEN } from './helpers.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* PLT-10, end to end: the one-shot wizard is the request that decides who
|
|
7
|
+
* owns the instance, and it carries the owner password plus the setup token.
|
|
8
|
+
* On a plaintext, non-loopback origin the server refuses it outright — the
|
|
9
|
+
* documented no-domain install path used to walk operators straight into
|
|
10
|
+
* handing both to the network.
|
|
11
|
+
*
|
|
12
|
+
* The refusal must sit BEFORE the token check, and it must not be reachable
|
|
13
|
+
* around by presenting a correct token.
|
|
14
|
+
*/
|
|
15
|
+
let container: StartedPostgreSqlContainer;
|
|
16
|
+
|
|
17
|
+
const owner = {
|
|
18
|
+
email: 'owner@example.com',
|
|
19
|
+
password: 'correct-horse-battery-staple',
|
|
20
|
+
name: 'Owner'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
async function bootWith(env: Record<string, string>, dbName: string): Promise<TestApp> {
|
|
24
|
+
const url = await createDatabase(container, dbName);
|
|
25
|
+
return createTestApp(url, env);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function postSetup(app: TestApp, body: unknown): Promise<Response> {
|
|
29
|
+
return app.app.request('/api/v1/setup', {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'content-type': 'application/json' },
|
|
32
|
+
body: JSON.stringify(body)
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
beforeAll(async () => {
|
|
37
|
+
container = await startPostgres();
|
|
38
|
+
}, 180_000);
|
|
39
|
+
|
|
40
|
+
afterAll(async () => {
|
|
41
|
+
await container?.stop();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('POST /setup over plaintext on a non-loopback origin', () => {
|
|
45
|
+
it('403s with insecure_transport, and does NOT create the instance', async () => {
|
|
46
|
+
const app = await bootWith(
|
|
47
|
+
{ PUBLIC_BASE_URL: 'http://platform.example.com', SETUP_TOKEN: 'the-setup-token' },
|
|
48
|
+
'plaintext_public'
|
|
49
|
+
);
|
|
50
|
+
try {
|
|
51
|
+
const res = await postSetup(app, {
|
|
52
|
+
owner,
|
|
53
|
+
instanceName: 'Acme',
|
|
54
|
+
setupToken: 'the-setup-token' // the CORRECT token — it must not help
|
|
55
|
+
});
|
|
56
|
+
expect(res.status).toBe(403);
|
|
57
|
+
expect(await res.json()).toMatchObject({ error: { code: 'insecure_transport' } });
|
|
58
|
+
|
|
59
|
+
// Still un-set-up: the wizard is genuinely still available over a safe
|
|
60
|
+
// transport, it was not consumed by the refused attempt.
|
|
61
|
+
const instance = await app.app.request('/api/v1/instance');
|
|
62
|
+
expect(((await instance.json()) as { setupRequired: boolean }).setupRequired).toBe(true);
|
|
63
|
+
} finally {
|
|
64
|
+
await app.stop();
|
|
65
|
+
}
|
|
66
|
+
}, 120_000);
|
|
67
|
+
|
|
68
|
+
it('is refused before the token check, so it cannot be probed for a valid token', async () => {
|
|
69
|
+
const app = await bootWith(
|
|
70
|
+
{ PUBLIC_BASE_URL: 'http://10.0.0.4:3000', SETUP_TOKEN: 'the-setup-token' },
|
|
71
|
+
'plaintext_private'
|
|
72
|
+
);
|
|
73
|
+
try {
|
|
74
|
+
const res = await postSetup(app, { owner, instanceName: 'Acme', setupToken: 'wrong' });
|
|
75
|
+
expect(res.status).toBe(403);
|
|
76
|
+
// A wrong token would give invalid_setup_token; the transport verdict
|
|
77
|
+
// must come first so the two cases are indistinguishable.
|
|
78
|
+
expect(await res.json()).toMatchObject({ error: { code: 'insecure_transport' } });
|
|
79
|
+
} finally {
|
|
80
|
+
await app.stop();
|
|
81
|
+
}
|
|
82
|
+
}, 120_000);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('POST /setup on a transport the operator can trust', () => {
|
|
86
|
+
it('succeeds over plaintext LOOPBACK — the `ssh -L` tunnel path', async () => {
|
|
87
|
+
const app = await bootWith({ PUBLIC_BASE_URL: 'http://127.0.0.1:3000' }, 'plaintext_loopback');
|
|
88
|
+
try {
|
|
89
|
+
const res = await postSetup(app, { owner, instanceName: 'Acme', setupToken: SETUP_TOKEN });
|
|
90
|
+
expect(res.status).toBe(201);
|
|
91
|
+
} finally {
|
|
92
|
+
await app.stop();
|
|
93
|
+
}
|
|
94
|
+
}, 120_000);
|
|
95
|
+
|
|
96
|
+
it('succeeds over https on a public origin', async () => {
|
|
97
|
+
const app = await bootWith({ PUBLIC_BASE_URL: 'https://platform.example.com' }, 'https_public');
|
|
98
|
+
try {
|
|
99
|
+
const res = await postSetup(app, { owner, instanceName: 'Acme', setupToken: SETUP_TOKEN });
|
|
100
|
+
expect(res.status).toBe(201);
|
|
101
|
+
} finally {
|
|
102
|
+
await app.stop();
|
|
103
|
+
}
|
|
104
|
+
}, 120_000);
|
|
105
|
+
|
|
106
|
+
it('succeeds over plaintext on a public origin ONLY with the explicit opt-in', async () => {
|
|
107
|
+
const app = await bootWith(
|
|
108
|
+
{ PUBLIC_BASE_URL: 'http://platform.example.com', ALLOW_INSECURE_SETUP: 'true' },
|
|
109
|
+
'plaintext_optin'
|
|
110
|
+
);
|
|
111
|
+
try {
|
|
112
|
+
const res = await postSetup(app, { owner, instanceName: 'Acme', setupToken: SETUP_TOKEN });
|
|
113
|
+
expect(res.status).toBe(201);
|
|
114
|
+
} finally {
|
|
115
|
+
await app.stop();
|
|
116
|
+
}
|
|
117
|
+
}, 120_000);
|
|
118
|
+
});
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
2
|
+
import type { StartedPostgreSqlContainer } from '@testcontainers/postgresql';
|
|
3
|
+
import { createDatabase, createTestApp, readJson, startPostgres, type TestApp } from './helpers.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* PRDCT-2830 / PRDCT-2848: the sign-in library's own wall (3 per 10 seconds
|
|
7
|
+
* per address on `/sign-in*`, on under NODE_ENV=production) answers 429 inside
|
|
8
|
+
* the `/auth/*` mount, and the chassis's failure-only login wall in front of
|
|
9
|
+
* it (10 per 15 minutes) counted every one of those 429s as a refused
|
|
10
|
+
* credential. A burst of ordinary sign-ins from one address (a room behind one
|
|
11
|
+
* public IP) then locked that address out for 15 minutes.
|
|
12
|
+
*
|
|
13
|
+
* Pinned here: a library 429 costs the chassis wall nothing; a wrong password
|
|
14
|
+
* still does; the federated start (`sign-in/oauth2`, no credential) is off the
|
|
15
|
+
* wall. The library's wall is off under NODE_ENV=test, so the suite switches
|
|
16
|
+
* it on in the live auth context, as production has it.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const OWNER = { email: 'owner@wall.test', name: 'Wall Owner', password: 'wall-owner-password-123' };
|
|
20
|
+
|
|
21
|
+
let container: StartedPostgreSqlContainer;
|
|
22
|
+
let app: TestApp;
|
|
23
|
+
type RateLimitCtx = { rateLimit: { enabled: boolean } };
|
|
24
|
+
let authCtx: RateLimitCtx;
|
|
25
|
+
|
|
26
|
+
const post = (path: string, ip: string, body: unknown) =>
|
|
27
|
+
app.app.request(`/api/v1/auth${path}`, {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: { 'content-type': 'application/json', 'x-forwarded-for': ip, origin: 'http://localhost:3000' },
|
|
30
|
+
body: JSON.stringify(body)
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/** The chassis's own wall answers `{ error: { code: 'rate_limited' } }`; the library's does not. */
|
|
34
|
+
async function isChassisWall(res: Response): Promise<boolean> {
|
|
35
|
+
if (res.status !== 429) return false;
|
|
36
|
+
const body = await readJson(res).catch(() => null);
|
|
37
|
+
return body?.error?.code === 'rate_limited';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
beforeAll(async () => {
|
|
41
|
+
container = await startPostgres();
|
|
42
|
+
app = await createTestApp(await createDatabase(container, 'signin_wall'));
|
|
43
|
+
const setup = await app.app.request('/api/v1/setup', {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers: { 'content-type': 'application/json' },
|
|
46
|
+
body: JSON.stringify({ setupToken: 'integration-test-setup-token', instanceName: 'Wall', owner: OWNER })
|
|
47
|
+
});
|
|
48
|
+
expect(setup.status).toBeLessThan(300);
|
|
49
|
+
authCtx = (await (app.auth as unknown as { $context: Promise<RateLimitCtx> }).$context) as RateLimitCtx;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
afterAll(async () => {
|
|
53
|
+
if (authCtx) authCtx.rateLimit.enabled = false;
|
|
54
|
+
await app?.stop();
|
|
55
|
+
await container?.stop();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('the login wall and the library wall behind it', () => {
|
|
59
|
+
it('a burst the library answers 429 does not lock the address out', async () => {
|
|
60
|
+
const ip = '198.51.100.10';
|
|
61
|
+
authCtx.rateLimit.enabled = true;
|
|
62
|
+
const statuses: number[] = [];
|
|
63
|
+
try {
|
|
64
|
+
for (let i = 0; i < 15; i++) {
|
|
65
|
+
const res = await post('/sign-in/email', ip, { email: OWNER.email, password: OWNER.password });
|
|
66
|
+
statuses.push(res.status);
|
|
67
|
+
expect(await isChassisWall(res)).toBe(false);
|
|
68
|
+
}
|
|
69
|
+
} finally {
|
|
70
|
+
// The library's 10-second window, elapsed.
|
|
71
|
+
authCtx.rateLimit.enabled = false;
|
|
72
|
+
}
|
|
73
|
+
// The library's wall did answer: 3 in, the rest 429 (more than the login wall's 10 points).
|
|
74
|
+
expect(statuses.filter((s) => s === 429).length).toBeGreaterThan(10);
|
|
75
|
+
// Once the library lets the address through again, the right password signs in.
|
|
76
|
+
const after = await post('/sign-in/email', ip, { email: OWNER.email, password: OWNER.password });
|
|
77
|
+
expect(after.status).toBe(200);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('a wrong password still costs: the eleventh from one address meets the 15-minute wall', async () => {
|
|
81
|
+
const ip = '198.51.100.20';
|
|
82
|
+
for (let i = 0; i < 10; i++) {
|
|
83
|
+
const res = await post('/sign-in/email', ip, {
|
|
84
|
+
email: `nobody-${i}@wall.test`,
|
|
85
|
+
password: 'wrong-password-1'
|
|
86
|
+
});
|
|
87
|
+
expect(res.status).toBe(401);
|
|
88
|
+
}
|
|
89
|
+
const eleventh = await post('/sign-in/email', ip, {
|
|
90
|
+
email: 'nobody-x@wall.test',
|
|
91
|
+
password: 'wrong-password-1'
|
|
92
|
+
});
|
|
93
|
+
expect(await isChassisWall(eleventh)).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('the federated start presents no credential and never meets the login wall', async () => {
|
|
97
|
+
const ip = '198.51.100.30';
|
|
98
|
+
for (let i = 0; i < 12; i++) {
|
|
99
|
+
const res = await post('/sign-in/oauth2', ip, { providerId: 'antasphere', callbackURL: '/' });
|
|
100
|
+
expect(await isChassisWall(res)).toBe(false);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
});
|