@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,451 @@
|
|
|
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
|
+
host,
|
|
8
|
+
readJson,
|
|
9
|
+
startPostgres,
|
|
10
|
+
type TestApp
|
|
11
|
+
} from './helpers.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Orphaned-user GC (ADR 010 + user-scoped federation): the nightly sweep
|
|
15
|
+
* deletes Better Auth users with ZERO workspace_members rows AND no live
|
|
16
|
+
* (unexpired) session once they are older than ORPHAN_USER_RETENTION_HOURS.
|
|
17
|
+
* The LIVE SESSION is the collect/protect discriminator — a hub account
|
|
18
|
+
* link deliberately is NOT (a fail-closed SSO login strands a linked,
|
|
19
|
+
* grant-bearing user whose session was revoked; protecting on the link
|
|
20
|
+
* would accumulate dormant refresh families without bound). Safety
|
|
21
|
+
* invariants under test: a user with ANY membership row — even DEACTIVATED
|
|
22
|
+
* — is never touched; neither is a fresh orphan inside the grace window, an
|
|
23
|
+
* orphan with a live pending invitation (mid-onboarding), a zero-membership
|
|
24
|
+
* user with a LIVE session (the legit /me zero state), nor a
|
|
25
|
+
* superadmin-allowlisted address (the break-glass operator). Deletion is
|
|
26
|
+
* always the WHOLE user (internalAdapter cascade: sessions + accounts +
|
|
27
|
+
* memberships together — the no_link hard constraint) and lands a
|
|
28
|
+
* system-actor `user.orphan_purge` audit row. 0 disables the sweep.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
const OWNER = { email: 'owner@gc.test', name: 'GC Owner', password: 'gc-owner-password-123' };
|
|
32
|
+
const MEMBER = { email: 'member@gc.test', name: 'GC Member', password: 'gc-member-password-12' };
|
|
33
|
+
const SUPERADMIN_EMAIL = 'breakglass@gc.test';
|
|
34
|
+
|
|
35
|
+
let container: StartedPostgreSqlContainer;
|
|
36
|
+
|
|
37
|
+
const json = (body: unknown, headers: Record<string, string> = {}) => ({
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: { 'content-type': 'application/json', ...headers },
|
|
40
|
+
body: JSON.stringify(body)
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Insert a raw user row (+ a session and credential account to prove the
|
|
45
|
+
* cascade). `sessionLive: false` seeds an EXPIRED session — the strand
|
|
46
|
+
* shape (a fail-closed login revokes; here expiry stands in for revocation
|
|
47
|
+
* while still proving the delete cascades session rows).
|
|
48
|
+
*/
|
|
49
|
+
async function seedUser(
|
|
50
|
+
app: TestApp,
|
|
51
|
+
id: string,
|
|
52
|
+
email: string,
|
|
53
|
+
ageHours: number,
|
|
54
|
+
opts: { sessionLive?: boolean; hubLinked?: boolean } = {}
|
|
55
|
+
): Promise<void> {
|
|
56
|
+
await app.db.pool.query(
|
|
57
|
+
`INSERT INTO "user" (id, name, email, email_verified, created_at, updated_at)
|
|
58
|
+
VALUES ($1, $2, $3, false, now() - make_interval(hours => $4), now())`,
|
|
59
|
+
[id, email, email, ageHours]
|
|
60
|
+
);
|
|
61
|
+
await app.db.pool.query(
|
|
62
|
+
`INSERT INTO session (id, expires_at, token, created_at, updated_at, user_id)
|
|
63
|
+
VALUES ($1, now() + $2::interval, $3, now(), now(), $4)`,
|
|
64
|
+
[`sess-${id}`, opts.sessionLive ? '7 days' : '-1 hour', `token-${id}`, id]
|
|
65
|
+
);
|
|
66
|
+
if (opts.hubLinked) {
|
|
67
|
+
// The fail-closed-login strand: an `antasphere` link HOLDING a stored
|
|
68
|
+
// offline grant (Better Auth writes tokens before the after-hook).
|
|
69
|
+
await app.db.pool.query(
|
|
70
|
+
`INSERT INTO account (id, account_id, provider_id, user_id, refresh_token, created_at, updated_at)
|
|
71
|
+
VALUES ($1, $2, 'antasphere', $3, 'stranded-grant-ciphertext', now(), now())`,
|
|
72
|
+
[`acc-${id}`, `hub-${id}`, id]
|
|
73
|
+
);
|
|
74
|
+
} else {
|
|
75
|
+
await app.db.pool.query(
|
|
76
|
+
`INSERT INTO account (id, account_id, provider_id, user_id, password, created_at, updated_at)
|
|
77
|
+
VALUES ($1, $2, 'credential', $3, 'hash', now(), now())`,
|
|
78
|
+
[`acc-${id}`, id, id]
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function userExists(app: TestApp, id: string): Promise<boolean> {
|
|
84
|
+
const res = await app.db.pool.query(`SELECT 1 FROM "user" WHERE id = $1`, [id]);
|
|
85
|
+
return res.rows.length > 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Send the purge job and wait for pg-boss to complete it (deterministic). */
|
|
89
|
+
async function runPurge(app: TestApp): Promise<void> {
|
|
90
|
+
const jobId = await app.jobs.boss.send('orphan-user-purge', {});
|
|
91
|
+
expect(jobId).toBeTruthy();
|
|
92
|
+
const deadline = Date.now() + 20_000;
|
|
93
|
+
for (;;) {
|
|
94
|
+
const job = await app.jobs.boss.getJobById('orphan-user-purge', jobId!);
|
|
95
|
+
if (job && (job.state === 'completed' || job.state === 'failed')) {
|
|
96
|
+
expect(job.state).toBe('completed');
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (Date.now() > deadline) throw new Error('orphan purge job did not complete in time');
|
|
100
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
beforeAll(async () => {
|
|
105
|
+
container = await startPostgres();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
afterAll(async () => {
|
|
109
|
+
await container?.stop();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('orphan purge (default 72h grace)', () => {
|
|
113
|
+
let app: TestApp;
|
|
114
|
+
|
|
115
|
+
beforeAll(async () => {
|
|
116
|
+
app = await createTestApp(await createDatabase(container, 'gc_on'), {
|
|
117
|
+
SUPERADMIN_EMAILS: SUPERADMIN_EMAIL
|
|
118
|
+
});
|
|
119
|
+
await app.app.request(
|
|
120
|
+
'/api/v1/setup',
|
|
121
|
+
json({ setupToken: 'integration-test-setup-token', instanceName: 'GC', owner: OWNER })
|
|
122
|
+
);
|
|
123
|
+
const ownerCookie = extractCookie(
|
|
124
|
+
await app.app.request(
|
|
125
|
+
'/api/v1/auth/sign-in/email',
|
|
126
|
+
json({ email: OWNER.email, password: OWNER.password })
|
|
127
|
+
)
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
// A real member — then DEACTIVATED and BACKDATED past the grace window:
|
|
131
|
+
// the strongest "never touch a member" case (inactive + old).
|
|
132
|
+
const inv = await readJson(
|
|
133
|
+
await app.app.request(
|
|
134
|
+
'/api/v1/invitations',
|
|
135
|
+
json({ email: MEMBER.email, role: 'member' }, { cookie: ownerCookie })
|
|
136
|
+
)
|
|
137
|
+
);
|
|
138
|
+
const token = (inv.acceptUrl as string).split('/invite/')[1]!;
|
|
139
|
+
await app.app.request(
|
|
140
|
+
'/api/v1/invitations/accept',
|
|
141
|
+
json({ token, name: MEMBER.name, password: MEMBER.password })
|
|
142
|
+
);
|
|
143
|
+
const { members } = await readJson(
|
|
144
|
+
await app.app.request('/api/v1/members', { headers: { cookie: ownerCookie } })
|
|
145
|
+
);
|
|
146
|
+
const member = members.find((m: { email: string }) => m.email === MEMBER.email);
|
|
147
|
+
await app.app.request(`/api/v1/members/${member.id}`, {
|
|
148
|
+
...json({ isActive: false }, { cookie: ownerCookie }),
|
|
149
|
+
method: 'PATCH'
|
|
150
|
+
});
|
|
151
|
+
await app.db.pool.query(`UPDATE "user" SET created_at = now() - interval '200 hours' WHERE email = $1`, [
|
|
152
|
+
MEMBER.email
|
|
153
|
+
]);
|
|
154
|
+
|
|
155
|
+
// The GC population:
|
|
156
|
+
await seedUser(app, 'orphan-old', 'orphan-old@gc.test', 100); // past grace, dead session → deleted
|
|
157
|
+
await seedUser(app, 'orphan-fresh', 'orphan-fresh@gc.test', 1); // inside grace → kept
|
|
158
|
+
await seedUser(app, 'orphan-invited', 'orphan-invited@gc.test', 100); // past grace but re-invited → kept
|
|
159
|
+
await app.app.request(
|
|
160
|
+
'/api/v1/invitations',
|
|
161
|
+
json({ email: 'orphan-invited@gc.test', role: 'member' }, { cookie: ownerCookie })
|
|
162
|
+
);
|
|
163
|
+
// The fail-closed-login STRAND: hub-linked, grant-bearing, session
|
|
164
|
+
// revoked (expired here) — the link must NOT protect it.
|
|
165
|
+
await seedUser(app, 'orphan-strand', 'orphan-strand@gc.test', 100, { hubLinked: true });
|
|
166
|
+
// The LEGIT zero-org user (the /me zero state): hub-linked too, but
|
|
167
|
+
// holding a LIVE session — the session is the protection.
|
|
168
|
+
await seedUser(app, 'zero-org-live', 'zero-org-live@gc.test', 100, {
|
|
169
|
+
hubLinked: true,
|
|
170
|
+
sessionLive: true
|
|
171
|
+
});
|
|
172
|
+
// Same protection for an UNLINKED zero-membership user with a live
|
|
173
|
+
// session (the discriminator is the session, never the link).
|
|
174
|
+
await seedUser(app, 'zero-org-live-local', 'zero-org-live-local@gc.test', 100, { sessionLive: true });
|
|
175
|
+
// The break-glass operator: allowlisted email, no membership, session
|
|
176
|
+
// long gone — must survive so recovery stays possible (ADR 010).
|
|
177
|
+
await seedUser(app, 'superadmin-dormant', SUPERADMIN_EMAIL, 100);
|
|
178
|
+
// BG-2 (PRDCT-1356): the allowlist shelters a VERIFIED address only —
|
|
179
|
+
// exactly what break-glass would accept. seedUser inserts unverified.
|
|
180
|
+
await app.db.pool.query(`UPDATE "user" SET email_verified = true WHERE id = 'superadmin-dormant'`);
|
|
181
|
+
}, 60_000);
|
|
182
|
+
|
|
183
|
+
afterAll(async () => {
|
|
184
|
+
await app.stop();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('deletes only the no-session zero-membership orphans and cascades sessions/accounts', async () => {
|
|
188
|
+
await runPurge(app);
|
|
189
|
+
|
|
190
|
+
// The old orphan is gone, cascade included.
|
|
191
|
+
expect(await userExists(app, 'orphan-old')).toBe(false);
|
|
192
|
+
const sess = await app.db.pool.query(`SELECT 1 FROM session WHERE user_id = 'orphan-old'`);
|
|
193
|
+
expect(sess.rows).toHaveLength(0);
|
|
194
|
+
const acc = await app.db.pool.query(`SELECT 1 FROM account WHERE user_id = 'orphan-old'`);
|
|
195
|
+
expect(acc.rows).toHaveLength(0);
|
|
196
|
+
|
|
197
|
+
// The fail-closed-login STRAND is collected — the hub link does NOT
|
|
198
|
+
// protect it, and its stored grant ciphertext dies with the account row
|
|
199
|
+
// (the whole point: no unbounded dormant-refresh-family accumulation).
|
|
200
|
+
expect(await userExists(app, 'orphan-strand')).toBe(false);
|
|
201
|
+
const strandAcc = await app.db.pool.query(`SELECT 1 FROM account WHERE user_id = 'orphan-strand'`);
|
|
202
|
+
expect(strandAcc.rows).toHaveLength(0);
|
|
203
|
+
|
|
204
|
+
// The LEGIT zero-org users survive: the LIVE SESSION is the
|
|
205
|
+
// discriminator, for linked and unlinked users alike.
|
|
206
|
+
expect(await userExists(app, 'zero-org-live')).toBe(true);
|
|
207
|
+
expect(await userExists(app, 'zero-org-live-local')).toBe(true);
|
|
208
|
+
|
|
209
|
+
// The dormant break-glass operator survives on the allowlist alone.
|
|
210
|
+
expect(await userExists(app, 'superadmin-dormant')).toBe(true);
|
|
211
|
+
|
|
212
|
+
// The fresh orphan survives the grace window.
|
|
213
|
+
expect(await userExists(app, 'orphan-fresh')).toBe(true);
|
|
214
|
+
|
|
215
|
+
// The re-invited orphan survives (live pending invitation = mid-onboarding).
|
|
216
|
+
expect(await userExists(app, 'orphan-invited')).toBe(true);
|
|
217
|
+
|
|
218
|
+
// THE invariant: a user with ANY membership row — even deactivated and
|
|
219
|
+
// far older than the grace period — is never a purge candidate.
|
|
220
|
+
const member = await app.db.pool.query(`SELECT 1 FROM "user" WHERE email = $1`, [MEMBER.email]);
|
|
221
|
+
expect(member.rows).toHaveLength(1);
|
|
222
|
+
const owner = await app.db.pool.query(`SELECT 1 FROM "user" WHERE email = $1`, [OWNER.email]);
|
|
223
|
+
expect(owner.rows).toHaveLength(1);
|
|
224
|
+
|
|
225
|
+
// ── The no_link HARD CONSTRAINT (user-scoped federation) ────────────
|
|
226
|
+
// The purge must never leave an `origin='hub'` membership row whose
|
|
227
|
+
// user lost their `antasphere` account row — that state would make the
|
|
228
|
+
// reconciler's fail-open no_link branch reachable for a hub-origin
|
|
229
|
+
// principal. The whole-user cascade makes it impossible; pin it.
|
|
230
|
+
const dangling = await app.db.pool.query(
|
|
231
|
+
`SELECT wm.id FROM workspace_members wm
|
|
232
|
+
WHERE wm.origin = 'hub'
|
|
233
|
+
AND NOT EXISTS (
|
|
234
|
+
SELECT 1 FROM account a WHERE a.user_id = wm.user_id AND a.provider_id = 'antasphere'
|
|
235
|
+
)`
|
|
236
|
+
);
|
|
237
|
+
expect(dangling.rows).toHaveLength(0);
|
|
238
|
+
|
|
239
|
+
// Audited as a system actor with the count — INSTANCE-attributed
|
|
240
|
+
// (workspace_id NULL, ADR 014): orphans belong to no workspace.
|
|
241
|
+
const audit = await app.db.pool.query(
|
|
242
|
+
`SELECT actor_via, actor_user_id, workspace_id, metadata FROM audit_log WHERE action = 'user.orphan_purge' ORDER BY id DESC LIMIT 1`
|
|
243
|
+
);
|
|
244
|
+
expect(audit.rows).toHaveLength(1);
|
|
245
|
+
expect(audit.rows[0].actor_via).toBe('system');
|
|
246
|
+
expect(audit.rows[0].actor_user_id).toBeNull();
|
|
247
|
+
expect(audit.rows[0].workspace_id).toBeNull();
|
|
248
|
+
expect(audit.rows[0].metadata.deleted).toBe(2);
|
|
249
|
+
expect(audit.rows[0].metadata.sample).toContain('orphan-old@gc.test');
|
|
250
|
+
expect(audit.rows[0].metadata.sample).toContain('orphan-strand@gc.test');
|
|
251
|
+
}, 40_000);
|
|
252
|
+
|
|
253
|
+
it('is idempotent: a second run finds nothing and writes no extra audit row', async () => {
|
|
254
|
+
const before = await app.db.pool.query(
|
|
255
|
+
`SELECT count(*)::int AS n FROM audit_log WHERE action = 'user.orphan_purge'`
|
|
256
|
+
);
|
|
257
|
+
await runPurge(app);
|
|
258
|
+
expect(await userExists(app, 'orphan-fresh')).toBe(true);
|
|
259
|
+
const after = await app.db.pool.query(
|
|
260
|
+
`SELECT count(*)::int AS n FROM audit_log WHERE action = 'user.orphan_purge'`
|
|
261
|
+
);
|
|
262
|
+
// No deletions → no audit row (the run itself only logs).
|
|
263
|
+
expect(after.rows[0].n).toBe(before.rows[0].n);
|
|
264
|
+
}, 40_000);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
describe('ORPHAN_USER_RETENTION_HOURS=0 disables the sweep', () => {
|
|
268
|
+
let app: TestApp;
|
|
269
|
+
|
|
270
|
+
beforeAll(async () => {
|
|
271
|
+
app = await createTestApp(await createDatabase(container, 'gc_off'), {
|
|
272
|
+
ORPHAN_USER_RETENTION_HOURS: '0'
|
|
273
|
+
});
|
|
274
|
+
await app.app.request(
|
|
275
|
+
'/api/v1/setup',
|
|
276
|
+
json({ setupToken: 'integration-test-setup-token', instanceName: 'GCOff', owner: OWNER })
|
|
277
|
+
);
|
|
278
|
+
await seedUser(app, 'orphan-ancient', 'orphan-ancient@gc.test', 1000);
|
|
279
|
+
}, 60_000);
|
|
280
|
+
|
|
281
|
+
afterAll(async () => {
|
|
282
|
+
await app.stop();
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('leaves even ancient orphans untouched', async () => {
|
|
286
|
+
await runPurge(app); // the handler early-returns; the job still completes
|
|
287
|
+
expect(await userExists(app, 'orphan-ancient')).toBe(true);
|
|
288
|
+
}, 40_000);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* The no_link HARD CONSTRAINT, at the mechanism level (user-scoped
|
|
293
|
+
* federation). The purge never deletes a user who HOLDS a membership — so
|
|
294
|
+
* the cascade the constraint leans on ("delete the WHOLE user … whose FK
|
|
295
|
+
* cascade removes account rows AND membership rows together") is, in every
|
|
296
|
+
* other suite, asserted but never exercised: all deleted users have zero
|
|
297
|
+
* memberships. This pins the actual DB-level guarantee that makes the
|
|
298
|
+
* constraint hold even under the scan→delete race — a hub-origin membership
|
|
299
|
+
* row can NEVER outlive its `antasphere` account row, because
|
|
300
|
+
* `internalAdapter.deleteUser` (the exact call the purge AND both GDPR
|
|
301
|
+
* delete surfaces make) removes the `user` row and Postgres cascades BOTH
|
|
302
|
+
* children in one shot. If this ever regressed — an ON DELETE that stops
|
|
303
|
+
* cascading, or a partial account-only cleanup swapped in — the reconciler's
|
|
304
|
+
* fail-open `no_link` branch would become reachable for a hub-origin
|
|
305
|
+
* principal (a live authorization hole), and only this test would catch it.
|
|
306
|
+
*/
|
|
307
|
+
describe('the deletion MECHANISM cascades a hub-origin membership with its account (no_link hard constraint)', () => {
|
|
308
|
+
let app: TestApp;
|
|
309
|
+
|
|
310
|
+
beforeAll(async () => {
|
|
311
|
+
app = await createTestApp(await createDatabase(container, 'gc_cascade'));
|
|
312
|
+
await app.app.request(
|
|
313
|
+
'/api/v1/setup',
|
|
314
|
+
json({ setupToken: 'integration-test-setup-token', instanceName: 'GCCascade', owner: OWNER })
|
|
315
|
+
);
|
|
316
|
+
}, 60_000);
|
|
317
|
+
|
|
318
|
+
afterAll(async () => {
|
|
319
|
+
await app.stop();
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('internalAdapter.deleteUser removes the antasphere account AND the origin=hub membership together', async () => {
|
|
323
|
+
const userId = 'cascade-hub-user';
|
|
324
|
+
const wsId = '33333333-cccc-4ddd-8eee-000000000001';
|
|
325
|
+
const hubOrgId = 'hub-org-cascade-0001';
|
|
326
|
+
|
|
327
|
+
// A PROJECTED workspace (central_account_id set) with an active
|
|
328
|
+
// origin='hub' membership whose user holds a live-grant `antasphere`
|
|
329
|
+
// account row — the exact shape a fail-closed-login strand or any
|
|
330
|
+
// hub-origin principal carries.
|
|
331
|
+
await app.db.pool.query(
|
|
332
|
+
`INSERT INTO workspaces (id, name, central_account_id, hub_status, created_at)
|
|
333
|
+
VALUES ($1, 'Cascade Org', $2, 'active', now())`,
|
|
334
|
+
[wsId, hubOrgId]
|
|
335
|
+
);
|
|
336
|
+
await app.db.pool.query(
|
|
337
|
+
`INSERT INTO "user" (id, name, email, email_verified, created_at, updated_at)
|
|
338
|
+
VALUES ($1, 'Cascade User', 'cascade@gc.test', true, now(), now())`,
|
|
339
|
+
[userId]
|
|
340
|
+
);
|
|
341
|
+
await app.db.pool.query(
|
|
342
|
+
`INSERT INTO account (id, account_id, provider_id, user_id, refresh_token, created_at, updated_at)
|
|
343
|
+
VALUES ('acc-cascade', 'hub-cascade', 'antasphere', $1, 'live-grant-ciphertext', now(), now())`,
|
|
344
|
+
[userId]
|
|
345
|
+
);
|
|
346
|
+
await app.db.pool.query(
|
|
347
|
+
`INSERT INTO workspace_members (id, workspace_id, user_id, role, origin, is_active, created_at)
|
|
348
|
+
VALUES (gen_random_uuid(), $1, $2, 'member', 'hub', true, now())`,
|
|
349
|
+
[wsId, userId]
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
// Sanity: the pre-delete state is exactly the one the constraint protects.
|
|
353
|
+
const before = await app.db.pool.query(
|
|
354
|
+
`SELECT 1 FROM workspace_members WHERE user_id = $1 AND origin = 'hub' AND is_active = true`,
|
|
355
|
+
[userId]
|
|
356
|
+
);
|
|
357
|
+
expect(before.rows).toHaveLength(1);
|
|
358
|
+
|
|
359
|
+
// The mechanism under test — the exact deletion call jobs/pgboss.ts makes.
|
|
360
|
+
const ctx = await app.auth.$context;
|
|
361
|
+
await ctx.internalAdapter.deleteUser(userId);
|
|
362
|
+
|
|
363
|
+
// The whole user is gone…
|
|
364
|
+
expect(await userExists(app, userId)).toBe(false);
|
|
365
|
+
// …its antasphere account row is gone…
|
|
366
|
+
const acc = await app.db.pool.query(
|
|
367
|
+
`SELECT 1 FROM account WHERE user_id = $1 AND provider_id = 'antasphere'`,
|
|
368
|
+
[userId]
|
|
369
|
+
);
|
|
370
|
+
expect(acc.rows).toHaveLength(0);
|
|
371
|
+
// …and — the load-bearing assertion — its origin='hub' membership
|
|
372
|
+
// cascaded WITH the account, never outliving it.
|
|
373
|
+
const mem = await app.db.pool.query(`SELECT 1 FROM workspace_members WHERE user_id = $1`, [userId]);
|
|
374
|
+
expect(mem.rows).toHaveLength(0);
|
|
375
|
+
|
|
376
|
+
// The fail-open state is unreachable: no origin='hub' row lacks its
|
|
377
|
+
// antasphere account anywhere in the instance.
|
|
378
|
+
const dangling = await app.db.pool.query(
|
|
379
|
+
`SELECT wm.id FROM workspace_members wm
|
|
380
|
+
WHERE wm.origin = 'hub'
|
|
381
|
+
AND NOT EXISTS (
|
|
382
|
+
SELECT 1 FROM account a WHERE a.user_id = wm.user_id AND a.provider_id = 'antasphere'
|
|
383
|
+
)`
|
|
384
|
+
);
|
|
385
|
+
expect(dangling.rows).toHaveLength(0);
|
|
386
|
+
|
|
387
|
+
// The projected workspace itself survives (only the membership cascaded) —
|
|
388
|
+
// the delete is scoped to the user, not the org.
|
|
389
|
+
const ws = await app.db.pool.query(`SELECT 1 FROM workspaces WHERE id = $1`, [wsId]);
|
|
390
|
+
expect(ws.rows).toHaveLength(1);
|
|
391
|
+
}, 40_000);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
describe('the setup operator is never an orphan (CLOUD-3), and the allowlist shelters VERIFIED addresses only (BG-2)', () => {
|
|
395
|
+
let app: TestApp;
|
|
396
|
+
let operatorId: string;
|
|
397
|
+
|
|
398
|
+
beforeAll(async () => {
|
|
399
|
+
// The CLOUD shape, for real: cloud setup mints NO membership, so the
|
|
400
|
+
// operator is exactly the zero-membership user the sweep collects.
|
|
401
|
+
// SUPERADMIN_EMAILS UNSET: the operator's survival must not depend on it.
|
|
402
|
+
app = await createTestApp(await createDatabase(container, 'gc_operator'), {
|
|
403
|
+
EDITION: 'cloud',
|
|
404
|
+
HUB_ISSUER_URL: 'http://hub.localhost:3300',
|
|
405
|
+
HUB_CLIENT_ID: host.hubClientId,
|
|
406
|
+
HUB_CLIENT_SECRET: 'integration-test-hub-secret-0001',
|
|
407
|
+
SUPERADMIN_EMAILS: '',
|
|
408
|
+
ORPHAN_USER_RETENTION_HOURS: '1'
|
|
409
|
+
});
|
|
410
|
+
const setup = await app.app.request(
|
|
411
|
+
'/api/v1/setup',
|
|
412
|
+
json({ setupToken: 'integration-test-setup-token', instanceName: 'GC Op', owner: OWNER })
|
|
413
|
+
);
|
|
414
|
+
expect(setup.status).toBe(201);
|
|
415
|
+
operatorId = (await readJson(setup)).ownerUserId;
|
|
416
|
+
const memberships = await app.db.pool.query(`SELECT 1 FROM workspace_members WHERE user_id = $1`, [
|
|
417
|
+
operatorId
|
|
418
|
+
]);
|
|
419
|
+
expect(memberships.rows).toHaveLength(0);
|
|
420
|
+
// Their session has lapsed; age the row past the grace.
|
|
421
|
+
await app.db.pool.query(`DELETE FROM session WHERE user_id = $1`, [operatorId]);
|
|
422
|
+
await app.db.pool.query(`UPDATE "user" SET created_at = now() - interval '400 hours' WHERE id = $1`, [
|
|
423
|
+
operatorId
|
|
424
|
+
]);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
afterAll(async () => {
|
|
428
|
+
await app.stop();
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it('the purge deletes a plain stale orphan but keeps the operator', async () => {
|
|
432
|
+
await seedUser(app, 'u-stale', 'stale@gc.test', 400);
|
|
433
|
+
await runPurge(app);
|
|
434
|
+
expect(await userExists(app, 'u-stale')).toBe(false);
|
|
435
|
+
expect(await userExists(app, operatorId)).toBe(true);
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
it('an UNVERIFIED allowlisted address gets no shelter (BG-2 — break-glass would not accept it either)', async () => {
|
|
439
|
+
await app.stop();
|
|
440
|
+
app = await createTestApp(await createDatabase(container, 'gc_bg2'), {
|
|
441
|
+
SUPERADMIN_EMAILS: 'squat@gc.test, real@gc.test',
|
|
442
|
+
ORPHAN_USER_RETENTION_HOURS: '1'
|
|
443
|
+
});
|
|
444
|
+
await seedUser(app, 'u-squat', 'squat@gc.test', 400); // email_verified = false
|
|
445
|
+
await seedUser(app, 'u-real', 'real@gc.test', 400);
|
|
446
|
+
await app.db.pool.query(`UPDATE "user" SET email_verified = true WHERE id = 'u-real'`);
|
|
447
|
+
await runPurge(app);
|
|
448
|
+
expect(await userExists(app, 'u-squat')).toBe(false);
|
|
449
|
+
expect(await userExists(app, 'u-real')).toBe(true);
|
|
450
|
+
});
|
|
451
|
+
});
|