WIP: Add service accounts#205
Conversation
3073dd8 to
02c7e2d
Compare
There was a problem hiding this comment.
Pull request overview
Adds first-class support for service accounts (non-human identities) and introduces a client-type–aware access model across the Rust API/models, runners, and frontend, plus runner version handshakes for “outdated runner” UI signaling.
Changes:
- Replace
api = false/API_ALLOWEDgating withclient_type = [...]/ALLOWED_CLIENT_TYPESacross endpoint macros and route mounting. - Introduce service accounts (RBAC resource + permissions, CRUD endpoints, DB tables/migrations, and permission resolution).
- Add runner WebSocket handshake (exposure type + runner semver), persist runner version, and surface “outdated” status in the UI (with an API
/versionendpoint).
Reviewed changes
Copilot reviewed 214 out of 240 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| runners/common/src/utils/router_ext.rs | Switch runner-side route mounting gate to ALLOWED_CLIENT_TYPES + ClientType. |
| runners/common/src/runner/database_sync.rs | Send runner handshake (version + exposure type); handle handshake-required retries. |
| runners/common/src/resource_executor/mod.rs | Adds ServiceAccount to resource-type match arm (still todo!()). |
| models/src/utils/mod.rs | Export new client_type utility module. |
| models/src/utils/client_type.rs | New ClientType enum shared across layers. |
| models/src/user_data.rs | Refactor request identity into IdentityData; add client_type on RequestUserData. |
| models/src/rbac/resource_type.rs | Add ResourceType::ServiceAccount. |
| models/src/rbac/permissions.rs | Add ServiceAccountPermission and Permission::ServiceAccount(...). |
| models/src/lib.rs | Re-export ServiceAccountPermission in prelude. |
| models/src/api/workspace/volume/update_volume.rs | Add client_type list to endpoint. |
| models/src/api/workspace/volume/list_volumes.rs | Add client_type list to endpoint. |
| models/src/api/workspace/volume/get_volume_info.rs | Add client_type list to endpoint. |
| models/src/api/workspace/volume/delete_volume.rs | Add client_type list to endpoint. |
| models/src/api/workspace/volume/create_volume.rs | Add client_type list to endpoint. |
| models/src/api/workspace/update_workspace_info.rs | Add client_type list to endpoint. |
| models/src/api/workspace/service_account/create_service_account.rs | New service-account create endpoint model. |
| models/src/api/workspace/service_account/delete_service_account.rs | New service-account delete endpoint model. |
| models/src/api/workspace/service_account/get_service_account_info.rs | New service-account get endpoint model. |
| models/src/api/workspace/service_account/list_service_accounts.rs | New service-account list endpoint model. |
| models/src/api/workspace/service_account/regenerate_service_account_token.rs | New token-regeneration endpoint model. |
| models/src/api/workspace/service_account/update_service_account.rs | New update endpoint model. |
| models/src/api/workspace/service_account/mod.rs | New module exporting service-account models/endpoints. |
| models/src/api/workspace/runner/stream_runner_logs.rs | Add client_type list to stream endpoint. |
| models/src/api/workspace/runner/stream_runner_data_for_workspace.rs | Enforce client_type = [ServiceAccount]; add handshake messages & runner version. |
| models/src/api/workspace/runner/remove_runner_from_workspace.rs | Add client_type list to endpoint. |
| models/src/api/workspace/runner/mod.rs | Add version: Version field to Runner model. |
| models/src/api/workspace/runner/list_runners_for_workspace.rs | Add client_type list to endpoint. |
| models/src/api/workspace/runner/get_runner_metrics.rs | Add client_type list to endpoint. |
| models/src/api/workspace/runner/get_runner_logs.rs | Add client_type list to endpoint. |
| models/src/api/workspace/runner/get_runner_info.rs | Add client_type list to endpoint. |
| models/src/api/workspace/runner/get_ingress_token_for_runner.rs | Add client_type list to endpoint. |
| models/src/api/workspace/runner/add_runner_to_workspace.rs | Add client_type list to endpoint. |
| models/src/api/workspace/rbac/user/update_user_roles_in_workspace.rs | Add client_type list to endpoint. |
| models/src/api/workspace/rbac/user/remove_user_from_workspace.rs | Add client_type list to endpoint. |
| models/src/api/workspace/rbac/user/list_users_in_workspace.rs | Add client_type list to endpoint. |
| models/src/api/workspace/rbac/role/update_role.rs | Add client_type list to endpoint. |
| models/src/api/workspace/rbac/role/list_users_for_role.rs | Add client_type list to endpoint. |
| models/src/api/workspace/rbac/role/list_all_roles.rs | Add client_type list to endpoint. |
| models/src/api/workspace/rbac/role/get_role_info.rs | Add client_type list to endpoint. |
| models/src/api/workspace/rbac/role/delete_role.rs | Add client_type list to endpoint. |
| models/src/api/workspace/rbac/role/create_new_role.rs | Add client_type list to endpoint. |
| models/src/api/workspace/rbac/list_all_resource_types.rs | Add client_type list to endpoint. |
| models/src/api/workspace/rbac/list_all_permissions.rs | Add client_type list to endpoint. |
| models/src/api/workspace/rbac/get_current_permissions.rs | Add client_type list to endpoint. |
| models/src/api/workspace/mod.rs | Export new service_account workspace API module. |
| models/src/api/workspace/managed_url/verify_configuration.rs | Add client_type list to endpoint. |
| models/src/api/workspace/managed_url/update_managed_url.rs | Add client_type list to endpoint. |
| models/src/api/workspace/managed_url/list_managed_url.rs | Add client_type list to endpoint. |
| models/src/api/workspace/managed_url/delete_managed_url.rs | Add client_type list to endpoint. |
| models/src/api/workspace/managed_url/create_managed_url.rs | Add client_type list to endpoint. |
| models/src/api/workspace/is_name_available.rs | Add client_type list to endpoint. |
| models/src/api/workspace/get_workspace_info.rs | Add client_type list to endpoint. |
| models/src/api/workspace/domain/verify_domain_in_workspace.rs | Add client_type list to endpoint. |
| models/src/api/workspace/domain/update_domain_dns_record.rs | Add client_type list to endpoint. |
| models/src/api/workspace/domain/list_domains_in_workspace.rs | Add client_type list to endpoint. |
| models/src/api/workspace/domain/is_domain_valid.rs | Add client_type list to endpoint. |
| models/src/api/workspace/domain/get_domain_info_in_workspace.rs | Add client_type list to endpoint. |
| models/src/api/workspace/domain/get_domain_dns_record.rs | Add client_type list to endpoint. |
| models/src/api/workspace/domain/delete_domain_in_workspace.rs | Add client_type list to endpoint. |
| models/src/api/workspace/domain/delete_dns_record.rs | Add client_type list to endpoint. |
| models/src/api/workspace/domain/add_domain_to_workspace.rs | Add client_type list to endpoint. |
| models/src/api/workspace/domain/add_dns_record.rs | Add client_type list to endpoint. |
| models/src/api/workspace/deployment/update_deployment.rs | Add client_type list to endpoint. |
| models/src/api/workspace/deployment/stream_deployment_logs.rs | Add client_type list to stream endpoint. |
| models/src/api/workspace/deployment/stop_deployment.rs | Add client_type list to endpoint. |
| models/src/api/workspace/deployment/start_deployment.rs | Add client_type list to endpoint. |
| models/src/api/workspace/deployment/list_deployment.rs | Add client_type list to endpoint. |
| models/src/api/workspace/deployment/list_all_deployment_machine_type.rs | Add client_type list to endpoint. |
| models/src/api/workspace/deployment/get_deployment_metric.rs | Add client_type list to endpoint. |
| models/src/api/workspace/deployment/get_deployment_logs.rs | Add client_type list to endpoint. |
| models/src/api/workspace/deployment/get_deployment_info.rs | Add client_type list to endpoint. |
| models/src/api/workspace/deployment/deploy_history/revert_deployment.rs | Add client_type list to endpoint. |
| models/src/api/workspace/deployment/deploy_history/list_deploy_history.rs | Add client_type list to endpoint. |
| models/src/api/workspace/deployment/deploy_history/delete_deploy_history.rs | Add client_type list to endpoint. |
| models/src/api/workspace/deployment/delete_deployment.rs | Add client_type list to endpoint. |
| models/src/api/workspace/deployment/create_deployment.rs | Add client_type list to endpoint. |
| models/src/api/workspace/delete_workspace.rs | Add client_type list to endpoint. |
| models/src/api/workspace/create_workspace.rs | Add client_type list to endpoint. |
| models/src/api/workspace/container_registry/list_repository_tags.rs | Add client_type list to endpoint. |
| models/src/api/workspace/container_registry/list_repository_manifests.rs | Add client_type list to endpoint. |
| models/src/api/workspace/container_registry/list_repositories.rs | Add client_type list to endpoint. |
| models/src/api/workspace/container_registry/get_repository_manifest_details.rs | Add client_type list to endpoint. |
| models/src/api/workspace/container_registry/get_repository_info.rs | Add client_type list to endpoint. |
| models/src/api/workspace/container_registry/get_exposed_ports.rs | Add client_type list to endpoint. |
| models/src/api/workspace/container_registry/delete_repository_manifest.rs | Add client_type list to endpoint. |
| models/src/api/workspace/container_registry/delete_repository.rs | Add client_type list to endpoint. |
| models/src/api/workspace/container_registry/create_repository.rs | Add client_type list to endpoint. |
| models/src/api/user/web_logins/list_web_logins.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/web_logins/get_web_login_info.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/web_logins/delete_web_login.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/update_user_info.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/search_for_user.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/recovery_options/verify_user_phone_number.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/recovery_options/verify_user_email.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/recovery_options/update_user_phone_number.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/recovery_options/update_user_email.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/mfa/get_mfa_secret.rs | Add client_type = [WebDashboard]. |
| models/src/api/user/mfa/deactivate_mfa.rs | Add client_type = [WebDashboard]. |
| models/src/api/user/mfa/activate_mfa.rs | Add client_type = [WebDashboard]. |
| models/src/api/user/list_user_workspaces.rs | Add client_type list to endpoint. |
| models/src/api/user/get_user_info.rs | Add client_type list to endpoint. |
| models/src/api/user/get_user_details.rs | Add client_type list to endpoint. |
| models/src/api/user/change_password.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/api_token/update_api_token.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/api_token/revoke_api_token.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/api_token/regenerate_api_token.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/api_token/list_api_tokens.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/api_token/get_api_token_info.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/user/api_token/create_api_token.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/get_version.rs | Add typed semver response and client-type gating. |
| models/src/api/auth/reset_password.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/auth/resend_otp.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/auth/renew_access_token.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/auth/oauth/token.rs | Add client_type = [WebDashboard]. |
| models/src/api/auth/oauth/revoke.rs | Add client_type = [WebDashboard]. |
| models/src/api/auth/oauth/introspect.rs | Add client_type = [WebDashboard]. |
| models/src/api/auth/oauth/authorize.rs | Add client_type = [WebDashboard]. |
| models/src/api/auth/logout.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/auth/login.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/auth/list_recovery_options.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/auth/is_username_valid.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/auth/is_email_valid.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/auth/forgot_password.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/auth/docker_login.rs | Add client_type = [ApiToken]. |
| models/src/api/auth/create_account.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/auth/complete_sign_up.rs | Replace api = false with client_type = [WebDashboard]. |
| models/src/api/api_endpoint.rs | Replace API_ALLOWED with ALLOWED_CLIENT_TYPES. |
| models/Cargo.toml | Add semver dependency with serde support. |
| macros/src/declare_stream_endpoint.rs | Require client_type in stream endpoint declarations; emit ALLOWED_CLIENT_TYPES. |
| macros/src/declare_api_endpoint.rs | Require client_type in API endpoint declarations; emit ALLOWED_CLIENT_TYPES. |
| frontend/src/routes/_logged-in/_workspaced/workspace/-components/workspace-header.tsx | UI tweak: role create link styling change. |
| frontend/src/routes/_logged-in/_workspaced/runners/index.tsx | Show runner version + outdated indicator; fetch API version. |
| frontend/src/routes/_logged-in/_workspaced/runners/-components/metrics.tsx | Add runner identity/version panel and outdated hint in metrics view. |
| frontend/src/routes/_logged-in/_workspaced/runners/$id.tsx | Default tab change; add delete modal; pass version info into metrics; fetch API version. |
| frontend/src/hooks/fetch/version.tsx | New query hook for API version endpoint. |
| frontend/src/hooks/fetch/index.tsx | Export useApiVersionQuery. |
| frontend/src/bindings/index.ts | Export GetVersionResponse binding. |
| frontend/pnpm-lock.yaml | Add semver + typings lock entries. |
| frontend/package.json | Add semver + @types/semver. |
| api/tests/utils.rs | Add TestServiceAccount helper + creation helper for tests. |
| api/tests/setup.rs | Update route setup call to accept &[ClientType]. |
| api/tests/api/workspace/rbac/permissions/service_account.rs | New RBAC permission tests for service-account permissions. |
| api/tests/api/workspace/rbac/permissions/mod.rs | Register new service-account permission test module. |
| api/tests/api/workspace/mod.rs | Register new workspace service-account test module. |
| api/tests/api/workspace/deployment/mod.rs | Fix request path to include required metric parameter. |
| api/src/utils/layers/registry/authenticator.rs | Update token auth to new client-type resolution signature. |
| api/src/utils/layers/authenticator.rs | Move ClientType into models; enforce endpoint client-type allowlist post-auth. |
| api/src/utils/extensions/router_ext.rs | Change mounting to accept [ClientType] and mount only when allowlists overlap. |
| api/src/routes/mod.rs | Enable API routes for ApiToken + ServiceAccount. |
| api/src/routes/mimir.patr.cloud/auth.rs | Restrict push auth to service-account client type. |
| api/src/routes/loki.patr.cloud/auth.rs | Restrict push auth to service-account client type. |
| api/src/routes/app.patr.cloud/mod.rs | Update setup call to accept &[ClientType::WebDashboard]. |
| api/src/routes/api.patr.cloud/workspace/volume/mod.rs | Propagate allowed_client_types: &[ClientType] through workspace volume router. |
| api/src/routes/api.patr.cloud/workspace/static_site/mod.rs | Propagate allowed_client_types: &[ClientType] through static-site router. |
| api/src/routes/api.patr.cloud/workspace/service_account/create_service_account.rs | Implement service-account creation + token generation. |
| api/src/routes/api.patr.cloud/workspace/service_account/list_service_accounts.rs | Implement listing service accounts (with role population). |
| api/src/routes/api.patr.cloud/workspace/service_account/get_service_account_info.rs | Implement service-account detail endpoint. |
| api/src/routes/api.patr.cloud/workspace/service_account/update_service_account.rs | Implement updating name/description and role replacement + cache invalidation. |
| api/src/routes/api.patr.cloud/workspace/service_account/delete_service_account.rs | Implement delete flow + cache invalidation. |
| api/src/routes/api.patr.cloud/workspace/service_account/regenerate_service_account_token.rs | Implement token regeneration + cache invalidation. |
| api/src/routes/api.patr.cloud/workspace/service_account/mod.rs | Wire service-account routes into workspace API router. |
| api/src/routes/api.patr.cloud/workspace/secret/mod.rs | Propagate allowed_client_types: &[ClientType] through secrets router. |
| api/src/routes/api.patr.cloud/workspace/runner/stream_runner_data_for_workspace.rs | Require handshake, persist runner version, and rename required message. |
| api/src/routes/api.patr.cloud/workspace/runner/mod.rs | Propagate allowed_client_types: &[ClientType] through runner router. |
| api/src/routes/api.patr.cloud/workspace/runner/list_runners_for_workspace.rs | Return runner version parsed as semver. |
| api/src/routes/api.patr.cloud/workspace/runner/get_runner_info.rs | Return runner last_seen + version (semver). |
| api/src/routes/api.patr.cloud/workspace/runner/add_runner_to_workspace.rs | Backfill runner version with 0.0.0 for new runners until handshake. |
| api/src/routes/api.patr.cloud/workspace/rbac/user/mod.rs | Propagate allowed_client_types: &[ClientType] through RBAC user router. |
| api/src/routes/api.patr.cloud/workspace/rbac/role/mod.rs | Propagate allowed_client_types: &[ClientType] through RBAC role router. |
| api/src/routes/api.patr.cloud/workspace/rbac/permission/mod.rs | Propagate allowed_client_types: &[ClientType] through RBAC permission router. |
| api/src/routes/api.patr.cloud/workspace/rbac/mod.rs | Propagate allowed_client_types: &[ClientType] through workspace RBAC router. |
| api/src/routes/api.patr.cloud/workspace/mod.rs | Wire service-account router and propagate allowed_client_types across workspace. |
| api/src/routes/api.patr.cloud/workspace/managed_url/update_managed_url.rs | Minor query refactor (remove unused binding). |
| api/src/routes/api.patr.cloud/workspace/managed_url/mod.rs | Propagate allowed_client_types: &[ClientType] through managed-url router. |
| api/src/routes/api.patr.cloud/workspace/domain/mod.rs | Propagate allowed_client_types: &[ClientType] through domain router. |
| api/src/routes/api.patr.cloud/workspace/deployment/mod.rs | Propagate allowed_client_types: &[ClientType] through deployment router. |
| api/src/routes/api.patr.cloud/workspace/deployment/deploy_history/mod.rs | Propagate allowed_client_types: &[ClientType] through deploy-history router. |
| api/src/routes/api.patr.cloud/workspace/database/mod.rs | Propagate allowed_client_types: &[ClientType] through database router. |
| api/src/routes/api.patr.cloud/workspace/container_registry/mod.rs | Propagate allowed_client_types: &[ClientType] through container-registry router. |
| api/src/routes/api.patr.cloud/user/web_logins/mod.rs | Propagate allowed_client_types: &[ClientType] through web-logins router. |
| api/src/routes/api.patr.cloud/user/recovery_options/mod.rs | Propagate allowed_client_types: &[ClientType] through recovery-options router. |
| api/src/routes/api.patr.cloud/user/mod.rs | Propagate allowed_client_types: &[ClientType] through user router. |
| api/src/routes/api.patr.cloud/user/mfa/mod.rs | Propagate allowed_client_types: &[ClientType] through MFA router. |
| api/src/routes/api.patr.cloud/user/mfa/get_mfa_secret.rs | Enforce human identity (username) requirement via IdentityData. |
| api/src/routes/api.patr.cloud/user/mfa/deactivate_mfa.rs | Enforce human identity (username) requirement via IdentityData. |
| api/src/routes/api.patr.cloud/user/mfa/activate_mfa.rs | Enforce human identity (username) requirement via IdentityData. |
| api/src/routes/api.patr.cloud/user/change_password.rs | Enforce human identity (username) requirement via IdentityData. |
| api/src/routes/api.patr.cloud/user/api_token/mod.rs | Propagate allowed_client_types: &[ClientType] through API-token router. |
| api/src/routes/api.patr.cloud/mod.rs | Add /version endpoint and propagate allowed_client_types through API router. |
| api/src/routes/api.patr.cloud/get_version.rs | Implement /version response using semver parse of build version. |
| api/src/routes/api.patr.cloud/auth/oauth/mod.rs | Propagate allowed_client_types: &[ClientType] through OAuth router. |
| api/src/routes/api.patr.cloud/auth/mod.rs | Propagate allowed_client_types: &[ClientType] through auth router. |
| api/src/models/permissions/web_dashboard.rs | Build RequestUserData using IdentityData::User + ClientType::WebDashboard. |
| api/src/models/permissions/mod.rs | Resolve client type by token format; extend permission resolution for service accounts. |
| api/src/models/permissions/api_token.rs | Add service-account token authentication branch; set IdentityData + ClientType. |
| api/src/migrations/v0_18_0/mod.rs | Register service-account and runner-version migrations. |
| api/src/migrations/v0_18_0/m004_runner_version.rs | Add runner.version column, backfill, drop default. |
| api/src/lib.rs | Update prelude to re-export ClientType from models. |
| api/src/db/workspace/service_account.rs | Create service-account tables, indexes, and constraints. |
| api/src/db/workspace/runner.rs | Add version column to runner table schema. |
| api/src/db/workspace/mod.rs | Initialize new service-account DB objects during workspace schema init. |
| api/src/db/rbac.rs | Extend RBAC SQL/constraints to support service-account role permissions. |
| api/src/app.rs | Run API domain with [ApiToken, ServiceAccount] allowed client types. |
| Cargo.lock | Add Rust semver dependency with serde support. |
| .sqlx/query-fdfefb758976cb8b60e93ed953cdba875bed339457343dc0f5924ff98349746e.json | New sqlx metadata for service-account select query. |
| .sqlx/query-f9827413c755c57d97ff3adea8649a6e5e8c1f7344a559e485099877c3f4acb8.json | Update sqlx metadata for include-permissions query (service-account union + params). |
| .sqlx/query-f57623f566034c7d8f4bcb4a3d9c6d8f9ad46c7829e9962c7e147f4754fb28c2.json | New sqlx metadata for service-account FK constraints. |
| .sqlx/query-f2d50e2d3c72f29923a689013ba9d389c5650ea0987013450ee7acd13701063b.json | New sqlx metadata for service-account-role FK constraints. |
| .sqlx/query-ee6a287cd21311680135dca639cc93f49ed8b3d9081ce8e4e3f678b3491ac1c0.json | Update sqlx metadata for runner table (add version column). |
| .sqlx/query-ed280ab6fd48207bd6f1f0eab21b5fc2f0e09bb6713e8733b76d982690d99d87.json | New sqlx metadata for updated RBAC function (service-account unions). |
| .sqlx/query-e99bbb100490d2884223cf128fc003767b9eb107d8f879d9a11a77a910c4e1c1.json | New sqlx metadata for service-account token lookup query. |
| .sqlx/query-e52764a5ee74a45b231c088fa1a6c247179d54e28ac91810882576ed9c0da604.json | New sqlx metadata for resource soft-delete update query. |
| .sqlx/query-cee64b83d74b8cbebe360a27b935391487e739616aa4dfae5515880fccc14c59.json | New sqlx metadata for service-account unique index creation. |
| .sqlx/query-cecd6c29cde5b95361c8f789e0aa6fd63a688163d3baea3e27f6a1e4eceab4b1.json | New sqlx metadata for service-account hard delete query. |
| .sqlx/query-cd83bf67cbad60094f70337b9da90cac9a45a438c2352dc287a5accfcbe6b470.json | Update sqlx metadata for user API token lookup (typed UUID fields). |
| .sqlx/query-b8f017fb23fe9903ffafbdea8627268ab686ee1c65354032b403801352bdceff.json | New sqlx metadata for service-account-role PK constraint. |
| .sqlx/query-aed0d288a5a92bceeb7e3527753d07390de655789e0df3215b287d0418f1b1fb.json | New sqlx metadata for runner version update query. |
| .sqlx/query-ae0fbfb614fdc8a80fc727b7eb505c0163047eb18f745dcd2e567e34567847e1.json | New sqlx metadata for service-account-role delete-by-SA query. |
| .sqlx/query-9b267699a93e6ab044e820b4f23cfa5c972e9f2e0a6abcc0887e10615eb58113.json | Update sqlx metadata for exclude-permissions query (service-account union + params). |
| .sqlx/query-9a7d77b5c98a4f17854f8c902a0ece01a444a8a83729d2f46d92779359f632d2.json | New sqlx metadata for service-account token-hash update query. |
| .sqlx/query-7a1d96c754b19ce8b852bcfc3febea3dedcce0b113485a9424f3e7a16088a0bc.json | Update sqlx metadata for updated workspace_user FK constraint. |
| .sqlx/query-78701ce75bba88f7cdd8c2f9890cedbfbd915a3acbd1f034f0d15689152192a9.json | Remove obsolete sqlx metadata for prior RBAC function definition. |
| .sqlx/query-75f0921e043d0aa93c127618e535bf8fc39381bc8528ec5a351404e8f4193659.json | New sqlx metadata for service-account PK/unique constraints. |
| .sqlx/query-7136b9c3a1d9939fc2c61535ac2c53aa7f06d1dfda8e5493f548c354ec1756e6.json | New sqlx metadata for service-account table creation. |
| .sqlx/query-6be5bb0ed0f21c53402d53dac32fc05657f328d83ec142f2f2f9c2e2475976c7.json | Update sqlx metadata for runner table creation (add version). |
| .sqlx/query-6989f17c307d10679d7dfbb49ca74340522394ee5512ad1316aece55311e48f6.json | Update sqlx metadata for runner listing query (select version). |
| .sqlx/query-6411b0ea49b4bc13ec3d9f3972f4d95d49b2855f707787ceede181f0ffd67b8d.json | New sqlx metadata for service-account list query. |
| .sqlx/query-63b3d3277e9994237d310bffaa3851ebd0877401f2d4fa0b18b5044b07558cac.json | New sqlx metadata for service-account insert query. |
| .sqlx/query-5cd0f65ae71076847f2b9b08dc4e429ea036f13d8941f579dda4f2457f6f758d.json | Update sqlx metadata for role constraints (add unique(id, owner_id)). |
| .sqlx/query-590deec508ca78e9eac846e8b98a0b01191c730536fdee9d40bd64d5f4d49c4e.json | New sqlx metadata for service-account-role table creation. |
| .sqlx/query-52703699e7152a1459a60c689f4e7ab745665e62a519fc83d85745c246041409.json | New sqlx metadata for service-account update query. |
| .sqlx/query-4e2a186ec7b34027195a6800df7a36dbbde1043bd2c894fd539c8947bfedaeee.json | Update sqlx metadata for runner table describe (add version). |
| .sqlx/query-1830c329cf3f633cd66977924ad52248245c8758bbe23caebcaca45229ea2b23.json | New sqlx metadata for resource insert for service accounts. |
| .sqlx/query-125238af7f9fed6327ea0cbd05ba5a56ef3bfbfebb8ffda652e7ba506be1d1ba.json | Update sqlx metadata for runner connect update (set version). |
| .sqlx/query-11f23e4d57bbe6551e9f909192bfba466207f13075d4e2ddecb34f47eeef5d16.json | New sqlx metadata for service-account-role insert query. |
| .sqlx/query-0e3cfd588fd9494c65cea36970df7a72f67981bbffa31b0b89484dccfc4ad3ed.json | New sqlx metadata for service-account role list query. |
| .sqlx/query-0ddd8016a998bbad16fa15cab795ee1b5181162a640ad43930861f0ed9011577.json | Update sqlx metadata for runner insert (backfill version). |
Files not reviewed (25)
- .sqlx/query-0e3cfd588fd9494c65cea36970df7a72f67981bbffa31b0b89484dccfc4ad3ed.json: Language not supported
- .sqlx/query-11f23e4d57bbe6551e9f909192bfba466207f13075d4e2ddecb34f47eeef5d16.json: Language not supported
- .sqlx/query-1830c329cf3f633cd66977924ad52248245c8758bbe23caebcaca45229ea2b23.json: Language not supported
- .sqlx/query-4e2a186ec7b34027195a6800df7a36dbbde1043bd2c894fd539c8947bfedaeee.json: Language not supported
- .sqlx/query-52703699e7152a1459a60c689f4e7ab745665e62a519fc83d85745c246041409.json: Language not supported
- .sqlx/query-590deec508ca78e9eac846e8b98a0b01191c730536fdee9d40bd64d5f4d49c4e.json: Language not supported
- .sqlx/query-63b3d3277e9994237d310bffaa3851ebd0877401f2d4fa0b18b5044b07558cac.json: Language not supported
- .sqlx/query-6411b0ea49b4bc13ec3d9f3972f4d95d49b2855f707787ceede181f0ffd67b8d.json: Language not supported
- .sqlx/query-7136b9c3a1d9939fc2c61535ac2c53aa7f06d1dfda8e5493f548c354ec1756e6.json: Language not supported
- .sqlx/query-75f0921e043d0aa93c127618e535bf8fc39381bc8528ec5a351404e8f4193659.json: Language not supported
- .sqlx/query-78701ce75bba88f7cdd8c2f9890cedbfbd915a3acbd1f034f0d15689152192a9.json: Language not supported
- .sqlx/query-9a7d77b5c98a4f17854f8c902a0ece01a444a8a83729d2f46d92779359f632d2.json: Language not supported
- .sqlx/query-ae0fbfb614fdc8a80fc727b7eb505c0163047eb18f745dcd2e567e34567847e1.json: Language not supported
- .sqlx/query-aed0d288a5a92bceeb7e3527753d07390de655789e0df3215b287d0418f1b1fb.json: Language not supported
- .sqlx/query-b8f017fb23fe9903ffafbdea8627268ab686ee1c65354032b403801352bdceff.json: Language not supported
- .sqlx/query-cecd6c29cde5b95361c8f789e0aa6fd63a688163d3baea3e27f6a1e4eceab4b1.json: Language not supported
- .sqlx/query-cee64b83d74b8cbebe360a27b935391487e739616aa4dfae5515880fccc14c59.json: Language not supported
- .sqlx/query-e52764a5ee74a45b231c088fa1a6c247179d54e28ac91810882576ed9c0da604.json: Language not supported
- .sqlx/query-e99bbb100490d2884223cf128fc003767b9eb107d8f879d9a11a77a910c4e1c1.json: Language not supported
- .sqlx/query-ed280ab6fd48207bd6f1f0eab21b5fc2f0e09bb6713e8733b76d982690d99d87.json: Language not supported
- .sqlx/query-ee6a287cd21311680135dca639cc93f49ed8b3d9081ce8e4e3f678b3491ac1c0.json: Language not supported
- .sqlx/query-f2d50e2d3c72f29923a689013ba9d389c5650ea0987013450ee7acd13701063b.json: Language not supported
- .sqlx/query-f57623f566034c7d8f4bcb4a3d9c6d8f9ad46c7829e9962c7e147f4754fb28c2.json: Language not supported
- .sqlx/query-fdfefb758976cb8b60e93ed953cdba875bed339457343dc0f5924ff98349746e.json: Language not supported
- frontend/pnpm-lock.yaml: Language not supported
| // Populate roles for each service account | ||
| for service_account in &mut service_accounts { | ||
| service_account.data.roles = query!( | ||
| r#" | ||
| SELECT | ||
| role_id AS "role_id: Uuid" | ||
| FROM | ||
| service_account_role | ||
| WHERE | ||
| service_account_id = $1; | ||
| "#, | ||
| service_account.id as _, | ||
| ) | ||
| .fetch_all(&mut **database) | ||
| .await? | ||
| .into_iter() | ||
| .map(|row| row.role_id) | ||
| .collect::<Vec<_>>(); | ||
| } |
There was a problem hiding this comment.
list_service_accounts populates roles with a per-service-account query (N+1). This will scale poorly as the number of service accounts grows. Consider fetching roles for all returned service accounts in a single query (e.g., join + GROUP BY/array_agg, or a second query with WHERE service_account_id = ANY($1) and then map/group in memory).
Service accounts are a new identity type alongside users. They belong to a
workspace, have a single token (patrv1.{refresh}.{sa_id}), and can be
assigned roles for fine-grained RBAC permissions.
Schema: service_account table with token_hash, service_account_role for role
assignments with workspace-enforced FKs. Updated RESOURCES_WITH_PERMISSION
PL/pgSQL function and permission resolution queries with UNION ALL branches.
Auth: api_token.rs tries user_api_token first, then service_account.
RequestUserData refactored with IdentityData enum (User | ServiceAccount).
CRUD endpoints: create (returns token), list, get, update, delete,
regenerate-token. All use ResourcePermissionAuthenticator with new
ServiceAccountPermission variants.
Also fixes: SearchType derive in macros (syn::Path compat), role FK
workspace enforcement on workspace_user.
- move ClientType to models crate, add ServiceAccount variant - replace api=bool with client_type=[WebDashboard, ApiToken, ServiceAccount] arrays - make client_type required in declare_api_endpoint and declare_stream_endpoint macros - auth layer dispatches by token format (patrv1 prefix vs JWT), checks resolved type against endpoint's ALLOWED_CLIENT_TYPES - add client_type field to RequestUserData - restrict loki/mimir push and stream_runner_data_for_workspace to SA only - exclude SA from create_workspace, SA management, and user-personal endpoints - add test plan for the refactor to api/tests/TODOs.md
- report runner version on the websocket handshake, store it, flag outdated runners in the UI - rename SetRunnerExposureType to Handshake, carry version alongside exposure type - wire up GET /version (was declared but unmounted) - runner detail: metrics default tab, container-registry-style identity block, delete when disconnected - migration adds version column with 0.0.0 sentinel for existing rows
…scoped to /workspace/{id}/runner/link/...
- per-runner service account issued on approve, cascading delete with the runner
- redis key for the link includes workspace_id, so cross-workspace lookups are 404
- CLI: workspace picker pre-selected on current_workspace, bearer auth on create/verify, friendly error when link is gone
- CLI: read response body as ApiErrorResponseBody on non-2xx instead of squashing to InternalServerError
- CLI: explicit config (CONFIG_PATH or repo cli.json) now overrides OS-level file
- frontend: split setup page into setup/ folder with index + dash-prefixed components
- frontend: OtpInput generalized (length, sanitize, separator, unstyled, refs not ids)
- frontend: Alert gains align prop
- volume: GetVolumeInfo now requires Volume(View) instead of Volume(Delete)
72394f5 to
2e1a820
Compare
service accounts - non-human identity for runners/automation. workspace-scoped, single token, role-based RBAC.
RequestUserData refactored with IdentityData enum. CRUD endpoints, permission resolution, migration, integration tests.
remaining work: