@fuzdev/fuz_app 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/actions/action_bridge.d.ts +65 -0
- package/dist/actions/action_bridge.d.ts.map +1 -0
- package/dist/actions/action_bridge.js +76 -0
- package/dist/actions/action_codegen.d.ts +97 -0
- package/dist/actions/action_codegen.d.ts.map +1 -0
- package/dist/actions/action_codegen.js +280 -0
- package/dist/actions/action_registry.d.ts +35 -0
- package/dist/actions/action_registry.d.ts.map +1 -0
- package/dist/actions/action_registry.js +83 -0
- package/dist/actions/action_spec.d.ts +169 -0
- package/dist/actions/action_spec.d.ts.map +1 -0
- package/dist/actions/action_spec.js +76 -0
- package/dist/auth/account_queries.d.ts +96 -0
- package/dist/auth/account_queries.d.ts.map +1 -0
- package/dist/auth/account_queries.js +172 -0
- package/dist/auth/account_routes.d.ts +86 -0
- package/dist/auth/account_routes.d.ts.map +1 -0
- package/dist/auth/account_routes.js +406 -0
- package/dist/auth/account_schema.d.ts +192 -0
- package/dist/auth/account_schema.d.ts.map +1 -0
- package/dist/auth/account_schema.js +105 -0
- package/dist/auth/admin_routes.d.ts +29 -0
- package/dist/auth/admin_routes.d.ts.map +1 -0
- package/dist/auth/admin_routes.js +193 -0
- package/dist/auth/api_token.d.ts +33 -0
- package/dist/auth/api_token.d.ts.map +1 -0
- package/dist/auth/api_token.js +36 -0
- package/dist/auth/api_token_queries.d.ts +80 -0
- package/dist/auth/api_token_queries.d.ts.map +1 -0
- package/dist/auth/api_token_queries.js +116 -0
- package/dist/auth/app_settings_queries.d.ts +33 -0
- package/dist/auth/app_settings_queries.d.ts.map +1 -0
- package/dist/auth/app_settings_queries.js +51 -0
- package/dist/auth/app_settings_routes.d.ts +27 -0
- package/dist/auth/app_settings_routes.d.ts.map +1 -0
- package/dist/auth/app_settings_routes.js +66 -0
- package/dist/auth/app_settings_schema.d.ts +35 -0
- package/dist/auth/app_settings_schema.d.ts.map +1 -0
- package/dist/auth/app_settings_schema.js +22 -0
- package/dist/auth/audit_log_queries.d.ts +90 -0
- package/dist/auth/audit_log_queries.d.ts.map +1 -0
- package/dist/auth/audit_log_queries.js +205 -0
- package/dist/auth/audit_log_routes.d.ts +33 -0
- package/dist/auth/audit_log_routes.d.ts.map +1 -0
- package/dist/auth/audit_log_routes.js +106 -0
- package/dist/auth/audit_log_schema.d.ts +259 -0
- package/dist/auth/audit_log_schema.d.ts.map +1 -0
- package/dist/auth/audit_log_schema.js +123 -0
- package/dist/auth/bearer_auth.d.ts +32 -0
- package/dist/auth/bearer_auth.d.ts.map +1 -0
- package/dist/auth/bearer_auth.js +90 -0
- package/dist/auth/bootstrap_account.d.ts +82 -0
- package/dist/auth/bootstrap_account.d.ts.map +1 -0
- package/dist/auth/bootstrap_account.js +97 -0
- package/dist/auth/bootstrap_routes.d.ts +74 -0
- package/dist/auth/bootstrap_routes.d.ts.map +1 -0
- package/dist/auth/bootstrap_routes.js +154 -0
- package/dist/auth/daemon_token.d.ts +49 -0
- package/dist/auth/daemon_token.d.ts.map +1 -0
- package/dist/auth/daemon_token.js +49 -0
- package/dist/auth/daemon_token_middleware.d.ts +93 -0
- package/dist/auth/daemon_token_middleware.d.ts.map +1 -0
- package/dist/auth/daemon_token_middleware.js +167 -0
- package/dist/auth/ddl.d.ts +27 -0
- package/dist/auth/ddl.d.ts.map +1 -0
- package/dist/auth/ddl.js +111 -0
- package/dist/auth/deps.d.ts +52 -0
- package/dist/auth/deps.d.ts.map +1 -0
- package/dist/auth/deps.js +10 -0
- package/dist/auth/invite_queries.d.ts +68 -0
- package/dist/auth/invite_queries.d.ts.map +1 -0
- package/dist/auth/invite_queries.js +105 -0
- package/dist/auth/invite_routes.d.ts +18 -0
- package/dist/auth/invite_routes.d.ts.map +1 -0
- package/dist/auth/invite_routes.js +129 -0
- package/dist/auth/invite_schema.d.ts +51 -0
- package/dist/auth/invite_schema.d.ts.map +1 -0
- package/dist/auth/invite_schema.js +25 -0
- package/dist/auth/keyring.d.ts +87 -0
- package/dist/auth/keyring.d.ts.map +1 -0
- package/dist/auth/keyring.js +142 -0
- package/dist/auth/middleware.d.ts +40 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +64 -0
- package/dist/auth/migrations.d.ts +42 -0
- package/dist/auth/migrations.d.ts.map +1 -0
- package/dist/auth/migrations.js +79 -0
- package/dist/auth/password.d.ts +39 -0
- package/dist/auth/password.d.ts.map +1 -0
- package/dist/auth/password.js +25 -0
- package/dist/auth/password_argon2.d.ts +43 -0
- package/dist/auth/password_argon2.d.ts.map +1 -0
- package/dist/auth/password_argon2.js +76 -0
- package/dist/auth/permit_queries.d.ts +72 -0
- package/dist/auth/permit_queries.d.ts.map +1 -0
- package/dist/auth/permit_queries.js +116 -0
- package/dist/auth/request_context.d.ts +114 -0
- package/dist/auth/request_context.d.ts.map +1 -0
- package/dist/auth/request_context.js +176 -0
- package/dist/auth/require_keeper.d.ts +20 -0
- package/dist/auth/require_keeper.d.ts.map +1 -0
- package/dist/auth/require_keeper.js +35 -0
- package/dist/auth/role_schema.d.ts +69 -0
- package/dist/auth/role_schema.d.ts.map +1 -0
- package/dist/auth/role_schema.js +70 -0
- package/dist/auth/route_guards.d.ts +21 -0
- package/dist/auth/route_guards.d.ts.map +1 -0
- package/dist/auth/route_guards.js +32 -0
- package/dist/auth/session_cookie.d.ts +158 -0
- package/dist/auth/session_cookie.d.ts.map +1 -0
- package/dist/auth/session_cookie.js +135 -0
- package/dist/auth/session_lifecycle.d.ts +35 -0
- package/dist/auth/session_lifecycle.d.ts.map +1 -0
- package/dist/auth/session_lifecycle.js +27 -0
- package/dist/auth/session_middleware.d.ts +33 -0
- package/dist/auth/session_middleware.d.ts.map +1 -0
- package/dist/auth/session_middleware.js +62 -0
- package/dist/auth/session_queries.d.ts +135 -0
- package/dist/auth/session_queries.d.ts.map +1 -0
- package/dist/auth/session_queries.js +186 -0
- package/dist/auth/signup_routes.d.ts +32 -0
- package/dist/auth/signup_routes.d.ts.map +1 -0
- package/dist/auth/signup_routes.js +150 -0
- package/dist/cli/args.d.ts +48 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +76 -0
- package/dist/cli/config.d.ts +48 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +77 -0
- package/dist/cli/daemon.d.ts +82 -0
- package/dist/cli/daemon.d.ts.map +1 -0
- package/dist/cli/daemon.js +149 -0
- package/dist/cli/help.d.ts +85 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +138 -0
- package/dist/cli/logger.d.ts +46 -0
- package/dist/cli/logger.d.ts.map +1 -0
- package/dist/cli/logger.js +48 -0
- package/dist/cli/util.d.ts +36 -0
- package/dist/cli/util.d.ts.map +1 -0
- package/dist/cli/util.js +50 -0
- package/dist/crypto.d.ts +13 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +19 -0
- package/dist/db/assert_row.d.ts +18 -0
- package/dist/db/assert_row.d.ts.map +1 -0
- package/dist/db/assert_row.js +24 -0
- package/dist/db/create_db.d.ts +38 -0
- package/dist/db/create_db.d.ts.map +1 -0
- package/dist/db/create_db.js +57 -0
- package/dist/db/db.d.ts +97 -0
- package/dist/db/db.d.ts.map +1 -0
- package/dist/db/db.js +76 -0
- package/dist/db/db_pg.d.ts +21 -0
- package/dist/db/db_pg.d.ts.map +1 -0
- package/dist/db/db_pg.js +45 -0
- package/dist/db/db_pglite.d.ts +21 -0
- package/dist/db/db_pglite.d.ts.map +1 -0
- package/dist/db/db_pglite.js +28 -0
- package/dist/db/migrate.d.ts +67 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +118 -0
- package/dist/db/pg_error.d.ts +16 -0
- package/dist/db/pg_error.d.ts.map +1 -0
- package/dist/db/pg_error.js +15 -0
- package/dist/db/query_deps.d.ts +14 -0
- package/dist/db/query_deps.d.ts.map +1 -0
- package/dist/db/query_deps.js +9 -0
- package/dist/db/sql_identifier.d.ts +27 -0
- package/dist/db/sql_identifier.d.ts.map +1 -0
- package/dist/db/sql_identifier.js +31 -0
- package/dist/db/status.d.ts +62 -0
- package/dist/db/status.d.ts.map +1 -0
- package/dist/db/status.js +116 -0
- package/dist/dev/setup.d.ts +159 -0
- package/dist/dev/setup.d.ts.map +1 -0
- package/dist/dev/setup.js +265 -0
- package/dist/env/dotenv.d.ts +25 -0
- package/dist/env/dotenv.d.ts.map +1 -0
- package/dist/env/dotenv.js +52 -0
- package/dist/env/load.d.ts +52 -0
- package/dist/env/load.d.ts.map +1 -0
- package/dist/env/load.js +79 -0
- package/dist/env/mask.d.ts +19 -0
- package/dist/env/mask.d.ts.map +1 -0
- package/dist/env/mask.js +26 -0
- package/dist/env/resolve.d.ts +126 -0
- package/dist/env/resolve.d.ts.map +1 -0
- package/dist/env/resolve.js +200 -0
- package/dist/hono_context.d.ts +48 -0
- package/dist/hono_context.d.ts.map +1 -0
- package/dist/hono_context.js +22 -0
- package/dist/http/common_routes.d.ts +52 -0
- package/dist/http/common_routes.d.ts.map +1 -0
- package/dist/http/common_routes.js +65 -0
- package/dist/http/db_routes.d.ts +57 -0
- package/dist/http/db_routes.d.ts.map +1 -0
- package/dist/http/db_routes.js +176 -0
- package/dist/http/error_schemas.d.ts +169 -0
- package/dist/http/error_schemas.d.ts.map +1 -0
- package/dist/http/error_schemas.js +178 -0
- package/dist/http/middleware_spec.d.ts +19 -0
- package/dist/http/middleware_spec.d.ts.map +1 -0
- package/dist/http/middleware_spec.js +9 -0
- package/dist/http/origin.d.ts +57 -0
- package/dist/http/origin.d.ts.map +1 -0
- package/dist/http/origin.js +207 -0
- package/dist/http/proxy.d.ts +112 -0
- package/dist/http/proxy.d.ts.map +1 -0
- package/dist/http/proxy.js +240 -0
- package/dist/http/route_spec.d.ts +197 -0
- package/dist/http/route_spec.d.ts.map +1 -0
- package/dist/http/route_spec.js +243 -0
- package/dist/http/schema_helpers.d.ts +64 -0
- package/dist/http/schema_helpers.d.ts.map +1 -0
- package/dist/http/schema_helpers.js +90 -0
- package/dist/http/surface.d.ts +132 -0
- package/dist/http/surface.d.ts.map +1 -0
- package/dist/http/surface.js +156 -0
- package/dist/http/surface_query.d.ts +77 -0
- package/dist/http/surface_query.d.ts.map +1 -0
- package/dist/http/surface_query.js +86 -0
- package/dist/rate_limiter.d.ts +94 -0
- package/dist/rate_limiter.d.ts.map +1 -0
- package/dist/rate_limiter.js +156 -0
- package/dist/realtime/sse.d.ts +80 -0
- package/dist/realtime/sse.d.ts.map +1 -0
- package/dist/realtime/sse.js +109 -0
- package/dist/realtime/sse_auth_guard.d.ts +93 -0
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -0
- package/dist/realtime/sse_auth_guard.js +111 -0
- package/dist/realtime/subscriber_registry.d.ts +85 -0
- package/dist/realtime/subscriber_registry.d.ts.map +1 -0
- package/dist/realtime/subscriber_registry.js +108 -0
- package/dist/runtime/deno.d.ts +21 -0
- package/dist/runtime/deno.d.ts.map +1 -0
- package/dist/runtime/deno.js +83 -0
- package/dist/runtime/deps.d.ts +113 -0
- package/dist/runtime/deps.d.ts.map +1 -0
- package/dist/runtime/deps.js +10 -0
- package/dist/runtime/fs.d.ts +15 -0
- package/dist/runtime/fs.d.ts.map +1 -0
- package/dist/runtime/fs.js +17 -0
- package/dist/runtime/mock.d.ts +81 -0
- package/dist/runtime/mock.d.ts.map +1 -0
- package/dist/runtime/mock.js +195 -0
- package/dist/runtime/node.d.ts +17 -0
- package/dist/runtime/node.d.ts.map +1 -0
- package/dist/runtime/node.js +117 -0
- package/dist/schema_meta.d.ts +16 -0
- package/dist/schema_meta.d.ts.map +1 -0
- package/dist/schema_meta.js +9 -0
- package/dist/sensitivity.d.ts +15 -0
- package/dist/sensitivity.d.ts.map +1 -0
- package/dist/sensitivity.js +9 -0
- package/dist/server/app_backend.d.ts +74 -0
- package/dist/server/app_backend.d.ts.map +1 -0
- package/dist/server/app_backend.js +39 -0
- package/dist/server/app_server.d.ts +201 -0
- package/dist/server/app_server.d.ts.map +1 -0
- package/dist/server/app_server.js +266 -0
- package/dist/server/env.d.ts +68 -0
- package/dist/server/env.d.ts.map +1 -0
- package/dist/server/env.js +95 -0
- package/dist/server/startup.d.ts +22 -0
- package/dist/server/startup.d.ts.map +1 -0
- package/dist/server/startup.js +48 -0
- package/dist/server/static.d.ts +39 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +38 -0
- package/dist/server/validate_nginx.d.ts +34 -0
- package/dist/server/validate_nginx.d.ts.map +1 -0
- package/dist/server/validate_nginx.js +118 -0
- package/dist/testing/CLAUDE.md +3 -0
- package/dist/testing/admin_integration.d.ts +45 -0
- package/dist/testing/admin_integration.d.ts.map +1 -0
- package/dist/testing/admin_integration.js +840 -0
- package/dist/testing/adversarial_404.d.ts +15 -0
- package/dist/testing/adversarial_404.d.ts.map +1 -0
- package/dist/testing/adversarial_404.js +118 -0
- package/dist/testing/adversarial_headers.d.ts +36 -0
- package/dist/testing/adversarial_headers.d.ts.map +1 -0
- package/dist/testing/adversarial_headers.js +128 -0
- package/dist/testing/adversarial_input.d.ts +56 -0
- package/dist/testing/adversarial_input.d.ts.map +1 -0
- package/dist/testing/adversarial_input.js +494 -0
- package/dist/testing/app_server.d.ts +169 -0
- package/dist/testing/app_server.d.ts.map +1 -0
- package/dist/testing/app_server.js +240 -0
- package/dist/testing/assert_dev_env.d.ts +10 -0
- package/dist/testing/assert_dev_env.d.ts.map +1 -0
- package/dist/testing/assert_dev_env.js +13 -0
- package/dist/testing/assertions.d.ts +61 -0
- package/dist/testing/assertions.d.ts.map +1 -0
- package/dist/testing/assertions.js +96 -0
- package/dist/testing/attack_surface.d.ts +63 -0
- package/dist/testing/attack_surface.d.ts.map +1 -0
- package/dist/testing/attack_surface.js +224 -0
- package/dist/testing/audit_completeness.d.ts +29 -0
- package/dist/testing/audit_completeness.d.ts.map +1 -0
- package/dist/testing/audit_completeness.js +410 -0
- package/dist/testing/auth_apps.d.ts +55 -0
- package/dist/testing/auth_apps.d.ts.map +1 -0
- package/dist/testing/auth_apps.js +122 -0
- package/dist/testing/data_exposure.d.ts +62 -0
- package/dist/testing/data_exposure.d.ts.map +1 -0
- package/dist/testing/data_exposure.js +297 -0
- package/dist/testing/db.d.ts +111 -0
- package/dist/testing/db.d.ts.map +1 -0
- package/dist/testing/db.js +258 -0
- package/dist/testing/entities.d.ts +21 -0
- package/dist/testing/entities.d.ts.map +1 -0
- package/dist/testing/entities.js +42 -0
- package/dist/testing/error_coverage.d.ts +78 -0
- package/dist/testing/error_coverage.d.ts.map +1 -0
- package/dist/testing/error_coverage.js +135 -0
- package/dist/testing/integration.d.ts +37 -0
- package/dist/testing/integration.d.ts.map +1 -0
- package/dist/testing/integration.js +1139 -0
- package/dist/testing/integration_helpers.d.ts +107 -0
- package/dist/testing/integration_helpers.d.ts.map +1 -0
- package/dist/testing/integration_helpers.js +246 -0
- package/dist/testing/middleware.d.ts +125 -0
- package/dist/testing/middleware.d.ts.map +1 -0
- package/dist/testing/middleware.js +210 -0
- package/dist/testing/rate_limiting.d.ts +43 -0
- package/dist/testing/rate_limiting.d.ts.map +1 -0
- package/dist/testing/rate_limiting.js +216 -0
- package/dist/testing/round_trip.d.ts +37 -0
- package/dist/testing/round_trip.d.ts.map +1 -0
- package/dist/testing/round_trip.js +128 -0
- package/dist/testing/schema_generators.d.ts +33 -0
- package/dist/testing/schema_generators.d.ts.map +1 -0
- package/dist/testing/schema_generators.js +137 -0
- package/dist/testing/standard.d.ts +49 -0
- package/dist/testing/standard.d.ts.map +1 -0
- package/dist/testing/standard.js +16 -0
- package/dist/testing/stubs.d.ts +96 -0
- package/dist/testing/stubs.d.ts.map +1 -0
- package/dist/testing/stubs.js +192 -0
- package/dist/testing/surface_invariants.d.ts +189 -0
- package/dist/testing/surface_invariants.d.ts.map +1 -0
- package/dist/testing/surface_invariants.js +450 -0
- package/dist/ui/AccountSessions.svelte +75 -0
- package/dist/ui/AccountSessions.svelte.d.ts +19 -0
- package/dist/ui/AccountSessions.svelte.d.ts.map +1 -0
- package/dist/ui/AdminAccounts.svelte +107 -0
- package/dist/ui/AdminAccounts.svelte.d.ts +19 -0
- package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -0
- package/dist/ui/AdminAuditLog.svelte +144 -0
- package/dist/ui/AdminAuditLog.svelte.d.ts +4 -0
- package/dist/ui/AdminAuditLog.svelte.d.ts.map +1 -0
- package/dist/ui/AdminInvites.svelte +142 -0
- package/dist/ui/AdminInvites.svelte.d.ts +4 -0
- package/dist/ui/AdminInvites.svelte.d.ts.map +1 -0
- package/dist/ui/AdminOverview.svelte +337 -0
- package/dist/ui/AdminOverview.svelte.d.ts +4 -0
- package/dist/ui/AdminOverview.svelte.d.ts.map +1 -0
- package/dist/ui/AdminPermitHistory.svelte +61 -0
- package/dist/ui/AdminPermitHistory.svelte.d.ts +19 -0
- package/dist/ui/AdminPermitHistory.svelte.d.ts.map +1 -0
- package/dist/ui/AdminSessions.svelte +85 -0
- package/dist/ui/AdminSessions.svelte.d.ts +19 -0
- package/dist/ui/AdminSessions.svelte.d.ts.map +1 -0
- package/dist/ui/AdminSettings.svelte +32 -0
- package/dist/ui/AdminSettings.svelte.d.ts +19 -0
- package/dist/ui/AdminSettings.svelte.d.ts.map +1 -0
- package/dist/ui/AdminSurface.svelte +42 -0
- package/dist/ui/AdminSurface.svelte.d.ts +4 -0
- package/dist/ui/AdminSurface.svelte.d.ts.map +1 -0
- package/dist/ui/AppShell.svelte +93 -0
- package/dist/ui/AppShell.svelte.d.ts +20 -0
- package/dist/ui/AppShell.svelte.d.ts.map +1 -0
- package/dist/ui/BootstrapForm.svelte +105 -0
- package/dist/ui/BootstrapForm.svelte.d.ts +4 -0
- package/dist/ui/BootstrapForm.svelte.d.ts.map +1 -0
- package/dist/ui/ColumnLayout.svelte +46 -0
- package/dist/ui/ColumnLayout.svelte.d.ts +11 -0
- package/dist/ui/ColumnLayout.svelte.d.ts.map +1 -0
- package/dist/ui/ConfirmButton.svelte +125 -0
- package/dist/ui/ConfirmButton.svelte.d.ts +54 -0
- package/dist/ui/ConfirmButton.svelte.d.ts.map +1 -0
- package/dist/ui/Datatable.svelte +185 -0
- package/dist/ui/Datatable.svelte.d.ts +35 -0
- package/dist/ui/Datatable.svelte.d.ts.map +1 -0
- package/dist/ui/LoginForm.svelte +82 -0
- package/dist/ui/LoginForm.svelte.d.ts +8 -0
- package/dist/ui/LoginForm.svelte.d.ts.map +1 -0
- package/dist/ui/LogoutButton.svelte +36 -0
- package/dist/ui/LogoutButton.svelte.d.ts +10 -0
- package/dist/ui/LogoutButton.svelte.d.ts.map +1 -0
- package/dist/ui/MenuLink.svelte +35 -0
- package/dist/ui/MenuLink.svelte.d.ts +12 -0
- package/dist/ui/MenuLink.svelte.d.ts.map +1 -0
- package/dist/ui/OpenSignupToggle.svelte +36 -0
- package/dist/ui/OpenSignupToggle.svelte.d.ts +19 -0
- package/dist/ui/OpenSignupToggle.svelte.d.ts.map +1 -0
- package/dist/ui/PopoverButton.svelte +136 -0
- package/dist/ui/PopoverButton.svelte.d.ts +63 -0
- package/dist/ui/PopoverButton.svelte.d.ts.map +1 -0
- package/dist/ui/SignupForm.svelte +117 -0
- package/dist/ui/SignupForm.svelte.d.ts +7 -0
- package/dist/ui/SignupForm.svelte.d.ts.map +1 -0
- package/dist/ui/SurfaceExplorer.svelte +287 -0
- package/dist/ui/SurfaceExplorer.svelte.d.ts +8 -0
- package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -0
- package/dist/ui/account_sessions_state.svelte.d.ts +15 -0
- package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -0
- package/dist/ui/account_sessions_state.svelte.js +45 -0
- package/dist/ui/admin_accounts_state.svelte.d.ts +19 -0
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -0
- package/dist/ui/admin_accounts_state.svelte.js +65 -0
- package/dist/ui/admin_invites_state.svelte.d.ts +19 -0
- package/dist/ui/admin_invites_state.svelte.d.ts.map +1 -0
- package/dist/ui/admin_invites_state.svelte.js +71 -0
- package/dist/ui/admin_sessions_state.svelte.d.ts +18 -0
- package/dist/ui/admin_sessions_state.svelte.d.ts.map +1 -0
- package/dist/ui/admin_sessions_state.svelte.js +62 -0
- package/dist/ui/app_settings_state.svelte.d.ts +14 -0
- package/dist/ui/app_settings_state.svelte.d.ts.map +1 -0
- package/dist/ui/app_settings_state.svelte.js +44 -0
- package/dist/ui/audit_log_state.svelte.d.ts +40 -0
- package/dist/ui/audit_log_state.svelte.d.ts.map +1 -0
- package/dist/ui/audit_log_state.svelte.js +153 -0
- package/dist/ui/auth_state.svelte.d.ts +85 -0
- package/dist/ui/auth_state.svelte.d.ts.map +1 -0
- package/dist/ui/auth_state.svelte.js +238 -0
- package/dist/ui/datatable.d.ts +25 -0
- package/dist/ui/datatable.d.ts.map +1 -0
- package/dist/ui/datatable.js +9 -0
- package/dist/ui/enter_advance.d.ts +13 -0
- package/dist/ui/enter_advance.d.ts.map +1 -0
- package/dist/ui/enter_advance.js +30 -0
- package/dist/ui/loadable.svelte.d.ts +55 -0
- package/dist/ui/loadable.svelte.d.ts.map +1 -0
- package/dist/ui/loadable.svelte.js +75 -0
- package/dist/ui/popover.svelte.d.ts +137 -0
- package/dist/ui/popover.svelte.d.ts.map +1 -0
- package/dist/ui/popover.svelte.js +288 -0
- package/dist/ui/position_helpers.d.ts +27 -0
- package/dist/ui/position_helpers.d.ts.map +1 -0
- package/dist/ui/position_helpers.js +81 -0
- package/dist/ui/sidebar_state.svelte.d.ts +30 -0
- package/dist/ui/sidebar_state.svelte.d.ts.map +1 -0
- package/dist/ui/sidebar_state.svelte.js +39 -0
- package/dist/ui/table_state.svelte.d.ts +63 -0
- package/dist/ui/table_state.svelte.d.ts.map +1 -0
- package/dist/ui/table_state.svelte.js +117 -0
- package/dist/ui/ui_fetch.d.ts +29 -0
- package/dist/ui/ui_fetch.d.ts.map +1 -0
- package/dist/ui/ui_fetch.js +37 -0
- package/dist/ui/ui_format.d.ts +63 -0
- package/dist/ui/ui_format.d.ts.map +1 -0
- package/dist/ui/ui_format.js +196 -0
- package/package.json +121 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import './assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* Composable audit log completeness test suite.
|
|
4
|
+
*
|
|
5
|
+
* Verifies that every auth mutation route produces the expected audit log
|
|
6
|
+
* event. Uses the real middleware stack and database — audit events are
|
|
7
|
+
* verified by querying the `audit_log` table after each request.
|
|
8
|
+
*
|
|
9
|
+
* Bootstrap is excluded because it requires filesystem token state that
|
|
10
|
+
* `create_test_app` does not provide. Bootstrap audit logging is tested
|
|
11
|
+
* separately in `bootstrap_account.db.test.ts`.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { describe, test, assert } from 'vitest';
|
|
16
|
+
import { ROLE_KEEPER, ROLE_ADMIN } from '../auth/role_schema.js';
|
|
17
|
+
import { AUDIT_EVENT_TYPES } from '../auth/audit_log_schema.js';
|
|
18
|
+
import { AUTH_MIGRATION_NS } from '../auth/migrations.js';
|
|
19
|
+
import { create_test_app } from './app_server.js';
|
|
20
|
+
import { create_pglite_factory, create_describe_db, AUTH_INTEGRATION_TRUNCATE_TABLES, } from './db.js';
|
|
21
|
+
import { find_auth_route } from './integration_helpers.js';
|
|
22
|
+
import { run_migrations } from '../db/migrate.js';
|
|
23
|
+
/** Find an admin route by suffix and method. */
|
|
24
|
+
const find_admin_route = (specs, suffix, method) => specs.find((s) => s.method === method &&
|
|
25
|
+
s.path.endsWith(suffix) &&
|
|
26
|
+
s.auth.type === 'role' &&
|
|
27
|
+
s.auth.role === 'admin');
|
|
28
|
+
/** Query audit log events from the database. */
|
|
29
|
+
const query_audit_events = async (db) => {
|
|
30
|
+
return db.query('SELECT event_type, seq FROM audit_log ORDER BY seq');
|
|
31
|
+
};
|
|
32
|
+
/** Assert that audit events contain the expected event type. */
|
|
33
|
+
const assert_has_event = (events, expected, context) => {
|
|
34
|
+
assert.ok(events.some((e) => e.event_type === expected), `Expected '${expected}' audit event after ${context}`);
|
|
35
|
+
};
|
|
36
|
+
/** Build CreateTestAppOptions with admin+keeper roles. */
|
|
37
|
+
const build_options = (options, db) => ({
|
|
38
|
+
session_options: options.session_options,
|
|
39
|
+
create_route_specs: options.create_route_specs,
|
|
40
|
+
db,
|
|
41
|
+
roles: [ROLE_KEEPER, ROLE_ADMIN],
|
|
42
|
+
app_options: options.app_options,
|
|
43
|
+
});
|
|
44
|
+
/** Headers for unauthenticated JSON requests (login, signup). */
|
|
45
|
+
const UNAUTHENTICATED_JSON_HEADERS = {
|
|
46
|
+
host: 'localhost',
|
|
47
|
+
origin: 'http://localhost:5173',
|
|
48
|
+
'content-type': 'application/json',
|
|
49
|
+
};
|
|
50
|
+
/** Standard request headers for session-authenticated JSON requests. */
|
|
51
|
+
const json_session_headers = (test_app, extra) => test_app.create_session_headers({
|
|
52
|
+
'content-type': 'application/json',
|
|
53
|
+
...extra,
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* Find an account-scoped parameterized route (e.g. `/tokens/:id/revoke`).
|
|
57
|
+
*
|
|
58
|
+
* Matches routes with a `:id` or `:param` segment that are NOT admin role-gated.
|
|
59
|
+
*/
|
|
60
|
+
const find_account_parameterized_route = (specs, segment, suffix, method) => specs.find((s) => s.method === method &&
|
|
61
|
+
s.path.includes(`/${segment}/`) &&
|
|
62
|
+
s.path.endsWith(suffix) &&
|
|
63
|
+
s.auth.type !== 'role');
|
|
64
|
+
/**
|
|
65
|
+
* Composable audit log completeness test suite.
|
|
66
|
+
*
|
|
67
|
+
* Verifies that every auth mutation route produces the correct audit log
|
|
68
|
+
* event type. Exercises routes via HTTP requests against a real PGlite
|
|
69
|
+
* database, then queries the `audit_log` table to verify events.
|
|
70
|
+
*
|
|
71
|
+
* @param options - session config, route factory, and optional overrides
|
|
72
|
+
*/
|
|
73
|
+
export const describe_audit_completeness_tests = (options) => {
|
|
74
|
+
const init_schema = async (db) => {
|
|
75
|
+
await run_migrations(db, [AUTH_MIGRATION_NS]);
|
|
76
|
+
};
|
|
77
|
+
const factories = options.db_factories ?? [create_pglite_factory(init_schema)];
|
|
78
|
+
const describe_db = create_describe_db(factories, AUTH_INTEGRATION_TRUNCATE_TABLES);
|
|
79
|
+
describe_db('audit_log_completeness', (get_db) => {
|
|
80
|
+
// --- Account routes ---
|
|
81
|
+
describe('account mutation audit events', () => {
|
|
82
|
+
test('login success produces login event', async () => {
|
|
83
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
84
|
+
const login_route = find_auth_route(test_app.route_specs, '/login', 'POST');
|
|
85
|
+
assert.ok(login_route, 'Expected POST /login route');
|
|
86
|
+
const res = await test_app.app.request(login_route.path, {
|
|
87
|
+
method: 'POST',
|
|
88
|
+
headers: UNAUTHENTICATED_JSON_HEADERS,
|
|
89
|
+
body: JSON.stringify({
|
|
90
|
+
username: test_app.backend.account.username,
|
|
91
|
+
password: 'test-password-123',
|
|
92
|
+
}),
|
|
93
|
+
});
|
|
94
|
+
assert.strictEqual(res.status, 200);
|
|
95
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
96
|
+
assert_has_event(events, 'login', 'POST /login (success)');
|
|
97
|
+
});
|
|
98
|
+
test('login failure produces login event with failure outcome', async () => {
|
|
99
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
100
|
+
const login_route = find_auth_route(test_app.route_specs, '/login', 'POST');
|
|
101
|
+
assert.ok(login_route, 'Expected POST /login route');
|
|
102
|
+
const res = await test_app.app.request(login_route.path, {
|
|
103
|
+
method: 'POST',
|
|
104
|
+
headers: UNAUTHENTICATED_JSON_HEADERS,
|
|
105
|
+
body: JSON.stringify({
|
|
106
|
+
username: test_app.backend.account.username,
|
|
107
|
+
password: 'wrong-password',
|
|
108
|
+
}),
|
|
109
|
+
});
|
|
110
|
+
assert.strictEqual(res.status, 401);
|
|
111
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
112
|
+
assert_has_event(events, 'login', 'POST /login (failure)');
|
|
113
|
+
});
|
|
114
|
+
test('logout produces logout event', async () => {
|
|
115
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
116
|
+
const logout_route = find_auth_route(test_app.route_specs, '/logout', 'POST');
|
|
117
|
+
assert.ok(logout_route, 'Expected POST /logout route');
|
|
118
|
+
const res = await test_app.app.request(logout_route.path, {
|
|
119
|
+
method: 'POST',
|
|
120
|
+
headers: test_app.create_session_headers(),
|
|
121
|
+
});
|
|
122
|
+
assert.strictEqual(res.status, 200);
|
|
123
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
124
|
+
assert_has_event(events, 'logout', 'POST /logout');
|
|
125
|
+
});
|
|
126
|
+
test('token create produces token_create event', async () => {
|
|
127
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
128
|
+
const route = find_auth_route(test_app.route_specs, '/tokens/create', 'POST');
|
|
129
|
+
assert.ok(route, 'Expected POST /tokens/create route');
|
|
130
|
+
const res = await test_app.app.request(route.path, {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
headers: json_session_headers(test_app),
|
|
133
|
+
body: JSON.stringify({ name: 'audit-test' }),
|
|
134
|
+
});
|
|
135
|
+
assert.strictEqual(res.status, 200);
|
|
136
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
137
|
+
assert_has_event(events, 'token_create', 'POST /tokens/create');
|
|
138
|
+
});
|
|
139
|
+
test('token revoke produces token_revoke event', async () => {
|
|
140
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
141
|
+
// get a token ID to revoke
|
|
142
|
+
const tokens_route = find_auth_route(test_app.route_specs, '/tokens', 'GET');
|
|
143
|
+
assert.ok(tokens_route, 'Expected GET /tokens route');
|
|
144
|
+
const list_res = await test_app.app.request(tokens_route.path, {
|
|
145
|
+
headers: test_app.create_session_headers(),
|
|
146
|
+
});
|
|
147
|
+
const { tokens } = (await list_res.json());
|
|
148
|
+
assert.ok(tokens.length > 0, 'Expected at least one token');
|
|
149
|
+
const route = find_account_parameterized_route(test_app.route_specs, 'tokens', '/revoke', 'POST');
|
|
150
|
+
assert.ok(route, 'Expected POST /tokens/:id/revoke route');
|
|
151
|
+
const path = route.path.replace(':id', tokens[0].id);
|
|
152
|
+
const res = await test_app.app.request(path, {
|
|
153
|
+
method: 'POST',
|
|
154
|
+
headers: test_app.create_session_headers(),
|
|
155
|
+
});
|
|
156
|
+
assert.strictEqual(res.status, 200);
|
|
157
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
158
|
+
assert_has_event(events, 'token_revoke', 'POST /tokens/:id/revoke');
|
|
159
|
+
});
|
|
160
|
+
test('session revoke produces session_revoke event', async () => {
|
|
161
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
162
|
+
// login to create a second session we can revoke
|
|
163
|
+
const login_route = find_auth_route(test_app.route_specs, '/login', 'POST');
|
|
164
|
+
assert.ok(login_route, 'Expected POST /login route');
|
|
165
|
+
await test_app.app.request(login_route.path, {
|
|
166
|
+
method: 'POST',
|
|
167
|
+
headers: UNAUTHENTICATED_JSON_HEADERS,
|
|
168
|
+
body: JSON.stringify({
|
|
169
|
+
username: test_app.backend.account.username,
|
|
170
|
+
password: 'test-password-123',
|
|
171
|
+
}),
|
|
172
|
+
});
|
|
173
|
+
// get session IDs (newest first)
|
|
174
|
+
const sessions_route = find_auth_route(test_app.route_specs, '/sessions', 'GET');
|
|
175
|
+
assert.ok(sessions_route, 'Expected GET /sessions route');
|
|
176
|
+
const list_res = await test_app.app.request(sessions_route.path, {
|
|
177
|
+
headers: test_app.create_session_headers(),
|
|
178
|
+
});
|
|
179
|
+
const { sessions } = (await list_res.json());
|
|
180
|
+
assert.ok(sessions.length >= 2, 'Expected at least 2 sessions');
|
|
181
|
+
const route = find_account_parameterized_route(test_app.route_specs, 'sessions', '/revoke', 'POST');
|
|
182
|
+
assert.ok(route, 'Expected POST /sessions/:id/revoke route');
|
|
183
|
+
// revoke the second session (not the one used for auth)
|
|
184
|
+
const path = route.path.replace(':id', sessions[1].id);
|
|
185
|
+
const res = await test_app.app.request(path, {
|
|
186
|
+
method: 'POST',
|
|
187
|
+
headers: test_app.create_session_headers(),
|
|
188
|
+
});
|
|
189
|
+
assert.strictEqual(res.status, 200);
|
|
190
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
191
|
+
assert_has_event(events, 'session_revoke', 'POST /sessions/:id/revoke');
|
|
192
|
+
});
|
|
193
|
+
test('session revoke-all produces session_revoke_all event', async () => {
|
|
194
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
195
|
+
const route = find_auth_route(test_app.route_specs, '/sessions/revoke-all', 'POST');
|
|
196
|
+
assert.ok(route, 'Expected POST /sessions/revoke-all route');
|
|
197
|
+
const res = await test_app.app.request(route.path, {
|
|
198
|
+
method: 'POST',
|
|
199
|
+
headers: test_app.create_session_headers(),
|
|
200
|
+
});
|
|
201
|
+
assert.strictEqual(res.status, 200);
|
|
202
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
203
|
+
assert_has_event(events, 'session_revoke_all', 'POST /sessions/revoke-all');
|
|
204
|
+
});
|
|
205
|
+
test('password change produces password_change event', async () => {
|
|
206
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
207
|
+
const route = find_auth_route(test_app.route_specs, '/password', 'POST');
|
|
208
|
+
assert.ok(route, 'Expected POST /password route');
|
|
209
|
+
const res = await test_app.app.request(route.path, {
|
|
210
|
+
method: 'POST',
|
|
211
|
+
headers: json_session_headers(test_app),
|
|
212
|
+
body: JSON.stringify({
|
|
213
|
+
current_password: 'test-password-123',
|
|
214
|
+
new_password: 'new-password-456',
|
|
215
|
+
}),
|
|
216
|
+
});
|
|
217
|
+
assert.strictEqual(res.status, 200);
|
|
218
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
219
|
+
assert_has_event(events, 'password_change', 'POST /password');
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
// --- Admin routes ---
|
|
223
|
+
describe('admin mutation audit events', () => {
|
|
224
|
+
test('permit grant produces permit_grant event', async () => {
|
|
225
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
226
|
+
const route = find_admin_route(test_app.route_specs, '/permits/grant', 'POST');
|
|
227
|
+
assert.ok(route, 'Expected admin POST /permits/grant route');
|
|
228
|
+
const target = await test_app.create_account({ username: 'audit_target' });
|
|
229
|
+
const path = route.path.replace(':account_id', target.account.id);
|
|
230
|
+
const res = await test_app.app.request(path, {
|
|
231
|
+
method: 'POST',
|
|
232
|
+
headers: json_session_headers(test_app),
|
|
233
|
+
body: JSON.stringify({ role: ROLE_ADMIN }),
|
|
234
|
+
});
|
|
235
|
+
assert.strictEqual(res.status, 200);
|
|
236
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
237
|
+
assert_has_event(events, 'permit_grant', 'POST /permits/grant');
|
|
238
|
+
});
|
|
239
|
+
test('permit revoke produces permit_revoke event', async () => {
|
|
240
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
241
|
+
const grant_route = find_admin_route(test_app.route_specs, '/permits/grant', 'POST');
|
|
242
|
+
const revoke_route = test_app.route_specs.find((s) => s.method === 'POST' &&
|
|
243
|
+
s.path.includes('/permits/') &&
|
|
244
|
+
s.path.endsWith('/revoke') &&
|
|
245
|
+
s.auth.type === 'role');
|
|
246
|
+
assert.ok(grant_route, 'Expected admin POST /permits/grant route');
|
|
247
|
+
assert.ok(revoke_route, 'Expected admin POST /permits/:permit_id/revoke route');
|
|
248
|
+
const target = await test_app.create_account({ username: 'audit_revoke_target' });
|
|
249
|
+
// grant a permit first
|
|
250
|
+
const grant_path = grant_route.path.replace(':account_id', target.account.id);
|
|
251
|
+
const grant_res = await test_app.app.request(grant_path, {
|
|
252
|
+
method: 'POST',
|
|
253
|
+
headers: json_session_headers(test_app),
|
|
254
|
+
body: JSON.stringify({ role: ROLE_ADMIN }),
|
|
255
|
+
});
|
|
256
|
+
const grant_body = (await grant_res.json());
|
|
257
|
+
// revoke it
|
|
258
|
+
const revoke_path = revoke_route.path
|
|
259
|
+
.replace(':account_id', target.account.id)
|
|
260
|
+
.replace(':permit_id', grant_body.permit.id);
|
|
261
|
+
const res = await test_app.app.request(revoke_path, {
|
|
262
|
+
method: 'POST',
|
|
263
|
+
headers: test_app.create_session_headers(),
|
|
264
|
+
});
|
|
265
|
+
assert.strictEqual(res.status, 200);
|
|
266
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
267
|
+
assert_has_event(events, 'permit_revoke', 'POST /permits/:permit_id/revoke');
|
|
268
|
+
});
|
|
269
|
+
test('admin session revoke-all produces session_revoke_all event', async () => {
|
|
270
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
271
|
+
const route = find_admin_route(test_app.route_specs, '/sessions/revoke-all', 'POST');
|
|
272
|
+
assert.ok(route, 'Expected admin POST /sessions/revoke-all route');
|
|
273
|
+
const target = await test_app.create_account({ username: 'audit_sessions_target' });
|
|
274
|
+
const path = route.path.replace(':account_id', target.account.id);
|
|
275
|
+
const res = await test_app.app.request(path, {
|
|
276
|
+
method: 'POST',
|
|
277
|
+
headers: test_app.create_session_headers(),
|
|
278
|
+
});
|
|
279
|
+
assert.strictEqual(res.status, 200);
|
|
280
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
281
|
+
// admin session revoke-all also produces session_revoke_all
|
|
282
|
+
assert_has_event(events, 'session_revoke_all', 'admin POST /sessions/revoke-all');
|
|
283
|
+
});
|
|
284
|
+
test('admin token revoke-all produces token_revoke_all event', async () => {
|
|
285
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
286
|
+
const route = find_admin_route(test_app.route_specs, '/tokens/revoke-all', 'POST');
|
|
287
|
+
assert.ok(route, 'Expected admin POST /tokens/revoke-all route');
|
|
288
|
+
const target = await test_app.create_account({ username: 'audit_tokens_target' });
|
|
289
|
+
const path = route.path.replace(':account_id', target.account.id);
|
|
290
|
+
const res = await test_app.app.request(path, {
|
|
291
|
+
method: 'POST',
|
|
292
|
+
headers: test_app.create_session_headers(),
|
|
293
|
+
});
|
|
294
|
+
assert.strictEqual(res.status, 200);
|
|
295
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
296
|
+
assert_has_event(events, 'token_revoke_all', 'admin POST /tokens/revoke-all');
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
// --- Invite routes ---
|
|
300
|
+
describe('invite mutation audit events', () => {
|
|
301
|
+
test('invite create and delete produce audit events', async () => {
|
|
302
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
303
|
+
const create_route = find_admin_route(test_app.route_specs, '/invites', 'POST');
|
|
304
|
+
const delete_route = test_app.route_specs.find((s) => s.method === 'DELETE' && s.path.includes('/invites/') && s.auth.type === 'role');
|
|
305
|
+
assert.ok(create_route, 'Expected admin POST /invites route');
|
|
306
|
+
assert.ok(delete_route, 'Expected admin DELETE /invites/:id route');
|
|
307
|
+
// create invite
|
|
308
|
+
const create_res = await test_app.app.request(create_route.path, {
|
|
309
|
+
method: 'POST',
|
|
310
|
+
headers: json_session_headers(test_app),
|
|
311
|
+
body: JSON.stringify({ username: 'invited_user' }),
|
|
312
|
+
});
|
|
313
|
+
assert.strictEqual(create_res.status, 200);
|
|
314
|
+
const { invite } = (await create_res.json());
|
|
315
|
+
// delete invite
|
|
316
|
+
const delete_path = delete_route.path.replace(':id', invite.id);
|
|
317
|
+
const delete_res = await test_app.app.request(delete_path, {
|
|
318
|
+
method: 'DELETE',
|
|
319
|
+
headers: test_app.create_session_headers(),
|
|
320
|
+
});
|
|
321
|
+
assert.strictEqual(delete_res.status, 200);
|
|
322
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
323
|
+
assert_has_event(events, 'invite_create', 'POST /invites');
|
|
324
|
+
assert_has_event(events, 'invite_delete', 'DELETE /invites/:id');
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
// --- App settings routes ---
|
|
328
|
+
describe('app settings mutation audit events', () => {
|
|
329
|
+
test('settings update produces app_settings_update event', async () => {
|
|
330
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
331
|
+
const route = find_admin_route(test_app.route_specs, '/settings', 'PATCH');
|
|
332
|
+
assert.ok(route, 'Expected admin PATCH /settings route');
|
|
333
|
+
const res = await test_app.app.request(route.path, {
|
|
334
|
+
method: 'PATCH',
|
|
335
|
+
headers: json_session_headers(test_app),
|
|
336
|
+
body: JSON.stringify({ open_signup: true }),
|
|
337
|
+
});
|
|
338
|
+
assert.strictEqual(res.status, 200);
|
|
339
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
340
|
+
assert_has_event(events, 'app_settings_update', 'PATCH /settings');
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
// --- Signup route ---
|
|
344
|
+
describe('signup audit events', () => {
|
|
345
|
+
test('signup produces signup event', async () => {
|
|
346
|
+
const test_app = await create_test_app(build_options(options, get_db()));
|
|
347
|
+
// enable open signup
|
|
348
|
+
const settings_route = find_admin_route(test_app.route_specs, '/settings', 'PATCH');
|
|
349
|
+
assert.ok(settings_route, 'Expected admin PATCH /settings route');
|
|
350
|
+
await test_app.app.request(settings_route.path, {
|
|
351
|
+
method: 'PATCH',
|
|
352
|
+
headers: json_session_headers(test_app),
|
|
353
|
+
body: JSON.stringify({ open_signup: true }),
|
|
354
|
+
});
|
|
355
|
+
// signup
|
|
356
|
+
const signup_route = find_auth_route(test_app.route_specs, '/signup', 'POST');
|
|
357
|
+
assert.ok(signup_route, 'Expected POST /signup route');
|
|
358
|
+
const res = await test_app.app.request(signup_route.path, {
|
|
359
|
+
method: 'POST',
|
|
360
|
+
headers: UNAUTHENTICATED_JSON_HEADERS,
|
|
361
|
+
body: JSON.stringify({
|
|
362
|
+
username: 'signup_user',
|
|
363
|
+
password: 'signup-password-123',
|
|
364
|
+
}),
|
|
365
|
+
});
|
|
366
|
+
assert.strictEqual(res.status, 200);
|
|
367
|
+
const events = await query_audit_events(test_app.backend.deps.db);
|
|
368
|
+
assert_has_event(events, 'signup', 'POST /signup');
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
// --- Completeness check ---
|
|
372
|
+
describe('completeness', () => {
|
|
373
|
+
/**
|
|
374
|
+
* Event types covered by this suite. Bootstrap is excluded because
|
|
375
|
+
* it requires filesystem token state not provided by create_test_app.
|
|
376
|
+
*/
|
|
377
|
+
const COVERED_EVENT_TYPES = new Set([
|
|
378
|
+
'login',
|
|
379
|
+
'logout',
|
|
380
|
+
'signup',
|
|
381
|
+
'password_change',
|
|
382
|
+
'session_revoke',
|
|
383
|
+
'session_revoke_all',
|
|
384
|
+
'token_create',
|
|
385
|
+
'token_revoke',
|
|
386
|
+
'token_revoke_all',
|
|
387
|
+
'permit_grant',
|
|
388
|
+
'permit_revoke',
|
|
389
|
+
'invite_create',
|
|
390
|
+
'invite_delete',
|
|
391
|
+
'app_settings_update',
|
|
392
|
+
]);
|
|
393
|
+
/** Event types excluded with justification. */
|
|
394
|
+
const EXCLUDED_EVENT_TYPES = new Set([
|
|
395
|
+
'bootstrap', // requires filesystem token — tested in bootstrap_account.db.test.ts
|
|
396
|
+
]);
|
|
397
|
+
test('all audit event types are covered or explicitly excluded', () => {
|
|
398
|
+
const all_covered = new Set([...COVERED_EVENT_TYPES, ...EXCLUDED_EVENT_TYPES]);
|
|
399
|
+
for (const event_type of AUDIT_EVENT_TYPES) {
|
|
400
|
+
assert.ok(all_covered.has(event_type), `Audit event type '${event_type}' is not covered by the completeness suite and not explicitly excluded — add a test or exclude with justification`);
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
test('no excluded event types are also covered', () => {
|
|
404
|
+
for (const event_type of EXCLUDED_EVENT_TYPES) {
|
|
405
|
+
assert.ok(!COVERED_EVENT_TYPES.has(event_type), `Event type '${event_type}' is in both COVERED and EXCLUDED — remove from one`);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import './assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* Auth test app factories for adversarial testing.
|
|
4
|
+
*
|
|
5
|
+
* Creates Hono test apps at each auth level (public, authenticated, keeper,
|
|
6
|
+
* per-role) for use in adversarial auth enforcement and input validation tests.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { Hono } from 'hono';
|
|
11
|
+
import { type RouteSpec, type RouteAuth } from '../http/route_spec.js';
|
|
12
|
+
import { type RequestContext } from '../auth/request_context.js';
|
|
13
|
+
import { type CredentialType } from '../hono_context.js';
|
|
14
|
+
/**
|
|
15
|
+
* Create a mock request context with optional role permit.
|
|
16
|
+
*
|
|
17
|
+
* @param role - optional role to grant
|
|
18
|
+
* @returns a valid `RequestContext`
|
|
19
|
+
*/
|
|
20
|
+
export declare const create_test_request_context: (role?: string) => RequestContext;
|
|
21
|
+
/**
|
|
22
|
+
* Create a Hono test app from route specs with optional auth context.
|
|
23
|
+
*
|
|
24
|
+
* @param route_specs - the route specs to register
|
|
25
|
+
* @param auth_ctx - optional request context to inject via middleware
|
|
26
|
+
* @param credential_type - optional credential type (default: `'session'` when auth_ctx provided)
|
|
27
|
+
* @returns a configured Hono app
|
|
28
|
+
*/
|
|
29
|
+
export declare const create_test_app_from_specs: (route_specs: Array<RouteSpec>, auth_ctx?: RequestContext, credential_type?: CredentialType) => Hono;
|
|
30
|
+
/** Pre-built Hono apps for each auth level, shared across adversarial test suites. */
|
|
31
|
+
export interface AuthTestApps {
|
|
32
|
+
public: Hono;
|
|
33
|
+
authed: Hono;
|
|
34
|
+
keeper: Hono;
|
|
35
|
+
by_role: Map<string, Hono>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create one Hono test app per auth level.
|
|
39
|
+
*
|
|
40
|
+
* @param route_specs - the route specs to register
|
|
41
|
+
* @param roles - all roles in the app
|
|
42
|
+
* @returns apps keyed by auth level
|
|
43
|
+
*/
|
|
44
|
+
export declare const create_auth_test_apps: (route_specs: Array<RouteSpec>, roles: Array<string>) => AuthTestApps;
|
|
45
|
+
/**
|
|
46
|
+
* Select the Hono test app with correct auth for a route.
|
|
47
|
+
*
|
|
48
|
+
* @param apps - the pre-built auth test apps
|
|
49
|
+
* @param auth - the route's auth options
|
|
50
|
+
* @returns the correctly-authenticated Hono app
|
|
51
|
+
*/
|
|
52
|
+
export declare const select_auth_app: (apps: AuthTestApps, auth: RouteAuth) => Hono;
|
|
53
|
+
/** Replace Hono route params (`:foo`) with dummy values for HTTP testing. */
|
|
54
|
+
export declare const resolve_test_path: (path: string) => string;
|
|
55
|
+
//# sourceMappingURL=auth_apps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth_apps.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/auth_apps.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;GAOG;AAEH,OAAO,EAAC,IAAI,EAAC,MAAM,MAAM,CAAC;AAG1B,OAAO,EAAoB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAExF,OAAO,EAAsB,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AACpF,OAAO,EAAsB,KAAK,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAG5E;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,GAAI,OAAO,MAAM,KAAG,cAkC1D,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,GACtC,aAAa,KAAK,CAAC,SAAS,CAAC,EAC7B,WAAW,cAAc,EACzB,kBAAkB,cAAc,KAC9B,IAkBF,CAAC;AAEF,sFAAsF;AACtF,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;IACb,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GACjC,aAAa,KAAK,CAAC,SAAS,CAAC,EAC7B,OAAO,KAAK,CAAC,MAAM,CAAC,KAClB,YAeF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,YAAY,EAAE,MAAM,SAAS,KAAG,IAcrE,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,MAA4C,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import './assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* Auth test app factories for adversarial testing.
|
|
4
|
+
*
|
|
5
|
+
* Creates Hono test apps at each auth level (public, authenticated, keeper,
|
|
6
|
+
* per-role) for use in adversarial auth enforcement and input validation tests.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { Hono } from 'hono';
|
|
11
|
+
import { Logger } from '@fuzdev/fuz_util/log.js';
|
|
12
|
+
import { apply_route_specs } from '../http/route_spec.js';
|
|
13
|
+
import { fuz_auth_guard_resolver } from '../auth/route_guards.js';
|
|
14
|
+
import { REQUEST_CONTEXT_KEY } from '../auth/request_context.js';
|
|
15
|
+
import { CREDENTIAL_TYPE_KEY } from '../hono_context.js';
|
|
16
|
+
import { create_stub_db } from './stubs.js';
|
|
17
|
+
/**
|
|
18
|
+
* Create a mock request context with optional role permit.
|
|
19
|
+
*
|
|
20
|
+
* @param role - optional role to grant
|
|
21
|
+
* @returns a valid `RequestContext`
|
|
22
|
+
*/
|
|
23
|
+
export const create_test_request_context = (role) => ({
|
|
24
|
+
account: {
|
|
25
|
+
id: 'acc_1',
|
|
26
|
+
username: 'testuser',
|
|
27
|
+
password_hash: 'hash',
|
|
28
|
+
created_at: new Date().toISOString(),
|
|
29
|
+
updated_at: new Date().toISOString(),
|
|
30
|
+
created_by: null,
|
|
31
|
+
updated_by: null,
|
|
32
|
+
email: null,
|
|
33
|
+
email_verified: false,
|
|
34
|
+
},
|
|
35
|
+
actor: {
|
|
36
|
+
id: 'act_1',
|
|
37
|
+
account_id: 'acc_1',
|
|
38
|
+
name: 'testuser',
|
|
39
|
+
created_at: new Date().toISOString(),
|
|
40
|
+
updated_at: null,
|
|
41
|
+
updated_by: null,
|
|
42
|
+
},
|
|
43
|
+
permits: role
|
|
44
|
+
? [
|
|
45
|
+
{
|
|
46
|
+
id: 'perm_1',
|
|
47
|
+
actor_id: 'act_1',
|
|
48
|
+
role,
|
|
49
|
+
created_at: new Date().toISOString(),
|
|
50
|
+
expires_at: null,
|
|
51
|
+
revoked_at: null,
|
|
52
|
+
revoked_by: null,
|
|
53
|
+
granted_by: null,
|
|
54
|
+
},
|
|
55
|
+
]
|
|
56
|
+
: [],
|
|
57
|
+
});
|
|
58
|
+
/**
|
|
59
|
+
* Create a Hono test app from route specs with optional auth context.
|
|
60
|
+
*
|
|
61
|
+
* @param route_specs - the route specs to register
|
|
62
|
+
* @param auth_ctx - optional request context to inject via middleware
|
|
63
|
+
* @param credential_type - optional credential type (default: `'session'` when auth_ctx provided)
|
|
64
|
+
* @returns a configured Hono app
|
|
65
|
+
*/
|
|
66
|
+
export const create_test_app_from_specs = (route_specs, auth_ctx, credential_type) => {
|
|
67
|
+
const app = new Hono();
|
|
68
|
+
app.use('/*', async (c, next) => {
|
|
69
|
+
c.set('pending_effects', []);
|
|
70
|
+
if (auth_ctx) {
|
|
71
|
+
c.set(REQUEST_CONTEXT_KEY, auth_ctx);
|
|
72
|
+
c.set(CREDENTIAL_TYPE_KEY, credential_type ?? 'session');
|
|
73
|
+
}
|
|
74
|
+
await next();
|
|
75
|
+
});
|
|
76
|
+
apply_route_specs(app, route_specs, fuz_auth_guard_resolver, new Logger('test', { level: 'off' }), create_stub_db());
|
|
77
|
+
return app;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Create one Hono test app per auth level.
|
|
81
|
+
*
|
|
82
|
+
* @param route_specs - the route specs to register
|
|
83
|
+
* @param roles - all roles in the app
|
|
84
|
+
* @returns apps keyed by auth level
|
|
85
|
+
*/
|
|
86
|
+
export const create_auth_test_apps = (route_specs, roles) => {
|
|
87
|
+
const by_role = new Map();
|
|
88
|
+
for (const role of roles) {
|
|
89
|
+
by_role.set(role, create_test_app_from_specs(route_specs, create_test_request_context(role)));
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
public: create_test_app_from_specs(route_specs),
|
|
93
|
+
authed: create_test_app_from_specs(route_specs, create_test_request_context()),
|
|
94
|
+
keeper: create_test_app_from_specs(route_specs, create_test_request_context('keeper'), 'daemon_token'),
|
|
95
|
+
by_role,
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Select the Hono test app with correct auth for a route.
|
|
100
|
+
*
|
|
101
|
+
* @param apps - the pre-built auth test apps
|
|
102
|
+
* @param auth - the route's auth options
|
|
103
|
+
* @returns the correctly-authenticated Hono app
|
|
104
|
+
*/
|
|
105
|
+
export const select_auth_app = (apps, auth) => {
|
|
106
|
+
switch (auth.type) {
|
|
107
|
+
case 'none':
|
|
108
|
+
return apps.public;
|
|
109
|
+
case 'authenticated':
|
|
110
|
+
return apps.authed;
|
|
111
|
+
case 'keeper':
|
|
112
|
+
return apps.keeper;
|
|
113
|
+
case 'role': {
|
|
114
|
+
const app = apps.by_role.get(auth.role);
|
|
115
|
+
if (!app)
|
|
116
|
+
throw new Error(`No test app for role '${auth.role}' — is it in the roles array?`);
|
|
117
|
+
return app;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
/** Replace Hono route params (`:foo`) with dummy values for HTTP testing. */
|
|
122
|
+
export const resolve_test_path = (path) => path.replace(/:(\w+)/g, 'test_$1');
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import './assert_dev_env.js';
|
|
2
|
+
import type { AppSurface, AppSurfaceSpec } from '../http/surface.js';
|
|
3
|
+
import type { RouteSpec } from '../http/route_spec.js';
|
|
4
|
+
import type { AppServerContext, AppServerOptions } from '../server/app_server.js';
|
|
5
|
+
import type { SessionOptions } from '../auth/session_cookie.js';
|
|
6
|
+
import { type DbFactory } from './db.js';
|
|
7
|
+
/**
|
|
8
|
+
* Recursively collect all property names from a JSON Schema.
|
|
9
|
+
*
|
|
10
|
+
* Walks `properties`, `items`, `allOf`/`anyOf`/`oneOf`, and
|
|
11
|
+
* `additionalProperties` to find every declared field name at any depth.
|
|
12
|
+
*
|
|
13
|
+
* @param schema - JSON Schema object
|
|
14
|
+
* @returns set of all property names found
|
|
15
|
+
*/
|
|
16
|
+
export declare const collect_json_schema_property_names: (schema: unknown) => Set<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Assert that no output schema in the surface contains sensitive field names.
|
|
19
|
+
*
|
|
20
|
+
* @param surface - the app surface to check
|
|
21
|
+
* @param sensitive_fields - field names to flag
|
|
22
|
+
*/
|
|
23
|
+
export declare const assert_output_schemas_no_sensitive_fields: (surface: AppSurface, sensitive_fields?: ReadonlyArray<string>) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Assert that non-admin route output schemas don't contain admin-only fields.
|
|
26
|
+
*
|
|
27
|
+
* @param surface - the app surface to check
|
|
28
|
+
* @param admin_only_fields - field names that are admin-only
|
|
29
|
+
*/
|
|
30
|
+
export declare const assert_non_admin_schemas_no_admin_fields: (surface: AppSurface, admin_only_fields?: ReadonlyArray<string>) => void;
|
|
31
|
+
/** Options for `describe_data_exposure_tests`. */
|
|
32
|
+
export interface DataExposureTestOptions {
|
|
33
|
+
/** Build the app surface spec (for schema-level checks). */
|
|
34
|
+
build: () => AppSurfaceSpec;
|
|
35
|
+
/** Session config for runtime tests. */
|
|
36
|
+
session_options: SessionOptions<string>;
|
|
37
|
+
/** Route spec factory for runtime tests. */
|
|
38
|
+
create_route_specs: (ctx: AppServerContext) => Array<RouteSpec>;
|
|
39
|
+
/** Fields that must never appear in any response. Default: `SENSITIVE_FIELD_BLOCKLIST`. */
|
|
40
|
+
sensitive_fields?: ReadonlyArray<string>;
|
|
41
|
+
/** Fields that must not appear in non-admin responses. Default: `ADMIN_ONLY_FIELD_BLOCKLIST`. */
|
|
42
|
+
admin_only_fields?: ReadonlyArray<string>;
|
|
43
|
+
/** Optional overrides for `AppServerOptions`. */
|
|
44
|
+
app_options?: Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs'>>;
|
|
45
|
+
/** Database factories to run tests against. Default: pglite only. */
|
|
46
|
+
db_factories?: Array<DbFactory>;
|
|
47
|
+
/** Routes to skip, in `'METHOD /path'` format. */
|
|
48
|
+
skip_routes?: Array<string>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Composable data exposure test suite.
|
|
52
|
+
*
|
|
53
|
+
* Three test groups:
|
|
54
|
+
* 1. Schema-level — walk JSON Schema output/error schemas for sensitive field names
|
|
55
|
+
* 2. Runtime — fire real requests and check response bodies against blocklists
|
|
56
|
+
* 3. Cross-privilege — admin routes return 403 for non-admin, error responses
|
|
57
|
+
* contain no sensitive fields
|
|
58
|
+
*
|
|
59
|
+
* @param options - test configuration
|
|
60
|
+
*/
|
|
61
|
+
export declare const describe_data_exposure_tests: (options: DataExposureTestOptions) => void;
|
|
62
|
+
//# sourceMappingURL=data_exposure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data_exposure.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/data_exposure.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAgB7B,OAAO,KAAK,EAAC,UAAU,EAAE,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,EAAE,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAChF,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAG9D,OAAO,EAAwB,KAAK,SAAS,EAAC,MAAM,SAAS,CAAC;AAc9D;;;;;;;;GAQG;AACH,eAAO,MAAM,kCAAkC,GAAI,QAAQ,OAAO,KAAG,GAAG,CAAC,MAAM,CAuB9E,CAAC;AAIF;;;;;GAKG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,UAAU,EACnB,mBAAkB,aAAa,CAAC,MAAM,CAA6B,KACjE,IAWF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wCAAwC,GACpD,SAAS,UAAU,EACnB,oBAAmB,aAAa,CAAC,MAAM,CAA8B,KACnE,IAcF,CAAC;AAIF,kDAAkD;AAClD,MAAM,WAAW,uBAAuB;IACvC,4DAA4D;IAC5D,KAAK,EAAE,MAAM,cAAc,CAAC;IAC5B,wCAAwC;IACxC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,4CAA4C;IAC5C,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,2FAA2F;IAC3F,gBAAgB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,iGAAiG;IACjG,iBAAiB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC1C,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CACpB,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,iBAAiB,GAAG,oBAAoB,CAAC,CAC5E,CAAC;IACF,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC,kDAAkD;IAClD,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CAC5B;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,GAAI,SAAS,uBAAuB,KAAG,IAmC/E,CAAC"}
|