From d9a5d9ab94dee82de44a1575e395016f1982f9a3 Mon Sep 17 00:00:00 2001 From: "spin-stack-website-sync[bot]" <347572492+spin-stack-website-sync[bot]@users.noreply.github.com> Date: Sat, 14 Nov 2026 12:22:28 +0000 Subject: [PATCH] sources: spin v20261113.01 911f516bc8 Written by sync.yml: versions.yaml bumped by task sources:bump, the reference by task reference. --- public/openapi.json | 4264 +++++++++++++---- src/assets/shots/snapshots.png | Bin 65276 -> 67377 bytes src/assets/shots/workspace.png | Bin 108458 -> 102889 bytes src/assets/shots/workspaces.png | Bin 47555 -> 49793 bytes .../docs/reference/api/adminservice.md | 252 +- src/content/docs/reference/api/authservice.md | 2 +- src/content/docs/reference/api/execservice.md | 2 +- .../docs/reference/api/forgeservice.md | 2 +- src/content/docs/reference/api/hostservice.md | 9 +- .../docs/reference/api/hostshellservice.md | 2 +- src/content/docs/reference/api/index.md | 8 +- src/content/docs/reference/api/logservice.md | 20 +- .../docs/reference/api/projectservice.md | 26 +- .../docs/reference/api/runnertokenservice.md | 2 +- .../docs/reference/api/settingsservice.md | 6 +- src/content/docs/reference/api/teamservice.md | 24 +- src/content/docs/reference/api/types.md | 437 +- .../docs/reference/api/workspaceservice.md | 101 +- src/content/docs/reference/cli/admin.md | 204 +- src/content/docs/reference/cli/api-key.md | 4 +- src/content/docs/reference/cli/open.md | 4 +- src/content/docs/reference/cli/project.md | 8 +- src/content/docs/reference/cli/ssh-config.md | 4 + src/content/docs/reference/cli/ssh.md | 4 + src/content/docs/reference/cli/vscode.md | 10 +- .../docs/reference/configuration/file.md | 16 +- .../docs/reference/security/known-gaps.md | 15 +- src/content/docs/reference/security/rules.md | 9 +- src/content/docs/reference/status/index.md | 177 +- src/content/docs/use/access.md | 2 +- src/content/docs/use/dashboard.md | 2 +- src/data/features.json | 65 +- src/data/figures.json | 8 +- src/data/pricing.json | 4 +- src/data/reference.json | 10 +- src/data/shots.json | 4 +- versions.yaml | 4 +- 37 files changed, 4509 insertions(+), 1202 deletions(-) diff --git a/public/openapi.json b/public/openapi.json index 39bf23d..a90690a 100644 --- a/public/openapi.json +++ b/public/openapi.json @@ -753,7 +753,7 @@ "AdminService" ], "summary": "GetCosts", - "description": "A month of the bill shared out to the workspaces that caused it: the runners' by what each\n workspace held of them, the volumes' bucket by what its volumes kept. What nobody caused is\n said apart and never spread: the runners' capacity nobody held, the bucket's bytes no\n workspace keeps, and the platform's own cost by service (internal/controlplane/domain/finops).", + "description": "A month of the bill shared out to the workspaces that caused it: the runners' by what each\n workspace held of them, the volumes' bucket by what its volumes kept. What nobody caused is\n said apart and never spread: the runners' capacity nobody held, the bucket's bytes no\n workspace keeps, and the platform's own cost by role and service; and, from those, what the\n installation costs a day with nobody working (internal/controlplane/domain/finops).", "operationId": "spin.v1.AdminService.GetCosts", "parameters": [ { @@ -995,14 +995,14 @@ } } }, - "/spin.v1.AdminService/GetInstallationSettings": { + "/spin.v1.AdminService/GetMonitoring": { "post": { "tags": [ "AdminService" ], - "summary": "GetInstallationSettings", - "description": "Get installation settings", - "operationId": "spin.v1.AdminService.GetInstallationSettings", + "summary": "GetMonitoring", + "description": "The Grafana the control plane serves over the installation's metrics, and the release's\n dashboards in it.", + "operationId": "spin.v1.AdminService.GetMonitoring", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1027,7 +1027,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetInstallationSettingsRequest" + "$ref": "#/components/schemas/spin.v1.GetMonitoringRequest" } } }, @@ -1049,7 +1049,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetInstallationSettingsResponse" + "$ref": "#/components/schemas/spin.v1.GetMonitoringResponse" } } } @@ -1057,14 +1057,14 @@ } } }, - "/spin.v1.AdminService/GetMonitoring": { + "/spin.v1.AdminService/GetPlatformImages": { "post": { "tags": [ "AdminService" ], - "summary": "GetMonitoring", - "description": "The Grafana the control plane serves over the installation's metrics, and the release's\n dashboards in it.", - "operationId": "spin.v1.AdminService.GetMonitoring", + "summary": "GetPlatformImages", + "description": "Whether the base image and the supervisor this control plane's image carries are\n published.", + "operationId": "spin.v1.AdminService.GetPlatformImages", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1089,7 +1089,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetMonitoringRequest" + "$ref": "#/components/schemas/spin.v1.GetPlatformImagesRequest" } } }, @@ -1111,7 +1111,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetMonitoringResponse" + "$ref": "#/components/schemas/spin.v1.GetPlatformImagesResponse" } } } @@ -1119,14 +1119,14 @@ } } }, - "/spin.v1.AdminService/GetPlatformImages": { + "/spin.v1.AdminService/GetRunbook": { "post": { "tags": [ "AdminService" ], - "summary": "GetPlatformImages", - "description": "Whether the base image and the supervisor this control plane's image carries are\n published.", - "operationId": "spin.v1.AdminService.GetPlatformImages", + "summary": "GetRunbook", + "description": "One runbook, its markdown and where its file is at the pinned commit. NOT_FOUND for an id\n this release's runbooks do not have.", + "operationId": "spin.v1.AdminService.GetRunbook", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1151,7 +1151,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetPlatformImagesRequest" + "$ref": "#/components/schemas/spin.v1.GetRunbookRequest" } } }, @@ -1173,7 +1173,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetPlatformImagesResponse" + "$ref": "#/components/schemas/spin.v1.GetRunbookResponse" } } } @@ -1181,14 +1181,14 @@ } } }, - "/spin.v1.AdminService/GetRegistrationMode": { + "/spin.v1.AdminService/GetSettings": { "post": { "tags": [ "AdminService" ], - "summary": "GetRegistrationMode", - "description": "Get registration mode (open, whitelist, closed)", - "operationId": "spin.v1.AdminService.GetRegistrationMode", + "summary": "GetSettings", + "description": "Every setting of the installation as it is in force, and what each is: its type, its\n default, its bounds, what it reaches when saved and who writes it\n (internal/controlplane/settings, the one registry the file, the dashboard and the CLI are\n made from).", + "operationId": "spin.v1.AdminService.GetSettings", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1213,7 +1213,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetRegistrationModeRequest" + "$ref": "#/components/schemas/spin.v1.GetSettingsRequest" } } }, @@ -1235,7 +1235,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetRegistrationModeResponse" + "$ref": "#/components/schemas/spin.v1.GetSettingsResponse" } } } @@ -1243,14 +1243,14 @@ } } }, - "/spin.v1.AdminService/GetRunbook": { + "/spin.v1.AdminService/GetStorageSettings": { "post": { "tags": [ "AdminService" ], - "summary": "GetRunbook", - "description": "One runbook, its markdown and where its file is at the pinned commit. NOT_FOUND for an id\n this release's runbooks do not have.", - "operationId": "spin.v1.AdminService.GetRunbook", + "summary": "GetStorageSettings", + "description": "Where the installation's object store is. The secret is never read back.", + "operationId": "spin.v1.AdminService.GetStorageSettings", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1275,7 +1275,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetRunbookRequest" + "$ref": "#/components/schemas/spin.v1.GetStorageSettingsRequest" } } }, @@ -1297,7 +1297,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetRunbookResponse" + "$ref": "#/components/schemas/spin.v1.GetStorageSettingsResponse" } } } @@ -1305,14 +1305,14 @@ } } }, - "/spin.v1.AdminService/GetSecuritySettings": { + "/spin.v1.AdminService/GetStorageUsage": { "post": { "tags": [ "AdminService" ], - "summary": "GetSecuritySettings", - "description": "Get security settings", - "operationId": "spin.v1.AdminService.GetSecuritySettings", + "summary": "GetStorageUsage", + "description": "What the store holds, by what each object is for: every volume's objects and the layers its\n commits name, with the workspace, image or extension release it is. As the storage-gc job\n last read it - daily, or when an admin runs it - never the bucket itself.", + "operationId": "spin.v1.AdminService.GetStorageUsage", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1337,7 +1337,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetSecuritySettingsRequest" + "$ref": "#/components/schemas/spin.v1.GetStorageUsageRequest" } } }, @@ -1359,7 +1359,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetSecuritySettingsResponse" + "$ref": "#/components/schemas/spin.v1.GetStorageUsageResponse" } } } @@ -1367,14 +1367,14 @@ } } }, - "/spin.v1.AdminService/GetStorageSettings": { + "/spin.v1.AdminService/GetTelemetryStatus": { "post": { "tags": [ "AdminService" ], - "summary": "GetStorageSettings", - "description": "Where the installation's object store is. The secret is never read back.", - "operationId": "spin.v1.AdminService.GetStorageSettings", + "summary": "GetTelemetryStatus", + "description": "What the collector has sent and failed to send over its last minute, as the watch on its\n machine read it from the collector itself.", + "operationId": "spin.v1.AdminService.GetTelemetryStatus", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1399,7 +1399,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetStorageSettingsRequest" + "$ref": "#/components/schemas/spin.v1.GetTelemetryStatusRequest" } } }, @@ -1421,7 +1421,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetStorageSettingsResponse" + "$ref": "#/components/schemas/spin.v1.GetTelemetryStatusResponse" } } } @@ -1429,14 +1429,14 @@ } } }, - "/spin.v1.AdminService/GetStorageUsage": { + "/spin.v1.AdminService/GetThirdPartyTerms": { "post": { "tags": [ "AdminService" ], - "summary": "GetStorageUsage", - "description": "What the store holds, by what each object is for: every volume's objects and the layers its\n commits name, with the workspace, image or extension release it is. As the storage-gc job\n last read it - daily, or when an admin runs it - never the bucket itself.", - "operationId": "spin.v1.AdminService.GetStorageUsage", + "summary": "GetThirdPartyTerms", + "description": "The software this installation downloads from its makers, the terms it is used under, and\n which of it an administrator accepted the terms for: who, when, and which text. Nothing is\n downloaded of an item whose terms are not accepted (internal/controlplane/thirdparty).", + "operationId": "spin.v1.AdminService.GetThirdPartyTerms", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1461,7 +1461,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetStorageUsageRequest" + "$ref": "#/components/schemas/spin.v1.GetThirdPartyTermsRequest" } } }, @@ -1483,7 +1483,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetStorageUsageResponse" + "$ref": "#/components/schemas/spin.v1.GetThirdPartyTermsResponse" } } } @@ -1491,14 +1491,14 @@ } } }, - "/spin.v1.AdminService/GetTelemetryStatus": { + "/spin.v1.AdminService/GetUserWorkspaceEgress": { "post": { "tags": [ "AdminService" ], - "summary": "GetTelemetryStatus", - "description": "What the collector has sent and failed to send over its last minute, as the watch on its\n machine read it from the collector itself.", - "operationId": "spin.v1.AdminService.GetTelemetryStatus", + "summary": "GetUserWorkspaceEgress", + "description": "Where a workspace sends, as its owner's GetWorkspaceEgress answers it: the host's counters by\n destination, nothing of what was carried. Audited, as a reading of somebody else's.", + "operationId": "spin.v1.AdminService.GetUserWorkspaceEgress", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1523,7 +1523,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetTelemetryStatusRequest" + "$ref": "#/components/schemas/spin.v1.GetUserWorkspaceEgressRequest" } } }, @@ -1545,7 +1545,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetTelemetryStatusResponse" + "$ref": "#/components/schemas/spin.v1.GetUserWorkspaceEgressResponse" } } } @@ -1553,14 +1553,14 @@ } } }, - "/spin.v1.AdminService/GetThirdPartyTerms": { + "/spin.v1.AdminService/GetVSCodeServers": { "post": { "tags": [ "AdminService" ], - "summary": "GetThirdPartyTerms", - "description": "The software this installation downloads from its makers, the terms it is used under, and\n which of it an administrator accepted the terms for: who, when, and which text. Nothing is\n downloaded of an item whose terms are not accepted (internal/controlplane/thirdparty).", - "operationId": "spin.v1.AdminService.GetThirdPartyTerms", + "summary": "GetVSCodeServers", + "description": "The VS Code servers workspaces are given (the vscode-server extension): each release, and\n the publish this control plane ran since it started, if it ran one.", + "operationId": "spin.v1.AdminService.GetVSCodeServers", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1585,7 +1585,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetThirdPartyTermsRequest" + "$ref": "#/components/schemas/spin.v1.GetVSCodeServersRequest" } } }, @@ -1607,7 +1607,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetThirdPartyTermsResponse" + "$ref": "#/components/schemas/spin.v1.GetVSCodeServersResponse" } } } @@ -1615,14 +1615,14 @@ } } }, - "/spin.v1.AdminService/GetVSCodeServers": { + "/spin.v1.AdminService/GetWorkspaceNames": { "post": { "tags": [ "AdminService" ], - "summary": "GetVSCodeServers", - "description": "The VS Code servers workspaces are given (the vscode-server extension): each release, and\n the publish this control plane ran since it started, if it ran one.", - "operationId": "spin.v1.AdminService.GetVSCodeServers", + "summary": "GetWorkspaceNames", + "description": "The names of the workspaces ids are, whoever owns them and whatever state they are in, a\n deleted one among them: a record of the platform's logs names a workspace by its id, and\n ListWorkspaces is the caller's own. An id the installation no longer holds a row for is\n left out of the answer.", + "operationId": "spin.v1.AdminService.GetWorkspaceNames", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1647,7 +1647,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetVSCodeServersRequest" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceNamesRequest" } } }, @@ -1669,7 +1669,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetVSCodeServersResponse" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceNamesResponse" } } } @@ -1677,14 +1677,14 @@ } } }, - "/spin.v1.AdminService/GetWorkspaceNames": { + "/spin.v1.AdminService/ListAlerts": { "post": { "tags": [ "AdminService" ], - "summary": "GetWorkspaceNames", - "description": "The names of the workspaces ids are, whoever owns them and whatever state they are in, a\n deleted one among them: a record of the platform's logs names a workspace by its id, and\n ListWorkspaces is the caller's own. An id the installation no longer holds a row for is\n left out of the answer.", - "operationId": "spin.v1.AdminService.GetWorkspaceNames", + "summary": "ListAlerts", + "description": "What the release's alert rules said in the installation's Grafana, newest first: each\n firing and each resolution the control plane heard, with its runbook and how many\n administrators it reached.", + "operationId": "spin.v1.AdminService.ListAlerts", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1709,7 +1709,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceNamesRequest" + "$ref": "#/components/schemas/spin.v1.ListAlertsRequest" } } }, @@ -1731,7 +1731,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceNamesResponse" + "$ref": "#/components/schemas/spin.v1.ListAlertsResponse" } } } @@ -1986,14 +1986,14 @@ } } }, - "/spin.v1.AdminService/ListJobRuns": { + "/spin.v1.AdminService/ListHostProblems": { "post": { "tags": [ "AdminService" ], - "summary": "ListJobRuns", - "description": "One job's runs, newest first.", - "operationId": "spin.v1.AdminService.ListJobRuns", + "summary": "ListHostProblems", + "description": "What is wrong with the fleet's hosts, one problem per host that is not connected or fails a\n check of its own: the same problems GetInstallationHealth's HOSTS part lists, for the pages\n that read one host or the fleet and nothing else of the installation.", + "operationId": "spin.v1.AdminService.ListHostProblems", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2018,7 +2018,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListJobRunsRequest" + "$ref": "#/components/schemas/spin.v1.ListHostProblemsRequest" } } }, @@ -2040,7 +2040,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListJobRunsResponse" + "$ref": "#/components/schemas/spin.v1.ListHostProblemsResponse" } } } @@ -2048,14 +2048,14 @@ } } }, - "/spin.v1.AdminService/ListJobs": { + "/spin.v1.AdminService/ListJobRuns": { "post": { "tags": [ "AdminService" ], - "summary": "ListJobs", - "description": "The control plane's periodic work - backups, cleanups, the object store's garbage\n collection - with how often each runs and how its last run went.", - "operationId": "spin.v1.AdminService.ListJobs", + "summary": "ListJobRuns", + "description": "One job's runs, newest first.", + "operationId": "spin.v1.AdminService.ListJobRuns", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2080,7 +2080,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListJobsRequest" + "$ref": "#/components/schemas/spin.v1.ListJobRunsRequest" } } }, @@ -2102,7 +2102,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListJobsResponse" + "$ref": "#/components/schemas/spin.v1.ListJobRunsResponse" } } } @@ -2110,14 +2110,14 @@ } } }, - "/spin.v1.AdminService/ListRekeys": { + "/spin.v1.AdminService/ListJobs": { "post": { "tags": [ "AdminService" ], - "summary": "ListRekeys", - "description": "The disks being re-keyed, and the ones a revoked host's keys marked for it.", - "operationId": "spin.v1.AdminService.ListRekeys", + "summary": "ListJobs", + "description": "The control plane's periodic work - backups, cleanups, the object store's garbage\n collection - with how often each runs and how its last run went.", + "operationId": "spin.v1.AdminService.ListJobs", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2142,7 +2142,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListRekeysRequest" + "$ref": "#/components/schemas/spin.v1.ListJobsRequest" } } }, @@ -2164,7 +2164,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListRekeysResponse" + "$ref": "#/components/schemas/spin.v1.ListJobsResponse" } } } @@ -2172,14 +2172,14 @@ } } }, - "/spin.v1.AdminService/ListResourcePresets": { + "/spin.v1.AdminService/ListRefusedVolumes": { "post": { "tags": [ "AdminService" ], - "summary": "ListResourcePresets", - "description": "List resource presets", - "operationId": "spin.v1.AdminService.ListResourcePresets", + "summary": "ListRefusedVolumes", + "description": "The disks a host refuses to serve, each with the workspace it is the disk of and whose that\n is. Audited.", + "operationId": "spin.v1.AdminService.ListRefusedVolumes", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2204,7 +2204,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListResourcePresetsRequest" + "$ref": "#/components/schemas/spin.v1.ListRefusedVolumesRequest" } } }, @@ -2226,7 +2226,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListResourcePresetsResponse" + "$ref": "#/components/schemas/spin.v1.ListRefusedVolumesResponse" } } } @@ -2234,14 +2234,14 @@ } } }, - "/spin.v1.AdminService/ListRunbooks": { + "/spin.v1.AdminService/ListRekeys": { "post": { "tags": [ "AdminService" ], - "summary": "ListRunbooks", - "description": "What an operator does when an alert fires, a job fails or an owner is told something went\n wrong: spin-stack/runbooks at the commit this release pins, served so it is read in the app.", - "operationId": "spin.v1.AdminService.ListRunbooks", + "summary": "ListRekeys", + "description": "The disks being re-keyed, and the ones a revoked host's keys marked for it.", + "operationId": "spin.v1.AdminService.ListRekeys", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2266,7 +2266,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListRunbooksRequest" + "$ref": "#/components/schemas/spin.v1.ListRekeysRequest" } } }, @@ -2288,7 +2288,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListRunbooksResponse" + "$ref": "#/components/schemas/spin.v1.ListRekeysResponse" } } } @@ -2296,14 +2296,14 @@ } } }, - "/spin.v1.AdminService/ListUserAPIKeys": { + "/spin.v1.AdminService/ListResourcePresets": { "post": { "tags": [ "AdminService" ], - "summary": "ListUserAPIKeys", - "description": "List another user's API keys. The secret is never stored, so this is what an admin can\n know about a key: what it is called, when it was made, when it was last used.", - "operationId": "spin.v1.AdminService.ListUserAPIKeys", + "summary": "ListResourcePresets", + "description": "List resource presets", + "operationId": "spin.v1.AdminService.ListResourcePresets", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2328,7 +2328,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListUserAPIKeysRequest" + "$ref": "#/components/schemas/spin.v1.ListResourcePresetsRequest" } } }, @@ -2350,7 +2350,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListUserAPIKeysResponse" + "$ref": "#/components/schemas/spin.v1.ListResourcePresetsResponse" } } } @@ -2358,14 +2358,14 @@ } } }, - "/spin.v1.AdminService/ListUsers": { + "/spin.v1.AdminService/ListRunbooks": { "post": { "tags": [ "AdminService" ], - "summary": "ListUsers", - "description": "List all users", - "operationId": "spin.v1.AdminService.ListUsers", + "summary": "ListRunbooks", + "description": "What an operator does when an alert fires, a job fails or an owner is told something went\n wrong: spin-stack/runbooks at the commit this release pins, served so it is read in the app.", + "operationId": "spin.v1.AdminService.ListRunbooks", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2390,7 +2390,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListUsersRequest" + "$ref": "#/components/schemas/spin.v1.ListRunbooksRequest" } } }, @@ -2412,7 +2412,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListUsersResponse" + "$ref": "#/components/schemas/spin.v1.ListRunbooksResponse" } } } @@ -2420,14 +2420,14 @@ } } }, - "/spin.v1.AdminService/PublishVSCodeServers": { + "/spin.v1.AdminService/ListTimeline": { "post": { "tags": [ "AdminService" ], - "summary": "PublishVSCodeServers", - "description": "Publish the servers of the newest stable VS Code releases, or of the commits named, as a\n new release. Answers once the publish has begun - it downloads a gigabyte - and\n GetVSCodeServers says how it goes.", - "operationId": "spin.v1.AdminService.PublishVSCodeServers", + "summary": "ListTimeline", + "description": "What happened, newest first, between two instants, to one workspace, host, team or project, or\n to the whole installation: read from the audit log, the workspaces' events, the jobs' failed\n runs and the projects' prebuilds as they are, never copied. Sign-ins and what is done inside a\n workspace (a session, a command) are the audit log's alone: they outnumber everything else.", + "operationId": "spin.v1.AdminService.ListTimeline", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2452,7 +2452,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.PublishVSCodeServersRequest" + "$ref": "#/components/schemas/spin.v1.ListTimelineRequest" } } }, @@ -2474,7 +2474,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.PublishVSCodeServersResponse" + "$ref": "#/components/schemas/spin.v1.ListTimelineResponse" } } } @@ -2482,14 +2482,14 @@ } } }, - "/spin.v1.AdminService/RekeyVolume": { + "/spin.v1.AdminService/ListUserAPIKeys": { "post": { "tags": [ "AdminService" ], - "summary": "RekeyVolume", - "description": "Re-key a workspace's disk: copy it whole under a key of its own, point the workspace at the\n copy, and delete the disk - which shreds the key assumed taken and every snapshot of the disk,\n since those are what that key opens. The workspace must be stopped or quarantined. Refused for\n a disk something descends from. Audited.", - "operationId": "spin.v1.AdminService.RekeyVolume", + "summary": "ListUserAPIKeys", + "description": "List another user's API keys. The secret is never stored, so this is what an admin can\n know about a key: what it is called, when it was made, when it was last used.", + "operationId": "spin.v1.AdminService.ListUserAPIKeys", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2514,7 +2514,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RekeyVolumeRequest" + "$ref": "#/components/schemas/spin.v1.ListUserAPIKeysRequest" } } }, @@ -2536,7 +2536,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RekeyVolumeResponse" + "$ref": "#/components/schemas/spin.v1.ListUserAPIKeysResponse" } } } @@ -2544,14 +2544,14 @@ } } }, - "/spin.v1.AdminService/RemoveAllowedEmail": { + "/spin.v1.AdminService/ListUsers": { "post": { "tags": [ "AdminService" ], - "summary": "RemoveAllowedEmail", - "description": "Remove allowed email/domain", - "operationId": "spin.v1.AdminService.RemoveAllowedEmail", + "summary": "ListUsers", + "description": "List all users", + "operationId": "spin.v1.AdminService.ListUsers", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2576,7 +2576,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RemoveAllowedEmailRequest" + "$ref": "#/components/schemas/spin.v1.ListUsersRequest" } } }, @@ -2598,7 +2598,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RemoveAllowedEmailResponse" + "$ref": "#/components/schemas/spin.v1.ListUsersResponse" } } } @@ -2606,14 +2606,14 @@ } } }, - "/spin.v1.AdminService/RemoveStoredVolume": { + "/spin.v1.AdminService/PublishVSCodeServers": { "post": { "tags": [ "AdminService" ], - "summary": "RemoveStoredVolume", - "description": "Remove an image, an extension release, an unclaimed volume or an orphan from the store: its\n row, then its volume, whose key is shredded; storage-gc collects its layers on its next run.\n Refused for one that is kept (StoredVolume.kept_because), one placed on a host, and a\n workspace's disk. Audited.", - "operationId": "spin.v1.AdminService.RemoveStoredVolume", + "summary": "PublishVSCodeServers", + "description": "Publish the servers of the newest stable VS Code releases, or of the commits named, as a\n new release. Answers once the publish has begun - it downloads a gigabyte - and\n GetVSCodeServers says how it goes.", + "operationId": "spin.v1.AdminService.PublishVSCodeServers", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2638,7 +2638,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RemoveStoredVolumeRequest" + "$ref": "#/components/schemas/spin.v1.PublishVSCodeServersRequest" } } }, @@ -2660,7 +2660,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RemoveStoredVolumeResponse" + "$ref": "#/components/schemas/spin.v1.PublishVSCodeServersResponse" } } } @@ -2668,14 +2668,14 @@ } } }, - "/spin.v1.AdminService/RetryPlatformImages": { + "/spin.v1.AdminService/RecoverUserWorkspace": { "post": { "tags": [ "AdminService" ], - "summary": "RetryPlatformImages", - "description": "Look again now rather than when the next retry is due.", - "operationId": "spin.v1.AdminService.RetryPlatformImages", + "summary": "RecoverUserWorkspace", + "description": "Move a workspace off a host that is gone, as its owner's RecoverWorkspace does, and with the\n same question first: without accept_data_loss it answers what the move would give up and\n changes nothing. The work given up is its owner's, so a reason is required, kept on the audit\n entry, and written with who asked on the workspace's history, which its owner reads\n (WORKSPACE_EVENT_TYPE_RECOVERED_BY_ADMIN). Refused for a workspace held in quarantine.", + "operationId": "spin.v1.AdminService.RecoverUserWorkspace", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2700,7 +2700,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RetryPlatformImagesRequest" + "$ref": "#/components/schemas/spin.v1.RecoverUserWorkspaceRequest" } } }, @@ -2722,7 +2722,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RetryPlatformImagesResponse" + "$ref": "#/components/schemas/spin.v1.RecoverUserWorkspaceResponse" } } } @@ -2730,14 +2730,14 @@ } } }, - "/spin.v1.AdminService/RevokeThirdPartyTerms": { + "/spin.v1.AdminService/RekeyVolume": { "post": { "tags": [ "AdminService" ], - "summary": "RevokeThirdPartyTerms", - "description": "Take the acceptance back for the items named: nothing more of them is downloaded. What was\n downloaded already stays until an administrator removes it.", - "operationId": "spin.v1.AdminService.RevokeThirdPartyTerms", + "summary": "RekeyVolume", + "description": "Re-key a workspace's disk: copy it whole under a key of its own, point the workspace at the\n copy, and delete the disk - which shreds the key assumed taken and every snapshot of the disk,\n since those are what that key opens. The workspace must be stopped or quarantined. Refused for\n a disk something descends from. Audited.", + "operationId": "spin.v1.AdminService.RekeyVolume", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2762,7 +2762,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeThirdPartyTermsRequest" + "$ref": "#/components/schemas/spin.v1.RekeyVolumeRequest" } } }, @@ -2784,7 +2784,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeThirdPartyTermsResponse" + "$ref": "#/components/schemas/spin.v1.RekeyVolumeResponse" } } } @@ -2792,14 +2792,14 @@ } } }, - "/spin.v1.AdminService/RevokeUserAPIKey": { + "/spin.v1.AdminService/RemoveAllowedEmail": { "post": { "tags": [ "AdminService" ], - "summary": "RevokeUserAPIKey", - "description": "Revoke another user's API key - the offboarding an admin cannot do by asking the user,\n who may already be gone. It is audited with the admin who did it.", - "operationId": "spin.v1.AdminService.RevokeUserAPIKey", + "summary": "RemoveAllowedEmail", + "description": "Remove allowed email/domain", + "operationId": "spin.v1.AdminService.RemoveAllowedEmail", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2824,7 +2824,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeUserAPIKeyRequest" + "$ref": "#/components/schemas/spin.v1.RemoveAllowedEmailRequest" } } }, @@ -2846,7 +2846,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeUserAPIKeyResponse" + "$ref": "#/components/schemas/spin.v1.RemoveAllowedEmailResponse" } } } @@ -2854,14 +2854,14 @@ } } }, - "/spin.v1.AdminService/RunJobNow": { + "/spin.v1.AdminService/RemoveStoredVolume": { "post": { "tags": [ "AdminService" ], - "summary": "RunJobNow", - "description": "Run a job now rather than when it is next due. Refused while it is running: a second run\n alongside the first would do the same work twice. Audited with the admin who asked.", - "operationId": "spin.v1.AdminService.RunJobNow", + "summary": "RemoveStoredVolume", + "description": "Remove an image, an extension release, an unclaimed volume or an orphan from the store: its\n row, then its volume, whose key is shredded; storage-gc collects its layers on its next run.\n Refused for one that is kept (StoredVolume.kept_because), one placed on a host, and a\n workspace's disk. Audited.", + "operationId": "spin.v1.AdminService.RemoveStoredVolume", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2886,7 +2886,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RunJobNowRequest" + "$ref": "#/components/schemas/spin.v1.RemoveStoredVolumeRequest" } } }, @@ -2908,7 +2908,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RunJobNowResponse" + "$ref": "#/components/schemas/spin.v1.RemoveStoredVolumeResponse" } } } @@ -2916,14 +2916,14 @@ } } }, - "/spin.v1.AdminService/SetRegistrationMode": { + "/spin.v1.AdminService/RetryPlatformImages": { "post": { "tags": [ "AdminService" ], - "summary": "SetRegistrationMode", - "description": "Set registration mode", - "operationId": "spin.v1.AdminService.SetRegistrationMode", + "summary": "RetryPlatformImages", + "description": "Look again now rather than when the next retry is due.", + "operationId": "spin.v1.AdminService.RetryPlatformImages", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2948,7 +2948,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SetRegistrationModeRequest" + "$ref": "#/components/schemas/spin.v1.RetryPlatformImagesRequest" } } }, @@ -2970,7 +2970,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SetRegistrationModeResponse" + "$ref": "#/components/schemas/spin.v1.RetryPlatformImagesResponse" } } } @@ -2978,14 +2978,14 @@ } } }, - "/spin.v1.AdminService/UntagImage": { + "/spin.v1.AdminService/RevokeThirdPartyTerms": { "post": { "tags": [ "AdminService" ], - "summary": "UntagImage", - "description": "Take a ref off what it names: no new workspace gets those bytes by it, the disks cloned from\n them go on reading them, and a later publish under the ref tags the new bytes. Audited.", - "operationId": "spin.v1.AdminService.UntagImage", + "summary": "RevokeThirdPartyTerms", + "description": "Take the acceptance back for the items named: nothing more of them is downloaded. What was\n downloaded already stays until an administrator removes it.", + "operationId": "spin.v1.AdminService.RevokeThirdPartyTerms", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3010,7 +3010,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UntagImageRequest" + "$ref": "#/components/schemas/spin.v1.RevokeThirdPartyTermsRequest" } } }, @@ -3032,7 +3032,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UntagImageResponse" + "$ref": "#/components/schemas/spin.v1.RevokeThirdPartyTermsResponse" } } } @@ -3040,14 +3040,14 @@ } } }, - "/spin.v1.AdminService/UpdateEmailSettings": { + "/spin.v1.AdminService/RevokeUserAPIKey": { "post": { "tags": [ "AdminService" ], - "summary": "UpdateEmailSettings", - "description": "Set the SMTP server, checked against it - connected to and signed in to - before it is\n written. An empty host turns email off.", - "operationId": "spin.v1.AdminService.UpdateEmailSettings", + "summary": "RevokeUserAPIKey", + "description": "Revoke another user's API key - the offboarding an admin cannot do by asking the user,\n who may already be gone. It is audited with the admin who did it.", + "operationId": "spin.v1.AdminService.RevokeUserAPIKey", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3072,7 +3072,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateEmailSettingsRequest" + "$ref": "#/components/schemas/spin.v1.RevokeUserAPIKeyRequest" } } }, @@ -3094,7 +3094,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateEmailSettingsResponse" + "$ref": "#/components/schemas/spin.v1.RevokeUserAPIKeyResponse" } } } @@ -3102,13 +3102,14 @@ } } }, - "/spin.v1.AdminService/UpdateHostClass": { + "/spin.v1.AdminService/RunJobNow": { "post": { "tags": [ "AdminService" ], - "summary": "UpdateHostClass", - "operationId": "spin.v1.AdminService.UpdateHostClass", + "summary": "RunJobNow", + "description": "Run a job now rather than when it is next due. Refused while it is running: a second run\n alongside the first would do the same work twice. Audited with the admin who asked.", + "operationId": "spin.v1.AdminService.RunJobNow", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3133,7 +3134,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateHostClassRequest" + "$ref": "#/components/schemas/spin.v1.RunJobNowRequest" } } }, @@ -3155,7 +3156,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateHostClassResponse" + "$ref": "#/components/schemas/spin.v1.RunJobNowResponse" } } } @@ -3163,14 +3164,14 @@ } } }, - "/spin.v1.AdminService/UpdateInstallationSettings": { + "/spin.v1.AdminService/SendTestAlert": { "post": { "tags": [ "AdminService" ], - "summary": "UpdateInstallationSettings", - "description": "Update installation settings", - "operationId": "spin.v1.AdminService.UpdateInstallationSettings", + "summary": "SendTestAlert", + "description": "Has Grafana test its contact point, which sends a test alert the whole way an alert goes:\n Grafana, the control plane, an email to every administrator who has not opted out.\n FAILED_PRECONDITION where this control plane serves no Grafana, or Grafana could not\n reach the control plane.", + "operationId": "spin.v1.AdminService.SendTestAlert", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3195,7 +3196,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateInstallationSettingsRequest" + "$ref": "#/components/schemas/spin.v1.SendTestAlertRequest" } } }, @@ -3217,7 +3218,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateInstallationSettingsResponse" + "$ref": "#/components/schemas/spin.v1.SendTestAlertResponse" } } } @@ -3225,13 +3226,14 @@ } } }, - "/spin.v1.AdminService/UpdateNetworkPolicy": { + "/spin.v1.AdminService/SetSettings": { "post": { "tags": [ "AdminService" ], - "summary": "UpdateNetworkPolicy", - "operationId": "spin.v1.AdminService.UpdateNetworkPolicy", + "summary": "SetSettings", + "description": "Writes the settings named, each checked by its definition and all of them together before\n any is written: a refused one writes nothing.", + "operationId": "spin.v1.AdminService.SetSettings", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3256,7 +3258,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateNetworkPolicyRequest" + "$ref": "#/components/schemas/spin.v1.SetSettingsRequest" } } }, @@ -3278,7 +3280,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateNetworkPolicyResponse" + "$ref": "#/components/schemas/spin.v1.SetSettingsResponse" } } } @@ -3286,14 +3288,14 @@ } } }, - "/spin.v1.AdminService/UpdateResourcePreset": { + "/spin.v1.AdminService/StopUserWorkspace": { "post": { "tags": [ "AdminService" ], - "summary": "UpdateResourcePreset", - "description": "Update a resource preset", - "operationId": "spin.v1.AdminService.UpdateResourcePreset", + "summary": "StopUserWorkspace", + "description": "Stop a workspace, as its owner's StopWorkspace does: one whose stop could not publish its\n disk runs on and holds its host until somebody stops it. Audited.", + "operationId": "spin.v1.AdminService.StopUserWorkspace", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3318,7 +3320,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateResourcePresetRequest" + "$ref": "#/components/schemas/spin.v1.StopUserWorkspaceRequest" } } }, @@ -3340,7 +3342,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateResourcePresetResponse" + "$ref": "#/components/schemas/spin.v1.StopUserWorkspaceResponse" } } } @@ -3348,14 +3350,14 @@ } } }, - "/spin.v1.AdminService/UpdateSecuritySettings": { + "/spin.v1.AdminService/UntagImage": { "post": { "tags": [ "AdminService" ], - "summary": "UpdateSecuritySettings", - "description": "Update security settings", - "operationId": "spin.v1.AdminService.UpdateSecuritySettings", + "summary": "UntagImage", + "description": "Take a ref off what it names: no new workspace gets those bytes by it, the disks cloned from\n them go on reading them, and a later publish under the ref tags the new bytes. Audited.", + "operationId": "spin.v1.AdminService.UntagImage", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3380,7 +3382,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateSecuritySettingsRequest" + "$ref": "#/components/schemas/spin.v1.UntagImageRequest" } } }, @@ -3402,7 +3404,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateSecuritySettingsResponse" + "$ref": "#/components/schemas/spin.v1.UntagImageResponse" } } } @@ -3410,14 +3412,14 @@ } } }, - "/spin.v1.AdminService/UpdateStorageSettings": { + "/spin.v1.AdminService/UpdateEmailSettings": { "post": { "tags": [ "AdminService" ], - "summary": "UpdateStorageSettings", - "description": "Set where the object store is, checked against it before it is written; every control\n plane restarts within seconds to open it. Another store while volumes exist is refused.", - "operationId": "spin.v1.AdminService.UpdateStorageSettings", + "summary": "UpdateEmailSettings", + "description": "Set the SMTP server, checked against it - connected to and signed in to - before it is\n written. An empty host turns email off.", + "operationId": "spin.v1.AdminService.UpdateEmailSettings", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3442,7 +3444,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateStorageSettingsRequest" + "$ref": "#/components/schemas/spin.v1.UpdateEmailSettingsRequest" } } }, @@ -3464,7 +3466,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateStorageSettingsResponse" + "$ref": "#/components/schemas/spin.v1.UpdateEmailSettingsResponse" } } } @@ -3472,14 +3474,13 @@ } } }, - "/spin.v1.AdminService/UpdateUser": { + "/spin.v1.AdminService/UpdateHostClass": { "post": { "tags": [ "AdminService" ], - "summary": "UpdateUser", - "description": "Update user (can toggle is_instance_admin, disable user)", - "operationId": "spin.v1.AdminService.UpdateUser", + "summary": "UpdateHostClass", + "operationId": "spin.v1.AdminService.UpdateHostClass", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3504,7 +3505,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateUserRequest" + "$ref": "#/components/schemas/spin.v1.UpdateHostClassRequest" } } }, @@ -3526,7 +3527,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateUserResponse" + "$ref": "#/components/schemas/spin.v1.UpdateHostClassResponse" } } } @@ -3534,13 +3535,13 @@ } } }, - "/spin.v1.AuthService/ApproveWorkspaceSignIn": { + "/spin.v1.AdminService/UpdateNetworkPolicy": { "post": { "tags": [ - "AuthService" + "AdminService" ], - "summary": "ApproveWorkspaceSignIn", - "operationId": "spin.v1.AuthService.ApproveWorkspaceSignIn", + "summary": "UpdateNetworkPolicy", + "operationId": "spin.v1.AdminService.UpdateNetworkPolicy", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3565,7 +3566,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ApproveWorkspaceSignInRequest" + "$ref": "#/components/schemas/spin.v1.UpdateNetworkPolicyRequest" } } }, @@ -3587,7 +3588,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ApproveWorkspaceSignInResponse" + "$ref": "#/components/schemas/spin.v1.UpdateNetworkPolicyResponse" } } } @@ -3595,14 +3596,14 @@ } } }, - "/spin.v1.AuthService/BeginWorkspaceSignIn": { + "/spin.v1.AdminService/UpdateResourcePreset": { "post": { "tags": [ - "AuthService" + "AdminService" ], - "summary": "BeginWorkspaceSignIn", - "description": "A sign-in on a workspace's host, done by the dashboard. The proxy begins it and sends the\n browser to the dashboard, which approves it for whoever is signed in there and sends the\n browser back with a one-time code; the proxy completes it with that code and the binding\n it gave the same browser. The identity provider is only ever told the dashboard's callback.", - "operationId": "spin.v1.AuthService.BeginWorkspaceSignIn", + "summary": "UpdateResourcePreset", + "description": "Update a resource preset", + "operationId": "spin.v1.AdminService.UpdateResourcePreset", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3627,7 +3628,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.BeginWorkspaceSignInRequest" + "$ref": "#/components/schemas/spin.v1.UpdateResourcePresetRequest" } } }, @@ -3649,7 +3650,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.BeginWorkspaceSignInResponse" + "$ref": "#/components/schemas/spin.v1.UpdateResourcePresetResponse" } } } @@ -3657,14 +3658,14 @@ } } }, - "/spin.v1.AuthService/CheckDeviceLogin": { + "/spin.v1.AdminService/UpdateStorageSettings": { "post": { "tags": [ - "AuthService" + "AdminService" ], - "summary": "CheckDeviceLogin", - "description": "Check device login status (CLI polls this)\n Returns session token once user has completed login and entered the code", - "operationId": "spin.v1.AuthService.CheckDeviceLogin", + "summary": "UpdateStorageSettings", + "description": "Set where the object store is, checked against it before it is written; every control\n plane restarts within seconds to open it. Another store while volumes exist is refused.", + "operationId": "spin.v1.AdminService.UpdateStorageSettings", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3689,7 +3690,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CheckDeviceLoginRequest" + "$ref": "#/components/schemas/spin.v1.UpdateStorageSettingsRequest" } } }, @@ -3711,7 +3712,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CheckDeviceLoginResponse" + "$ref": "#/components/schemas/spin.v1.UpdateStorageSettingsResponse" } } } @@ -3719,14 +3720,14 @@ } } }, - "/spin.v1.AuthService/CompleteLogin": { + "/spin.v1.AdminService/UpdateUser": { "post": { "tags": [ - "AuthService" + "AdminService" ], - "summary": "CompleteLogin", - "description": "Complete login (callback from IdP)", - "operationId": "spin.v1.AuthService.CompleteLogin", + "summary": "UpdateUser", + "description": "Update user (can toggle is_instance_admin, disable user)", + "operationId": "spin.v1.AdminService.UpdateUser", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3751,7 +3752,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CompleteLoginRequest" + "$ref": "#/components/schemas/spin.v1.UpdateUserRequest" } } }, @@ -3773,7 +3774,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CompleteLoginResponse" + "$ref": "#/components/schemas/spin.v1.UpdateUserResponse" } } } @@ -3781,13 +3782,13 @@ } } }, - "/spin.v1.AuthService/CompleteWorkspaceSignIn": { + "/spin.v1.AuthService/ApproveWorkspaceSignIn": { "post": { "tags": [ "AuthService" ], - "summary": "CompleteWorkspaceSignIn", - "operationId": "spin.v1.AuthService.CompleteWorkspaceSignIn", + "summary": "ApproveWorkspaceSignIn", + "operationId": "spin.v1.AuthService.ApproveWorkspaceSignIn", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3812,7 +3813,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CompleteWorkspaceSignInRequest" + "$ref": "#/components/schemas/spin.v1.ApproveWorkspaceSignInRequest" } } }, @@ -3834,7 +3835,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CompleteWorkspaceSignInResponse" + "$ref": "#/components/schemas/spin.v1.ApproveWorkspaceSignInResponse" } } } @@ -3842,14 +3843,14 @@ } } }, - "/spin.v1.AuthService/ConfirmDeviceLogin": { + "/spin.v1.AuthService/BeginWorkspaceSignIn": { "post": { "tags": [ "AuthService" ], - "summary": "ConfirmDeviceLogin", - "description": "Complete device login (dashboard calls this after user enters code)\n Requires authentication - links the device code to the current user", - "operationId": "spin.v1.AuthService.ConfirmDeviceLogin", + "summary": "BeginWorkspaceSignIn", + "description": "A sign-in on a workspace's host, done by the dashboard. The proxy begins it and sends the\n browser to the dashboard, which approves it for whoever is signed in there and sends the\n browser back with a one-time code; the proxy completes it with that code and the binding\n it gave the same browser. The identity provider is only ever told the dashboard's callback.", + "operationId": "spin.v1.AuthService.BeginWorkspaceSignIn", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3874,7 +3875,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ConfirmDeviceLoginRequest" + "$ref": "#/components/schemas/spin.v1.BeginWorkspaceSignInRequest" } } }, @@ -3896,7 +3897,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ConfirmDeviceLoginResponse" + "$ref": "#/components/schemas/spin.v1.BeginWorkspaceSignInResponse" } } } @@ -3904,14 +3905,14 @@ } } }, - "/spin.v1.AuthService/CreateAPIKey": { + "/spin.v1.AuthService/CheckDeviceLogin": { "post": { "tags": [ "AuthService" ], - "summary": "CreateAPIKey", - "description": "Create API key", - "operationId": "spin.v1.AuthService.CreateAPIKey", + "summary": "CheckDeviceLogin", + "description": "Check device login status (CLI polls this)\n Returns session token once user has completed login and entered the code", + "operationId": "spin.v1.AuthService.CheckDeviceLogin", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3936,7 +3937,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CreateAPIKeyRequest" + "$ref": "#/components/schemas/spin.v1.CheckDeviceLoginRequest" } } }, @@ -3958,7 +3959,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CreateAPIKeyResponse" + "$ref": "#/components/schemas/spin.v1.CheckDeviceLoginResponse" } } } @@ -3966,14 +3967,14 @@ } } }, - "/spin.v1.AuthService/ExchangeWorkloadToken": { + "/spin.v1.AuthService/CompleteLogin": { "post": { "tags": [ "AuthService" ], - "summary": "ExchangeWorkloadToken", - "description": "Exchanges a workload's JWT-SVID, for the control plane's audience (identity.ControlPlaneAudience),\n for a key delegated from the key that made its workspace: what an agent in a workspace drives\n others with. Verified by go-spiffe against the trust domain's bundle; the key holds no more than\n its parent (delegation.Within), lasts no longer than the token's workload needs, and goes with the\n workspace.", - "operationId": "spin.v1.AuthService.ExchangeWorkloadToken", + "summary": "CompleteLogin", + "description": "Complete login (callback from IdP)", + "operationId": "spin.v1.AuthService.CompleteLogin", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3998,7 +3999,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ExchangeWorkloadTokenRequest" + "$ref": "#/components/schemas/spin.v1.CompleteLoginRequest" } } }, @@ -4020,7 +4021,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ExchangeWorkloadTokenResponse" + "$ref": "#/components/schemas/spin.v1.CompleteLoginResponse" } } } @@ -4028,14 +4029,13 @@ } } }, - "/spin.v1.AuthService/GetCurrentUser": { + "/spin.v1.AuthService/CompleteWorkspaceSignIn": { "post": { "tags": [ "AuthService" ], - "summary": "GetCurrentUser", - "description": "Get current user info", - "operationId": "spin.v1.AuthService.GetCurrentUser", + "summary": "CompleteWorkspaceSignIn", + "operationId": "spin.v1.AuthService.CompleteWorkspaceSignIn", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4060,7 +4060,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetCurrentUserRequest" + "$ref": "#/components/schemas/spin.v1.CompleteWorkspaceSignInRequest" } } }, @@ -4082,7 +4082,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetCurrentUserResponse" + "$ref": "#/components/schemas/spin.v1.CompleteWorkspaceSignInResponse" } } } @@ -4090,14 +4090,14 @@ } } }, - "/spin.v1.AuthService/ListAPIKeys": { + "/spin.v1.AuthService/ConfirmDeviceLogin": { "post": { "tags": [ "AuthService" ], - "summary": "ListAPIKeys", - "description": "List API keys", - "operationId": "spin.v1.AuthService.ListAPIKeys", + "summary": "ConfirmDeviceLogin", + "description": "Complete device login (dashboard calls this after user enters code)\n Requires authentication - links the device code to the current user", + "operationId": "spin.v1.AuthService.ConfirmDeviceLogin", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4122,7 +4122,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListAPIKeysRequest" + "$ref": "#/components/schemas/spin.v1.ConfirmDeviceLoginRequest" } } }, @@ -4144,7 +4144,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListAPIKeysResponse" + "$ref": "#/components/schemas/spin.v1.ConfirmDeviceLoginResponse" } } } @@ -4152,14 +4152,14 @@ } } }, - "/spin.v1.AuthService/ListIdentityProviders": { + "/spin.v1.AuthService/CreateAPIKey": { "post": { "tags": [ "AuthService" ], - "summary": "ListIdentityProviders", - "description": "List available identity providers (for login page)\n Always includes built-in GitHub provider; additional OIDC providers from database", - "operationId": "spin.v1.AuthService.ListIdentityProviders", + "summary": "CreateAPIKey", + "description": "Create API key", + "operationId": "spin.v1.AuthService.CreateAPIKey", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4184,7 +4184,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListIdentityProvidersRequest" + "$ref": "#/components/schemas/spin.v1.CreateAPIKeyRequest" } } }, @@ -4206,7 +4206,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListIdentityProvidersResponse" + "$ref": "#/components/schemas/spin.v1.CreateAPIKeyResponse" } } } @@ -4214,14 +4214,14 @@ } } }, - "/spin.v1.AuthService/Logout": { + "/spin.v1.AuthService/ExchangeWorkloadToken": { "post": { "tags": [ "AuthService" ], - "summary": "Logout", - "description": "Logout (invalidate session)", - "operationId": "spin.v1.AuthService.Logout", + "summary": "ExchangeWorkloadToken", + "description": "Exchanges a workload's JWT-SVID, for the control plane's audience (identity.ControlPlaneAudience),\n for a key delegated from the key that made its workspace: what an agent in a workspace drives\n others with. Verified by go-spiffe against the trust domain's bundle; the key holds no more than\n its parent (delegation.Within), lasts no longer than the token's workload needs, and goes with the\n workspace.", + "operationId": "spin.v1.AuthService.ExchangeWorkloadToken", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4246,7 +4246,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.LogoutRequest" + "$ref": "#/components/schemas/spin.v1.ExchangeWorkloadTokenRequest" } } }, @@ -4268,7 +4268,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.LogoutResponse" + "$ref": "#/components/schemas/spin.v1.ExchangeWorkloadTokenResponse" } } } @@ -4276,14 +4276,14 @@ } } }, - "/spin.v1.AuthService/RevokeAPIKey": { + "/spin.v1.AuthService/GetCurrentUser": { "post": { "tags": [ "AuthService" ], - "summary": "RevokeAPIKey", - "description": "Revoke API key", - "operationId": "spin.v1.AuthService.RevokeAPIKey", + "summary": "GetCurrentUser", + "description": "Get current user info", + "operationId": "spin.v1.AuthService.GetCurrentUser", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4308,7 +4308,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeAPIKeyRequest" + "$ref": "#/components/schemas/spin.v1.GetCurrentUserRequest" } } }, @@ -4330,7 +4330,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeAPIKeyResponse" + "$ref": "#/components/schemas/spin.v1.GetCurrentUserResponse" } } } @@ -4338,14 +4338,262 @@ } } }, - "/spin.v1.AuthService/SearchUsers": { + "/spin.v1.AuthService/ListAPIKeys": { "post": { "tags": [ "AuthService" ], - "summary": "SearchUsers", - "description": "Search users by name or email (for team member selection, workspace sharing)", - "operationId": "spin.v1.AuthService.SearchUsers", + "summary": "ListAPIKeys", + "description": "List API keys", + "operationId": "spin.v1.AuthService.ListAPIKeys", + "parameters": [ + { + "name": "Connect-Protocol-Version", + "in": "header", + "description": "Define the version of the Connect protocol", + "schema": { + "$ref": "#/components/schemas/connect-protocol-version" + }, + "example": 1 + }, + { + "name": "Connect-Timeout-Ms", + "in": "header", + "description": "Define the timeout, in ms", + "schema": { + "$ref": "#/components/schemas/connect-timeout-header" + }, + "example": 1000 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.ListAPIKeysRequest" + } + } + }, + "required": true + }, + "responses": { + "default": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/connect.error" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.ListAPIKeysResponse" + } + } + } + } + } + } + }, + "/spin.v1.AuthService/ListIdentityProviders": { + "post": { + "tags": [ + "AuthService" + ], + "summary": "ListIdentityProviders", + "description": "List available identity providers (for login page)\n Always includes built-in GitHub provider; additional OIDC providers from database", + "operationId": "spin.v1.AuthService.ListIdentityProviders", + "parameters": [ + { + "name": "Connect-Protocol-Version", + "in": "header", + "description": "Define the version of the Connect protocol", + "schema": { + "$ref": "#/components/schemas/connect-protocol-version" + }, + "example": 1 + }, + { + "name": "Connect-Timeout-Ms", + "in": "header", + "description": "Define the timeout, in ms", + "schema": { + "$ref": "#/components/schemas/connect-timeout-header" + }, + "example": 1000 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.ListIdentityProvidersRequest" + } + } + }, + "required": true + }, + "responses": { + "default": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/connect.error" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.ListIdentityProvidersResponse" + } + } + } + } + } + } + }, + "/spin.v1.AuthService/Logout": { + "post": { + "tags": [ + "AuthService" + ], + "summary": "Logout", + "description": "Logout (invalidate session)", + "operationId": "spin.v1.AuthService.Logout", + "parameters": [ + { + "name": "Connect-Protocol-Version", + "in": "header", + "description": "Define the version of the Connect protocol", + "schema": { + "$ref": "#/components/schemas/connect-protocol-version" + }, + "example": 1 + }, + { + "name": "Connect-Timeout-Ms", + "in": "header", + "description": "Define the timeout, in ms", + "schema": { + "$ref": "#/components/schemas/connect-timeout-header" + }, + "example": 1000 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.LogoutRequest" + } + } + }, + "required": true + }, + "responses": { + "default": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/connect.error" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.LogoutResponse" + } + } + } + } + } + } + }, + "/spin.v1.AuthService/RevokeAPIKey": { + "post": { + "tags": [ + "AuthService" + ], + "summary": "RevokeAPIKey", + "description": "Revoke API key", + "operationId": "spin.v1.AuthService.RevokeAPIKey", + "parameters": [ + { + "name": "Connect-Protocol-Version", + "in": "header", + "description": "Define the version of the Connect protocol", + "schema": { + "$ref": "#/components/schemas/connect-protocol-version" + }, + "example": 1 + }, + { + "name": "Connect-Timeout-Ms", + "in": "header", + "description": "Define the timeout, in ms", + "schema": { + "$ref": "#/components/schemas/connect-timeout-header" + }, + "example": 1000 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.RevokeAPIKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "default": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/connect.error" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.RevokeAPIKeyResponse" + } + } + } + } + } + } + }, + "/spin.v1.AuthService/SearchUsers": { + "post": { + "tags": [ + "AuthService" + ], + "summary": "SearchUsers", + "description": "Search users by name or email (for team member selection, workspace sharing)", + "operationId": "spin.v1.AuthService.SearchUsers", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5828,7 +6076,7 @@ "HostService" ], "summary": "RemoveHost", - "description": "Takes a machine of an autoscaling group out of the fleet (admin only), as Host.removal says:\n given back to its group (GIVE_BACK), or forgotten (FORGET). A host whose removal is REVOKE is\n refused: RevokeRunner is its removal.", + "description": "Takes a machine of an autoscaling group out of the fleet (admin only), as Host.removal says:\n given back to its group (GIVE_BACK), or forgotten (FORGET). A host whose removal is REVOKE is\n refused: RevokeRunner is its removal. Asked with taken, the host leaves as one believed\n compromised: its credentials revoked and every team's disk whose key it was given marked for\n re-keying (ListRekeys), as RevokeRunner does, and its machine given back all the same.", "operationId": "spin.v1.HostService.RemoveHost", "parameters": [ { @@ -6565,14 +6813,14 @@ } } }, - "/spin.v1.LogService/ListLogIndexes": { + "/spin.v1.LogService/KeptTraces": { "post": { "tags": [ "LogService" ], - "summary": "ListLogIndexes", - "description": "ListLogIndexes is every index the store keeps, as the store itself reports it: its fields,\n how long it keeps what it holds and how much it holds. An administrator's: how much each\n index holds is how busy the installation and its workspaces are.", - "operationId": "spin.v1.LogService.ListLogIndexes", + "summary": "KeptTraces", + "description": "KeptTraces is which of the trace ids a page shows the store holds: those, and only those,\n are links. A trace id is written where its span began, before the collector decides whether\n to keep the trace, and it stays after the store's retention has deleted it.", + "operationId": "spin.v1.LogService.KeptTraces", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6597,7 +6845,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListLogIndexesRequest" + "$ref": "#/components/schemas/spin.v1.KeptTracesRequest" } } }, @@ -6619,7 +6867,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListLogIndexesResponse" + "$ref": "#/components/schemas/spin.v1.KeptTracesResponse" } } } @@ -6627,7 +6875,69 @@ } } }, - "/spin.v1.LogService/PlatformLogFieldValues": { + "/spin.v1.LogService/ListLogIndexes": { + "post": { + "tags": [ + "LogService" + ], + "summary": "ListLogIndexes", + "description": "ListLogIndexes is every index the store keeps, as the store itself reports it: its fields,\n how long it keeps what it holds and how much it holds. An administrator's: how much each\n index holds is how busy the installation and its workspaces are.", + "operationId": "spin.v1.LogService.ListLogIndexes", + "parameters": [ + { + "name": "Connect-Protocol-Version", + "in": "header", + "description": "Define the version of the Connect protocol", + "schema": { + "$ref": "#/components/schemas/connect-protocol-version" + }, + "example": 1 + }, + { + "name": "Connect-Timeout-Ms", + "in": "header", + "description": "Define the timeout, in ms", + "schema": { + "$ref": "#/components/schemas/connect-timeout-header" + }, + "example": 1000 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.ListLogIndexesRequest" + } + } + }, + "required": true + }, + "responses": { + "default": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/connect.error" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.ListLogIndexesResponse" + } + } + } + } + } + } + }, + "/spin.v1.LogService/PlatformLogFieldValues": { "post": { "tags": [ "LogService" @@ -7553,6 +7863,68 @@ } } }, + "/spin.v1.ProjectService/GetProjectCosts": { + "post": { + "tags": [ + "ProjectService" + ], + "summary": "GetProjectCosts", + "description": "What a project cost in the month in progress, to its admins and nobody else, as\n ListProjectWorkspaces: everybody's workspaces of it summed, its prebuilds' builds included,\n and a month of what its prebuilds keep. A sum, never by workspace: one workspace's cost says\n how much its owner works, which a project's admin who is not their team's is not told. Read\n from the bill as the installation last read it, never from the cloud.", + "operationId": "spin.v1.ProjectService.GetProjectCosts", + "parameters": [ + { + "name": "Connect-Protocol-Version", + "in": "header", + "description": "Define the version of the Connect protocol", + "schema": { + "$ref": "#/components/schemas/connect-protocol-version" + }, + "example": 1 + }, + { + "name": "Connect-Timeout-Ms", + "in": "header", + "description": "Define the timeout, in ms", + "schema": { + "$ref": "#/components/schemas/connect-timeout-header" + }, + "example": 1000 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.GetProjectCostsRequest" + } + } + }, + "required": true + }, + "responses": { + "default": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/connect.error" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.GetProjectCostsResponse" + } + } + } + } + } + } + }, "/spin.v1.ProjectService/ListPrebuilds": { "post": { "tags": [ @@ -8362,7 +8734,7 @@ "SettingsService" ], "summary": "GetNotificationPreferences", - "description": "Which of those the caller is emailed about.", + "description": "Which of those the caller is emailed about, and for an administrator which of the\n installation's events besides.", "operationId": "spin.v1.SettingsService.GetNotificationPreferences", "parameters": [ { @@ -9961,6 +10333,68 @@ } } }, + "/spin.v1.TeamService/GetTeamCosts": { + "post": { + "tags": [ + "TeamService" + ], + "summary": "GetTeamCosts", + "description": "What the team's workspaces cost in the month in progress, each and summed, for the team's\n admins: a member reads their own workspace's (WorkspaceService.GetWorkspaceCost) and nobody\n else's. A workspace is the team's whose it was on the last day it cost anything; a team below\n this one is not counted in it.", + "operationId": "spin.v1.TeamService.GetTeamCosts", + "parameters": [ + { + "name": "Connect-Protocol-Version", + "in": "header", + "description": "Define the version of the Connect protocol", + "schema": { + "$ref": "#/components/schemas/connect-protocol-version" + }, + "example": 1 + }, + { + "name": "Connect-Timeout-Ms", + "in": "header", + "description": "Define the timeout, in ms", + "schema": { + "$ref": "#/components/schemas/connect-timeout-header" + }, + "example": 1000 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.GetTeamCostsRequest" + } + } + }, + "required": true + }, + "responses": { + "default": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/connect.error" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.GetTeamCostsResponse" + } + } + } + } + } + } + }, "/spin.v1.TeamService/ListIdentityProviders": { "post": { "tags": [ @@ -11445,14 +11879,14 @@ } } }, - "/spin.v1.WorkspaceService/GetWorkspaceEgress": { + "/spin.v1.WorkspaceService/GetWorkspaceCost": { "post": { "tags": [ "WorkspaceService" ], - "summary": "GetWorkspaceEgress", - "description": "What a running workspace has actually reached beyond the node.", - "operationId": "spin.v1.WorkspaceService.GetWorkspaceEgress", + "summary": "GetWorkspaceCost", + "description": "What the workspace cost in the month in progress and what it costs while it runs, for whoever\n reads the workspace itself: its owner, and a guest its owner let in. Nobody else is answered -\n one workspace's cost says how much another person works. Read from the bill as the\n installation last read it, never from the cloud.", + "operationId": "spin.v1.WorkspaceService.GetWorkspaceCost", "parameters": [ { "name": "Connect-Protocol-Version", @@ -11477,7 +11911,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceEgressRequest" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceCostRequest" } } }, @@ -11499,7 +11933,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceEgressResponse" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceCostResponse" } } } @@ -11507,14 +11941,14 @@ } } }, - "/spin.v1.WorkspaceService/GetWorkspaceHistory": { + "/spin.v1.WorkspaceService/GetWorkspaceDeletion": { "post": { "tags": [ "WorkspaceService" ], - "summary": "GetWorkspaceHistory", - "description": "Get workspace history (snapshots/state changes timeline)", - "operationId": "spin.v1.WorkspaceService.GetWorkspaceHistory", + "summary": "GetWorkspaceDeletion", + "description": "What deleting a workspace would do, asked before it is done: what goes to the trash and for\n how long, what is erased at once, and what outlives it. It changes nothing.", + "operationId": "spin.v1.WorkspaceService.GetWorkspaceDeletion", "parameters": [ { "name": "Connect-Protocol-Version", @@ -11539,7 +11973,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceHistoryRequest" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceDeletionRequest" } } }, @@ -11561,7 +11995,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceHistoryResponse" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceDeletionResponse" } } } @@ -11569,14 +12003,14 @@ } } }, - "/spin.v1.WorkspaceService/GetWorkspaceIdentity": { + "/spin.v1.WorkspaceService/GetWorkspaceEgress": { "post": { "tags": [ "WorkspaceService" ], - "summary": "GetWorkspaceIdentity", - "description": "Who the workspace is outside spin: the identity its tokens and signatures carry, the issuer a\n relying party trusts it by, and what it was cloned from.", - "operationId": "spin.v1.WorkspaceService.GetWorkspaceIdentity", + "summary": "GetWorkspaceEgress", + "description": "What a running workspace has actually reached beyond the node.", + "operationId": "spin.v1.WorkspaceService.GetWorkspaceEgress", "parameters": [ { "name": "Connect-Protocol-Version", @@ -11601,7 +12035,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceIdentityRequest" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceEgressRequest" } } }, @@ -11623,7 +12057,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceIdentityResponse" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceEgressResponse" } } } @@ -11631,14 +12065,14 @@ } } }, - "/spin.v1.WorkspaceService/GetWorkspaceStatus": { + "/spin.v1.WorkspaceService/GetWorkspaceHistory": { "post": { "tags": [ "WorkspaceService" ], - "summary": "GetWorkspaceStatus", - "description": "What every party believes about one workspace, and where they disagree.", - "operationId": "spin.v1.WorkspaceService.GetWorkspaceStatus", + "summary": "GetWorkspaceHistory", + "description": "Get workspace history (snapshots/state changes timeline)", + "operationId": "spin.v1.WorkspaceService.GetWorkspaceHistory", "parameters": [ { "name": "Connect-Protocol-Version", @@ -11663,7 +12097,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceStatusRequest" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceHistoryRequest" } } }, @@ -11685,7 +12119,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceStatusResponse" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceHistoryResponse" } } } @@ -11693,14 +12127,14 @@ } } }, - "/spin.v1.WorkspaceService/GetWorkspaceUsage": { + "/spin.v1.WorkspaceService/GetWorkspaceIdentity": { "post": { "tags": [ "WorkspaceService" ], - "summary": "GetWorkspaceUsage", - "description": "What the workspace's machine used of what it held, over the last hour at most, as its host\n sampled it: a running machine's up to now, a stopped or failed one's up to when it ended.\n The samples live on that host, so the series begins where the machine began there, and goes\n with a restart of the host, a move, the workspace's next start or its removal.", - "operationId": "spin.v1.WorkspaceService.GetWorkspaceUsage", + "summary": "GetWorkspaceIdentity", + "description": "Who the workspace is outside spin: the identity its tokens and signatures carry, the issuer a\n relying party trusts it by, and what it was cloned from.", + "operationId": "spin.v1.WorkspaceService.GetWorkspaceIdentity", "parameters": [ { "name": "Connect-Protocol-Version", @@ -11725,7 +12159,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceUsageRequest" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceIdentityRequest" } } }, @@ -11747,7 +12181,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceUsageResponse" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceIdentityResponse" } } } @@ -11755,13 +12189,14 @@ } } }, - "/spin.v1.WorkspaceService/GrantPortAccess": { + "/spin.v1.WorkspaceService/GetWorkspaceStatus": { "post": { "tags": [ "WorkspaceService" ], - "summary": "GrantPortAccess", - "operationId": "spin.v1.WorkspaceService.GrantPortAccess", + "summary": "GetWorkspaceStatus", + "description": "What every party believes about one workspace, and where they disagree.", + "operationId": "spin.v1.WorkspaceService.GetWorkspaceStatus", "parameters": [ { "name": "Connect-Protocol-Version", @@ -11786,7 +12221,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GrantPortAccessRequest" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceStatusRequest" } } }, @@ -11808,7 +12243,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GrantPortAccessResponse" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceStatusResponse" } } } @@ -11816,14 +12251,14 @@ } } }, - "/spin.v1.WorkspaceService/GrantWorkspaceResources": { + "/spin.v1.WorkspaceService/GetWorkspaceUsage": { "post": { "tags": [ "WorkspaceService" ], - "summary": "GrantWorkspaceResources", - "description": "Give a workspace more cores and memory of its own, up to its preset's ceiling: its host\n reserves them and its machine is grown while it runs. The grant lasts until it is released\n or the workspace is deleted.", - "operationId": "spin.v1.WorkspaceService.GrantWorkspaceResources", + "summary": "GetWorkspaceUsage", + "description": "What the workspace's machine used of what it held, over the last hour at most, as its host\n sampled it: a running machine's up to now, a stopped or failed one's up to when it ended.\n The samples live on that host, so the series begins where the machine began there, and goes\n with a restart of the host, a move, the workspace's next start or its removal.", + "operationId": "spin.v1.WorkspaceService.GetWorkspaceUsage", "parameters": [ { "name": "Connect-Protocol-Version", @@ -11848,7 +12283,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GrantWorkspaceResourcesRequest" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceUsageRequest" } } }, @@ -11870,7 +12305,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GrantWorkspaceResourcesResponse" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceUsageResponse" } } } @@ -11878,14 +12313,13 @@ } } }, - "/spin.v1.WorkspaceService/KeepWorkspace": { + "/spin.v1.WorkspaceService/GrantPortAccess": { "post": { "tags": [ "WorkspaceService" ], - "summary": "KeepWorkspace", - "description": "Keep a running workspace awake for a while: neither the idle suspension nor the running cap\n fires before kept_until, and the question asked before one (suspends_at) is withdrawn. An\n answer with an end, never permanent: at most a day at a time (MaxKeepMinutes).", - "operationId": "spin.v1.WorkspaceService.KeepWorkspace", + "summary": "GrantPortAccess", + "operationId": "spin.v1.WorkspaceService.GrantPortAccess", "parameters": [ { "name": "Connect-Protocol-Version", @@ -11910,7 +12344,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.KeepWorkspaceRequest" + "$ref": "#/components/schemas/spin.v1.GrantPortAccessRequest" } } }, @@ -11932,7 +12366,131 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.KeepWorkspaceResponse" + "$ref": "#/components/schemas/spin.v1.GrantPortAccessResponse" + } + } + } + } + } + } + }, + "/spin.v1.WorkspaceService/GrantWorkspaceResources": { + "post": { + "tags": [ + "WorkspaceService" + ], + "summary": "GrantWorkspaceResources", + "description": "Give a workspace more cores and memory of its own, up to its preset's ceiling: its host\n reserves them and its machine is grown while it runs. The grant lasts until it is released\n or the workspace is deleted.", + "operationId": "spin.v1.WorkspaceService.GrantWorkspaceResources", + "parameters": [ + { + "name": "Connect-Protocol-Version", + "in": "header", + "description": "Define the version of the Connect protocol", + "schema": { + "$ref": "#/components/schemas/connect-protocol-version" + }, + "example": 1 + }, + { + "name": "Connect-Timeout-Ms", + "in": "header", + "description": "Define the timeout, in ms", + "schema": { + "$ref": "#/components/schemas/connect-timeout-header" + }, + "example": 1000 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.GrantWorkspaceResourcesRequest" + } + } + }, + "required": true + }, + "responses": { + "default": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/connect.error" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.GrantWorkspaceResourcesResponse" + } + } + } + } + } + } + }, + "/spin.v1.WorkspaceService/KeepWorkspace": { + "post": { + "tags": [ + "WorkspaceService" + ], + "summary": "KeepWorkspace", + "description": "Keep a running workspace awake for a while: neither the idle suspension nor the running cap\n fires before kept_until, and the question asked before one (suspends_at) is withdrawn. An\n answer with an end, never permanent: at most a day at a time (MaxKeepMinutes).", + "operationId": "spin.v1.WorkspaceService.KeepWorkspace", + "parameters": [ + { + "name": "Connect-Protocol-Version", + "in": "header", + "description": "Define the version of the Connect protocol", + "schema": { + "$ref": "#/components/schemas/connect-protocol-version" + }, + "example": 1 + }, + { + "name": "Connect-Timeout-Ms", + "in": "header", + "description": "Define the timeout, in ms", + "schema": { + "$ref": "#/components/schemas/connect-timeout-header" + }, + "example": 1000 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.KeepWorkspaceRequest" + } + } + }, + "required": true + }, + "responses": { + "default": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/connect.error" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.KeepWorkspaceResponse" } } } @@ -12311,6 +12869,68 @@ } } }, + "/spin.v1.WorkspaceService/ListOwnAgentThreads": { + "post": { + "tags": [ + "WorkspaceService" + ], + "summary": "ListOwnAgentThreads", + "description": "The caller's own chats across every workspace of theirs, each workspace's as its supervisor\n last reported them: what the dashboard's chat mode lists in one rail. Selected by the caller's\n id, never one from the request, and a key bound to a team or projects lists theirs alone.", + "operationId": "spin.v1.WorkspaceService.ListOwnAgentThreads", + "parameters": [ + { + "name": "Connect-Protocol-Version", + "in": "header", + "description": "Define the version of the Connect protocol", + "schema": { + "$ref": "#/components/schemas/connect-protocol-version" + }, + "example": 1 + }, + { + "name": "Connect-Timeout-Ms", + "in": "header", + "description": "Define the timeout, in ms", + "schema": { + "$ref": "#/components/schemas/connect-timeout-header" + }, + "example": 1000 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.ListOwnAgentThreadsRequest" + } + } + }, + "required": true + }, + "responses": { + "default": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/connect.error" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.ListOwnAgentThreadsResponse" + } + } + } + } + } + } + }, "/spin.v1.WorkspaceService/ListSnapshots": { "post": { "tags": [ @@ -12497,6 +13117,68 @@ } } }, + "/spin.v1.WorkspaceService/ListWorkspaceTimeline": { + "post": { + "tags": [ + "WorkspaceService" + ], + "summary": "ListWorkspaceTimeline", + "description": "What happened to a workspace, newest first, between two instants: its own events and what\n the audit log records of it and its snapshots, each with who did it - for its owner, read as\n GetWorkspaceHistory is. AdminService.ListTimeline is the same reading of any workspace, a host,\n a team, a project or the whole installation.", + "operationId": "spin.v1.WorkspaceService.ListWorkspaceTimeline", + "parameters": [ + { + "name": "Connect-Protocol-Version", + "in": "header", + "description": "Define the version of the Connect protocol", + "schema": { + "$ref": "#/components/schemas/connect-protocol-version" + }, + "example": 1 + }, + { + "name": "Connect-Timeout-Ms", + "in": "header", + "description": "Define the timeout, in ms", + "schema": { + "$ref": "#/components/schemas/connect-timeout-header" + }, + "example": 1000 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.ListWorkspaceTimelineRequest" + } + } + }, + "required": true + }, + "responses": { + "default": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/connect.error" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/spin.v1.ListWorkspaceTimelineResponse" + } + } + } + } + } + } + }, "/spin.v1.WorkspaceService/ListWorkspaces": { "post": { "tags": [ @@ -13950,10 +14632,6 @@ "format": "duration", "description": "A signed duration in seconds, with up to nine fractional digits and an `s` suffix (for example, `3s` or `-0.001s`)." }, - "google.protobuf.FieldMask": { - "type": "string", - "description": "Comma-separated field paths in lowerCamelCase (for example, `user.displayName,photo`)." - }, "google.protobuf.ListValue": { "type": "array", "items": { @@ -14088,7 +14766,7 @@ ], "title": "max_workspaces", "format": "int32", - "description": "What the workspaces its tree made may hold at once; unset for no bound past its person's." + "description": "How many of the workspaces its tree made - this key and every key delegated from it - may be\n on a runner at once, and how many cores those may hold: bounds on what runs, unset for none\n past its person's. A workspace counts while it is being made or started, runs, is stopping or\n waits for a runner. One that is stopped, suspended or in the trash counts for nothing,\n whatever disk it keeps, and is counted again when it is started: a start past the bound is\n refused as a create is, naming the workspaces that hold it." }, "maxCores": { "type": [ @@ -14305,30 +14983,53 @@ "title": "AddWorkspaceGuestResponse", "additionalProperties": false }, - "spin.v1.AgentThread": { + "spin.v1.AffectedWorkspace": { "type": "object", "properties": { "id": { "type": "string", "title": "id" }, - "title": { - "type": "string", - "title": "title" - }, - "project": { - "type": "string", - "title": "project", - "description": "project is the directory the thread works in." - }, - "model": { + "name": { "type": "string", - "title": "model" + "title": "name" }, - "updatedAt": { + "state": { "allOf": [ { - "$ref": "#/components/schemas/google.protobuf.Timestamp" + "$ref": "#/components/schemas/spin.v1.WorkspaceState" + } + ], + "title": "state" + } + }, + "title": "AffectedWorkspace", + "additionalProperties": false + }, + "spin.v1.AgentThread": { + "type": "object", + "properties": { + "id": { + "type": "string", + "title": "id" + }, + "title": { + "type": "string", + "title": "title" + }, + "project": { + "type": "string", + "title": "project", + "description": "project is the directory the thread works in." + }, + "model": { + "type": "string", + "title": "model" + }, + "updatedAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" } ], "title": "updated_at" @@ -14377,6 +15078,102 @@ "additionalProperties": false, "description": "AgentVolume is one agent home of the caller's." }, + "spin.v1.Alert": { + "type": "object", + "properties": { + "id": { + "type": "string", + "title": "id", + "description": "The installation event's id." + }, + "event": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.InstallationEventType" + } + ], + "title": "event" + }, + "name": { + "type": "string", + "title": "name", + "description": "The rule's title (Grafana's alertname)." + }, + "summary": { + "type": "string", + "title": "summary", + "description": "The rule's summary, rendered for what fired; empty where it has none." + }, + "description": { + "type": "string", + "title": "description" + }, + "severity": { + "type": "string", + "title": "severity", + "description": "critical, warning; empty where the rule says none." + }, + "runbookUrl": { + "type": "string", + "title": "runbook_url", + "description": "Where the dashboard's runbook for it is, as the rule names it: /admin/runbooks/\u003cid\u003e." + }, + "labels": { + "type": "object", + "title": "labels", + "additionalProperties": { + "type": "string", + "title": "value" + }, + "description": "What else the alert's series is labelled with: which host, which volume." + }, + "startsAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "starts_at", + "description": "When it began firing, and for a resolution when it stopped." + }, + "endsAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "ends_at" + }, + "createdAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "created_at", + "description": "When the control plane heard it." + }, + "sent": { + "type": "integer", + "title": "sent", + "format": "int32", + "description": "How many administrators it was emailed to, is waiting for, and failed every attempt for." + }, + "pending": { + "type": "integer", + "title": "pending", + "format": "int32" + }, + "failed": { + "type": "integer", + "title": "failed", + "format": "int32" + } + }, + "title": "Alert", + "additionalProperties": false, + "description": "Alert is one firing or one resolution of an alert rule, as Grafana sent it." + }, "spin.v1.AllowedEmail": { "type": "object", "properties": { @@ -15372,6 +16169,135 @@ "additionalProperties": false, "description": "Empty on success" }, + "spin.v1.CostEstimate": { + "type": "object", + "properties": { + "day": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "day", + "description": "The billed day the rate is from: its first instant, UTC." + }, + "runningHourMicros": { + "type": [ + "string", + "null" + ], + "title": "running_hour_micros", + "format": "int64", + "description": "An hour of its machine running, for the cores and memory it holds; unset where that day billed\n no runner." + }, + "stoppedMonthMicros": { + "type": [ + "string", + "null" + ], + "title": "stopped_month_micros", + "format": "int64", + "description": "A month of its disk kept while it is stopped, for the bytes it kept that day; unset where that\n day billed no volume, or the workspace was made since." + } + }, + "title": "CostEstimate", + "additionalProperties": false, + "description": "What a workspace would cost at what the last billed day charged. An estimate: that day is over\n and the next may be charged otherwise, so it is never said without the day it is from." + }, + "spin.v1.CostMonth": { + "type": "object", + "properties": { + "month": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "month", + "description": "Its first instant, UTC." + }, + "readAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "read_at", + "description": "The reading its costs are from." + }, + "currency": { + "type": "string", + "title": "currency", + "description": "ISO 4217." + }, + "totalMicros": { + "type": "string", + "title": "total_micros", + "format": "int64", + "description": "Every cost of its days; idle and unstored are parts of it." + }, + "idleMicros": { + "type": "string", + "title": "idle_micros", + "format": "int64", + "description": "What the runners cost that no workspace held." + }, + "unstoredMicros": { + "type": "string", + "title": "unstored_micros", + "format": "int64", + "description": "What the volumes' bucket cost for bytes no workspace keeps." + }, + "budgetLimitMicros": { + "type": [ + "string", + "null" + ], + "title": "budget_limit_micros", + "format": "int64", + "description": "The installation's budget as the month's last reading in it said; unset where it had none." + } + }, + "title": "CostMonth", + "additionalProperties": false, + "description": "One month of the trend on Admin → Costs, in millionths of the bill's currency. An estimate of\n what nobody caused, from the reading it names: a month's last days are revised by the cloud\n into the next, and read again until they settle." + }, + "spin.v1.CostShare": { + "type": "object", + "properties": { + "computeMicros": { + "type": "string", + "title": "compute_micros", + "format": "int64", + "description": "Of the runners: what was held of them." + }, + "storageMicros": { + "type": "string", + "title": "storage_micros", + "format": "int64", + "description": "Of the volumes' bucket: what the volumes kept." + }, + "sentBytes": { + "type": "string", + "title": "sent_bytes", + "format": "int64", + "description": "What the traffic came to in the month: the machine's network out and back, and its sessions\n through the relay, both ways. Counted, not costed." + }, + "receivedBytes": { + "type": "string", + "title": "received_bytes", + "format": "int64" + }, + "forwardedBytes": { + "type": "string", + "title": "forwarded_bytes", + "format": "int64" + } + }, + "title": "CostShare", + "additionalProperties": false, + "description": "What was caused in a month of the cloud's bill, as the installation shares it out\n (AdminService.GetCosts): by one workspace, or by several summed. In millionths of the bill's\n currency. A share is of days already billed, never of this hour: the bill is read from the\n cloud a few times a day." + }, "spin.v1.CpuUsagePoint": { "type": "object", "properties": { @@ -15443,7 +16369,7 @@ "teamId": { "type": "string", "title": "team_id", - "description": "What it reaches and what its tree may hold: as APIKey's. Asked by a key holding keys:delegate,\n it is that key's child, and holds no more than it (delegation.Within)." + "description": "What it reaches and what its tree may have running at once: as APIKey's, where what is counted\n is said. Asked by a key holding keys:delegate, it is that key's child, and holds no more than it\n (delegation.Within)." }, "projectIds": { "type": "array", @@ -15955,7 +16881,7 @@ "preset": { "type": "string", "title": "preset", - "description": "The preset it is sized by, by name (AdminService.ListResourcePresets): its cores, memory,\n disk and how it grows. Empty is the project's preset when project_id names one, otherwise\n the installation's default preset, or with none marked 1 core, 512 MB and 10 GB free. A\n disabled preset is refused." + "description": "The preset it is sized by, by name (AdminService.ListResourcePresets): its cores, memory,\n disk and how it grows. Empty is the project's preset when project_id names one, otherwise\n the installation's default preset, or with none marked 1 core, 2048 MB and 10 GB free. A\n disabled preset is refused." }, "env": { "type": "object", @@ -16362,6 +17288,70 @@ "additionalProperties": false, "description": "DeletedWorkspace is a workspace in the trash." }, + "spin.v1.DeletionEffect": { + "type": "object", + "properties": { + "fate": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.DeletionFate" + } + ], + "title": "fate" + }, + "what": { + "type": "string", + "title": "what", + "description": "What it is: \"Its disk\", \"2 snapshots\"." + }, + "detail": { + "type": "string", + "title": "detail", + "description": "What happens to it and what follows from that, one sentence." + } + }, + "title": "DeletionEffect", + "additionalProperties": false, + "description": "DeletionEffect is one thing a workspace has and what a delete does to it, in words its owner\n reads before confirming." + }, + "spin.v1.DeletionFate": { + "type": "string", + "title": "DeletionFate", + "enum": [ + "DELETION_FATE_UNSPECIFIED", + "DELETION_FATE_ERASED", + "DELETION_FATE_TRASHED", + "DELETION_FATE_KEPT" + ], + "description": "DeletionFate is what a delete does to one thing a workspace has.\n\n- `DELETION_FATE_ERASED`: Gone when the delete is done, and not undeleted.\n- `DELETION_FATE_TRASHED`: In the trash for GetWorkspaceDeletionResponse.trash_days, restored by an undelete, erased\n when they are up.\n- `DELETION_FATE_KEPT`: Outlives the workspace, the trash's days included.", + "x-enum-descriptions": [ + "", + "Gone when the delete is done, and not undeleted.", + "In the trash for GetWorkspaceDeletionResponse.trash_days, restored by an undelete, erased\n when they are up.", + "Outlives the workspace, the trash's days included." + ] + }, + "spin.v1.DepartureFate": { + "type": "string", + "title": "DepartureFate", + "enum": [ + "DEPARTURE_FATE_UNSPECIFIED", + "DEPARTURE_FATE_MOVES", + "DEPARTURE_FATE_STAYS", + "DEPARTURE_FATE_LOSES_PLACE", + "DEPARTURE_FATE_HOLDS", + "DEPARTURE_FATE_STOPS" + ], + "description": "DepartureFate is what taking a host out does to one workspace on it.\n\n- `DEPARTURE_FATE_MOVES`: Suspended with its memory and resumed on another runner with room.\n- `DEPARTURE_FATE_STAYS`: Keeps its place on this runner: a drain moves only what runs.\n- `DEPARTURE_FATE_LOSES_PLACE`: Suspended at a published snapshot: its disk is let go of here, and its next start is on\n another runner, from what it published.\n- `DEPARTURE_FATE_HOLDS`: It keeps the host: the removal is refused while it is here. A group's machine is held by a\n disk only here, until it is stopped, which publishes it, or moved; a revoked host by any\n workspace that names it.\n- `DEPARTURE_FATE_STOPS`: Its disk is only here and is left here: it runs again only once recovered onto another\n runner, giving up what this one had not published.", + "x-enum-descriptions": [ + "", + "Suspended with its memory and resumed on another runner with room.", + "Keeps its place on this runner: a drain moves only what runs.", + "Suspended at a published snapshot: its disk is let go of here, and its next start is on\n another runner, from what it published.", + "It keeps the host: the removal is refused while it is here. A group's machine is held by a\n disk only here, until it is stopped, which publishes it, or moved; a revoked host by any\n workspace that names it.", + "Its disk is only here and is left here: it runs again only once recovered onto another\n runner, giving up what this one had not published." + ] + }, "spin.v1.DeviceLoginStatus": { "type": "string", "title": "DeviceLoginStatus", @@ -16816,12 +17806,6 @@ ], "title": "released_at" }, - "workspaces": { - "type": "string", - "title": "workspaces", - "format": "int64", - "description": "How many workspaces run it; one that nothing runs and is not the newest is collectable." - }, "newest": { "type": "boolean", "title": "newest", @@ -16835,12 +17819,12 @@ "removable": { "type": "boolean", "title": "removable", - "description": "Not the newest and nothing runs it: RemoveStoredVolume removes it, and so does the\n collect-releases job on its own." + "description": "Not the newest, and open in no machine and no suspended memory: RemoveStoredVolume removes\n it, and so does the collect-releases job on its own. A release only stopped workspaces last\n ran is removable, since their next start is given the newest." }, "keptBecause": { "type": "string", "title": "kept_because", - "description": "Why it stays, in words, where it may not go." + "description": "Why it stays, in words, where it may not go: how many machines and suspended memories have\n it open, or that it is the newest." } }, "title": "ExtensionRelease", @@ -16861,7 +17845,8 @@ "workspaces": { "type": "string", "title": "workspaces", - "format": "int64" + "format": "int64", + "description": "The machines that have it open and the suspended memories that do: a stopped workspace is\n given the newest at its next start, and is on none." }, "newest": { "type": "boolean", @@ -17093,6 +18078,20 @@ } ], "title": "give_back_refused_at" + }, + "capacityRefused": { + "type": "boolean", + "title": "capacity_refused", + "description": "launch_failure is the cloud having no machine of the kind the class asks for - no spot\n capacity, or the spot quota spent - which the class's spot setting, or its fallback, is what\n changes; false for any other failure, and while there is none." + }, + "onDemandUntil": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "on_demand_until", + "description": "Set while a spot class's group starts on-demand machines because the cloud refused it spot\n (HostClass.fallback_on_demand): until this, and spot again after. Its class still says spot." } }, "title": "FleetClass", @@ -17416,11 +18415,37 @@ "platform": { "type": "array", "items": { - "$ref": "#/components/schemas/spin.v1.ServiceCost" + "$ref": "#/components/schemas/spin.v1.PlatformCost" }, "title": "platform", - "description": "Every other cost - the control plane, the proxy, keys, logs - by service, costliest first." - } + "description": "Every other cost - the control plane, the proxy, keys, logs - by role and service, costliest\n first." + }, + "standby": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.StandbyCost" + } + ], + "title": "standby", + "description": "What the installation costs a day with nobody working; unset where no day before the\n reading billed anything." + }, + "readAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "read_at", + "description": "When the month's bill was last read; unset where it never was, and then nothing is answered." + }, + "trend": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.CostMonth" + }, + "title": "trend", + "description": "The year up to this month, oldest first, this month last: each month the bill was read in,\n shared out as this one is. A month never read is not among them." + } }, "title": "GetCostsResponse", "additionalProperties": false @@ -17621,6 +18646,15 @@ } ], "title": "host" + }, + "departure": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.HostDeparture" + } + ], + "title": "departure", + "description": "What taking the host out would do to each workspace on it, as the server would do it: asked\n of one host, because it reads every workspace there." } }, "title": "GetHostResponse", @@ -17687,54 +18721,6 @@ "title": "GetInstallationHealthResponse", "additionalProperties": false }, - "spin.v1.GetInstallationSettingsRequest": { - "type": "object", - "title": "GetInstallationSettingsRequest", - "additionalProperties": false - }, - "spin.v1.GetInstallationSettingsResponse": { - "type": "object", - "properties": { - "settings": { - "allOf": [ - { - "$ref": "#/components/schemas/spin.v1.InstallationSettings" - } - ], - "title": "settings" - }, - "reaches": { - "type": "object", - "title": "reaches", - "additionalProperties": { - "allOf": [ - { - "$ref": "#/components/schemas/spin.v1.SettingReach" - } - ], - "title": "value" - }, - "description": "What each setting touches when saved, by its update_mask path: every path\n UpdateInstallationSettings accepts, and no other." - }, - "runningWorkspaces": { - "type": "integer", - "title": "running_workspaces", - "format": "int32", - "description": "How many workspaces are running now: what a RUNNING_WORKSPACES setting reaches, and what a\n NEW_WORKSPACES one leaves as it is." - }, - "connectedRunners": { - "type": [ - "integer", - "null" - ], - "title": "connected_runners", - "format": "int32", - "description": "How many runners hold their stream to this control plane now: what a NEXT_HEARTBEAT setting\n reaches. Unset where this control plane cannot tell." - } - }, - "title": "GetInstallationSettingsResponse", - "additionalProperties": false - }, "spin.v1.GetMonitoringRequest": { "type": "object", "title": "GetMonitoringRequest", @@ -17770,7 +18756,7 @@ "$ref": "#/components/schemas/spin.v1.NotificationPreference" }, "title": "preferences", - "description": "One per event a person may be told of, in the order they are shown." + "description": "One per event a person may be told of, in the order they are shown: an administrator's\n include the installation's." }, "emailConfigured": { "type": "boolean", @@ -17855,6 +18841,64 @@ "title": "GetPrebuildResponse", "additionalProperties": false }, + "spin.v1.GetProjectCostsRequest": { + "type": "object", + "properties": { + "projectId": { + "type": "string", + "title": "project_id" + } + }, + "title": "GetProjectCostsRequest", + "additionalProperties": false + }, + "spin.v1.GetProjectCostsResponse": { + "type": "object", + "properties": { + "month": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "month", + "description": "The month in progress: its first instant, UTC." + }, + "readAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "read_at", + "description": "When the bill was last read; unset where it never was - an installation with no bill scope -\n and then nothing below is known and nothing is to be drawn." + }, + "currency": { + "type": "string", + "title": "currency", + "description": "ISO 4217; every amount here is in millionths of it." + }, + "workspaces": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.CostShare" + } + ], + "title": "workspaces", + "description": "Its workspaces' shares summed, deleted ones and its prebuilds' builds included: a workspace is\n the project's it opened, whoever's it was." + }, + "prebuilds": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.PrebuildsKept" + } + ], + "title": "prebuilds" + } + }, + "title": "GetProjectCostsResponse", + "additionalProperties": false + }, "spin.v1.GetProjectRequest": { "type": "object", "properties": { @@ -17886,26 +18930,6 @@ "title": "GetProjectResponse", "additionalProperties": false }, - "spin.v1.GetRegistrationModeRequest": { - "type": "object", - "title": "GetRegistrationModeRequest", - "additionalProperties": false - }, - "spin.v1.GetRegistrationModeResponse": { - "type": "object", - "properties": { - "mode": { - "allOf": [ - { - "$ref": "#/components/schemas/spin.v1.RegistrationMode" - } - ], - "title": "mode" - } - }, - "title": "GetRegistrationModeResponse", - "additionalProperties": false - }, "spin.v1.GetRunbookRequest": { "type": "object", "properties": { @@ -17942,24 +18966,57 @@ "title": "GetRunbookResponse", "additionalProperties": false }, - "spin.v1.GetSecuritySettingsRequest": { + "spin.v1.GetSettingsRequest": { "type": "object", - "title": "GetSecuritySettingsRequest", + "title": "GetSettingsRequest", "additionalProperties": false }, - "spin.v1.GetSecuritySettingsResponse": { + "spin.v1.GetSettingsResponse": { "type": "object", "properties": { - "settings": { + "values": { + "type": "object", + "title": "values", + "additionalProperties": { + "type": "string", + "title": "value" + }, + "description": "Every definition's value in force, by key, as text of its type: what the installation says,\n or the default where it says nothing. The control plane's own are left out." + }, + "definitions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.SettingDefinition" + }, + "title": "definitions", + "description": "Every setting an administrator is shown, in the registry's order." + }, + "runningWorkspaces": { + "type": "integer", + "title": "running_workspaces", + "format": "int32", + "description": "How many workspaces are running now: what a RUNNING_WORKSPACES setting reaches, and what a\n NEW_WORKSPACES one leaves as it is." + }, + "connectedRunners": { + "type": [ + "integer", + "null" + ], + "title": "connected_runners", + "format": "int32", + "description": "How many runners hold their stream to this control plane now: what a NEXT_HEARTBEAT setting\n reaches. Unset where this control plane cannot tell." + }, + "place": { "allOf": [ { - "$ref": "#/components/schemas/spin.v1.SecuritySettings" + "$ref": "#/components/schemas/spin.v1.InstallationPlace" } ], - "title": "settings" + "title": "place", + "description": "Where the installation runs and what it runs, read-only." } }, - "title": "GetSecuritySettingsResponse", + "title": "GetSettingsResponse", "additionalProperties": false }, "spin.v1.GetSetupStatusRequest": { @@ -18104,6 +19161,64 @@ "title": "GetStorageUsageResponse", "additionalProperties": false }, + "spin.v1.GetTeamCostsRequest": { + "type": "object", + "properties": { + "teamId": { + "type": "string", + "title": "team_id" + } + }, + "title": "GetTeamCostsRequest", + "additionalProperties": false + }, + "spin.v1.GetTeamCostsResponse": { + "type": "object", + "properties": { + "month": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "month", + "description": "The month in progress: its first instant, UTC." + }, + "readAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "read_at", + "description": "When the bill was last read; unset where it never was - an installation with no bill scope -\n and then nothing below is known and nothing is to be drawn." + }, + "currency": { + "type": "string", + "title": "currency", + "description": "ISO 4217; every amount here is in millionths of it." + }, + "total": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.CostShare" + } + ], + "title": "total", + "description": "Its workspaces, summed." + }, + "workspaces": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.TeamWorkspaceCost" + }, + "title": "workspaces", + "description": "Costliest first." + } + }, + "title": "GetTeamCostsResponse", + "additionalProperties": false + }, "spin.v1.GetTeamRequest": { "type": "object", "properties": { @@ -18180,6 +19295,14 @@ ], "title": "samples", "description": "Into the installation's store of metrics." + }, + "perVolumeHistograms": { + "type": "array", + "items": { + "type": "string" + }, + "title": "per_volume_histograms", + "description": "The metrics that cost most to keep, a histogram per volume, which a surface may offer to\n drop as one (the setting telemetry_metrics_drop)." } }, "title": "GetTelemetryStatusResponse", @@ -18264,6 +19387,38 @@ "title": "GetUserSettingsResponse", "additionalProperties": false }, + "spin.v1.GetUserWorkspaceEgressRequest": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "title": "workspace_id", + "description": "The workspace's id." + }, + "reason": { + "type": "string", + "title": "reason", + "description": "Why, kept on the audit entry." + } + }, + "title": "GetUserWorkspaceEgressRequest", + "additionalProperties": false + }, + "spin.v1.GetUserWorkspaceEgressResponse": { + "type": "object", + "properties": { + "egress": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.GetWorkspaceEgressResponse" + } + ], + "title": "egress" + } + }, + "title": "GetUserWorkspaceEgressResponse", + "additionalProperties": false + }, "spin.v1.GetVSCodeServersRequest": { "type": "object", "title": "GetVSCodeServersRequest", @@ -18339,7 +19494,7 @@ "title": "GetWorkspaceConsoleResponse", "additionalProperties": false }, - "spin.v1.GetWorkspaceEgressRequest": { + "spin.v1.GetWorkspaceCostRequest": { "type": "object", "properties": { "workspaceId": { @@ -18347,26 +19502,122 @@ "title": "workspace_id" } }, - "title": "GetWorkspaceEgressRequest", - "additionalProperties": false, - "description": "GetWorkspaceEgressRequest asks what a workspace has reached beyond the node. The host keeps\n the record, so the workspace has to be running on one; it is kept for six hours and survives\n a restart of the runner, not of the host." + "title": "GetWorkspaceCostRequest", + "additionalProperties": false }, - "spin.v1.GetWorkspaceEgressResponse": { + "spin.v1.GetWorkspaceCostResponse": { "type": "object", "properties": { - "destinations": { - "type": "array", - "items": { - "$ref": "#/components/schemas/spin.v1.ObservedDestination" - }, - "title": "destinations", - "description": "Most traffic first, so what an allowlist has to carry is at the top." + "month": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "month", + "description": "The month in progress: its first instant, UTC." }, - "lookups": { - "type": "array", - "items": { - "$ref": "#/components/schemas/spin.v1.ResolverLookup" - }, + "readAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "read_at", + "description": "When the bill was last read; unset where it never was - an installation with no bill scope, a\n cloud that sends none - and then nothing below is known and nothing is to be drawn." + }, + "currency": { + "type": "string", + "title": "currency", + "description": "ISO 4217; every amount here is in millionths of it." + }, + "share": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.CostShare" + } + ], + "title": "share", + "description": "The month so far." + }, + "estimate": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.CostEstimate" + } + ], + "title": "estimate", + "description": "Unset where no day before the reading was billed, or none says anything of this workspace." + } + }, + "title": "GetWorkspaceCostResponse", + "additionalProperties": false + }, + "spin.v1.GetWorkspaceDeletionRequest": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "title": "workspace_id" + }, + "permanently": { + "type": "boolean", + "title": "permanently", + "description": "What DeleteWorkspaceRequest.permanently would do: an erase, whatever the trash keeps." + } + }, + "title": "GetWorkspaceDeletionRequest", + "additionalProperties": false + }, + "spin.v1.GetWorkspaceDeletionResponse": { + "type": "object", + "properties": { + "trashDays": { + "type": "integer", + "title": "trash_days", + "format": "int32", + "description": "How many days the delete keeps the workspace in the trash; 0 is an erase now - the\n installation keeps no trash, or permanently was asked." + }, + "effects": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.DeletionEffect" + }, + "title": "effects", + "description": "Everything the delete does to what the workspace has, ordered erased, trashed, kept. Only\n what this workspace has: one with no snapshot is told nothing of snapshots." + } + }, + "title": "GetWorkspaceDeletionResponse", + "additionalProperties": false + }, + "spin.v1.GetWorkspaceEgressRequest": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "title": "workspace_id" + } + }, + "title": "GetWorkspaceEgressRequest", + "additionalProperties": false, + "description": "GetWorkspaceEgressRequest asks what a workspace has reached beyond the node. The host keeps\n the record, so the workspace has to be running on one; it is kept for six hours and survives\n a restart of the runner, not of the host." + }, + "spin.v1.GetWorkspaceEgressResponse": { + "type": "object", + "properties": { + "destinations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.ObservedDestination" + }, + "title": "destinations", + "description": "Most traffic first, so what an allowlist has to carry is at the top." + }, + "lookups": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.ResolverLookup" + }, "title": "lookups", "description": "The workspace's recent lookups its host's resolver did not answer as asked, newest first:\n \"it cannot resolve github.com\" is an upstream failing, a name pointing into the node being\n removed, or a query type refused, and this says which. Answered lookups are not kept." }, @@ -18616,6 +19867,14 @@ }, "title": "injections", "description": "Each header a brokered rule of the workspace's policies sets, and whether what it is set\n from is there to set: a request to a brokered name is refused when it is not, and this is\n where that is seen from outside the machine." + }, + "network": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.WorkspaceNetworkStatus" + }, + "title": "network", + "description": "The policies the workspace's network is under (Workspace.network_tags), in their order, and\n whether each is declared and installed on its host. Empty for a workspace with no tag, which\n reaches anything beyond its host's own networks." } }, "title": "GetWorkspaceStatusResponse", @@ -18929,6 +20188,19 @@ ], "title": "known_at", "description": "known_at is when what decided the status was so: the moment it was asked for a part asked\n now, the collector's last report, the last WAL file archived or failed, a failed job's run." + }, + "problems": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.Problem" + }, + "title": "problems", + "description": "What is wrong in this part, each on its own: one per host, one per job, one for a part that is\n a single thing. Empty while the part is OK. At most 20 are listed, the worst first;\n problem_count is how many there are." + }, + "problemCount": { + "type": "integer", + "title": "problem_count", + "format": "int32" } }, "title": "HealthCheck", @@ -18973,7 +20245,7 @@ "HEALTH_PART_HOSTS", "HEALTH_PART_WAITING_WORKSPACES" ], - "description": "HealthPart is which part of the installation a check is of.\n\n- `HEALTH_PART_DATABASE`: The control plane's database answers a query.\n- `HEALTH_PART_DATABASE_ARCHIVE`: The database's continuous archive keeps up: its last WAL file sent and how many wait. Its base\n backups are taken by a timer outside the control plane, which records nothing it can read.\n- `HEALTH_PART_LOG_STORE`: The log store (Quickwit) beside the control plane answers that it is ready.\n- `HEALTH_PART_COLLECTOR`: The collector sends what it is given: spans to the trace store, samples to the metric store\n (GetTelemetryStatus). It is what says whether the metric store takes writes - the control\n plane is not one of the metric store's readers.\n- `HEALTH_PART_JOBS`: The control plane's periodic work: a job whose last run failed (ListJobs).\n- `HEALTH_PART_HOSTS`: The hosts registered and not taken out of the fleet, against those whose command stream is up.\n- `HEALTH_PART_WAITING_WORKSPACES`: Workspaces waiting for a runner, across the whole fleet.", + "description": "HealthPart is which part of the installation a check is of.\n\n- `HEALTH_PART_DATABASE`: The control plane's database answers a query.\n- `HEALTH_PART_DATABASE_ARCHIVE`: The database's continuous archive keeps up: its last WAL file sent and how many wait. Its base\n backups are taken by a timer outside the control plane, which records nothing it can read.\n- `HEALTH_PART_LOG_STORE`: The log store (Quickwit) beside the control plane answers that it is ready.\n- `HEALTH_PART_COLLECTOR`: The collector sends what it is given: spans to the trace store, samples to the metric store\n (GetTelemetryStatus). It is what says whether the metric store takes writes - the control\n plane is not one of the metric store's readers.\n- `HEALTH_PART_JOBS`: The control plane's periodic work: a job whose last run failed (ListJobs).\n- `HEALTH_PART_HOSTS`: The hosts registered and not taken out of the fleet: those whose command stream is not up,\n and those that answer and fail a check of their own (HostCheck).\n- `HEALTH_PART_WAITING_WORKSPACES`: Workspaces waiting for a runner, across the whole fleet.", "x-enum-descriptions": [ "", "The control plane's database answers a query.", @@ -18981,7 +20253,7 @@ "The log store (Quickwit) beside the control plane answers that it is ready.", "The collector sends what it is given: spans to the trace store, samples to the metric store\n (GetTelemetryStatus). It is what says whether the metric store takes writes - the control\n plane is not one of the metric store's readers.", "The control plane's periodic work: a job whose last run failed (ListJobs).", - "The hosts registered and not taken out of the fleet, against those whose command stream is up.", + "The hosts registered and not taken out of the fleet: those whose command stream is not up,\n and those that answer and fail a check of their own (HostCheck).", "Workspaces waiting for a runner, across the whole fleet." ] }, @@ -19281,6 +20553,50 @@ "type": "string", "title": "removal_refused", "description": "removal_refused is why that removal cannot run now - a workspace whose disk is there - in\n words an administrator acts on; empty while it can." + }, + "keysGiven": { + "type": "integer", + "title": "keys_given", + "format": "int32", + "description": "keys_given is how many teams' disks this host was given the key of: what revoking it, or\n removing it as taken, marks for re-keying." + }, + "machineId": { + "type": "string", + "title": "machine_id", + "description": "Where the host's machine is, as its cloud said when the host joined - never as the host said\n of itself: the machine's id and type as that cloud names them, its zone and its region. Each\n empty for a host that joined with no cloud (a registration token: a development stack, a\n machine of one's own), and for what its cloud did not say." + }, + "machineType": { + "type": "string", + "title": "machine_type" + }, + "zone": { + "type": "string", + "title": "zone" + }, + "region": { + "type": "string", + "title": "region" + }, + "reclaimable": { + "type": [ + "boolean", + "null" + ], + "title": "reclaimable", + "description": "reclaimable is whether the cloud may take the machine back, as its cloud said of the instance\n when it joined - a spot machine is, whatever its class says: a group that fell back to\n on-demand, or one whose class was changed, starts machines its class does not describe. Unset\n where nothing says: a host that joined with no cloud, or one its cloud named nothing of." + }, + "holders": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.HostHolder" + }, + "title": "holders", + "description": "holders is what keeps this host in the fleet, from the database: the workspaces whose disk is\n only here - whichever list of theirs leaves them out, a prebuild's build, a team's, another\n person's, a failed one - and the volumes still here that are no such workspace's disk, a\n trashed workspace's or an agent's home, each of which forgetting the host must detach first.\n At most 10; holder_count is how many there are." + }, + "holderCount": { + "type": "integer", + "title": "holder_count", + "format": "int32" } }, "title": "Host", @@ -19361,13 +20677,125 @@ "type": "integer", "title": "max_hosts", "format": "int32", - "description": "The most hosts of it; 0 is no limit of its own (InstallationSettings.autoscaling_max_hosts\n bounds them all)." + "description": "The most hosts of it; 0 is no limit of its own (the setting autoscaling_max_hosts\n bounds them all)." + }, + "fallbackOnDemand": { + "type": "boolean", + "title": "fallback_on_demand", + "description": "A spot class whose group the cloud refuses spot machines for capacity starts on-demand ones\n for a while, and then spot again (FleetClass.on_demand_until); spot itself is not changed.\n Off, the class's workspaces wait until somebody changes spot. Only a spot class has it." } }, "title": "HostClass", "additionalProperties": false, "description": "A kind of runner: the shape of the machines a group of the installation's cloud starts for it,\n which the control plane makes and sizes. What a machine boots is the installation's launch\n template, never this. \"default\" is the class a preset that names none runs on." }, + "spin.v1.HostDeparture": { + "type": "object", + "properties": { + "workspaces": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.WorkspaceDeparture" + }, + "title": "workspaces", + "description": "At most 20, the running first; count is how many there are." + }, + "count": { + "type": "integer", + "title": "count", + "format": "int32" + } + }, + "title": "HostDeparture", + "additionalProperties": false, + "description": "HostDeparture is what draining the host, and removing it as Host.removal says, would do to each\n workspace that names it - the ones a drain moves, the ones that stay, the ones that lose their\n place on it and the ones that hold it - so the confirmation says it before it is done." + }, + "spin.v1.HostHolder": { + "type": "object", + "properties": { + "kind": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.HostHolderKind" + } + ], + "title": "kind" + }, + "workspaceId": { + "type": "string", + "title": "workspace_id", + "description": "The workspace it is or was the disk of; for an agent's home, the workspace that mounts it, or\n that last did by name alone (workspace_id empty)." + }, + "workspaceName": { + "type": "string", + "title": "workspace_name" + }, + "volumeId": { + "type": "string", + "title": "volume_id", + "description": "The volume, for a holder that is a volume (a trashed workspace's disk, an agent's home); empty\n for a workspace, whose disk the workspace names." + }, + "ownerId": { + "type": "string", + "title": "owner_id", + "description": "Whose it is." + }, + "ownerEmail": { + "type": "string", + "title": "owner_email" + }, + "state": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.WorkspaceState" + } + ], + "title": "state", + "description": "The workspace's state; UNSPECIFIED for an agent's home no workspace mounts." + }, + "lastEvent": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.WorkspaceEventType" + } + ], + "title": "last_event", + "description": "What last happened to the workspace, and when: its history's newest entry. UNSPECIFIED and\n unset where it has none." + }, + "lastEventAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "last_event_at" + } + }, + "title": "HostHolder", + "additionalProperties": false, + "description": "HostHolder is one thing a host holds that its removal would lose or has to wait for, with\n whose it is and what last happened to it." + }, + "spin.v1.HostHolderKind": { + "type": "string", + "title": "HostHolderKind", + "enum": [ + "HOST_HOLDER_KIND_UNSPECIFIED", + "HOST_HOLDER_KIND_WORKSPACE", + "HOST_HOLDER_KIND_TEAM_WORKSPACE", + "HOST_HOLDER_KIND_PREBUILD_BUILD", + "HOST_HOLDER_KIND_TRASHED_WORKSPACE", + "HOST_HOLDER_KIND_AGENT_HOME" + ], + "description": "HostHolderKind is what a holder is, which says which list of whose shows it.\n\n- `HOST_HOLDER_KIND_WORKSPACE`: A person's own workspace, in their workspaces list.\n- `HOST_HOLDER_KIND_TEAM_WORKSPACE`: A workspace of a team, in its members' lists.\n- `HOST_HOLDER_KIND_PREBUILD_BUILD`: A prebuild's build: kept stopped as its prebuild's anchor, and in nobody's list.\n- `HOST_HOLDER_KIND_TRASHED_WORKSPACE`: The disk of a workspace in its owner's trash.\n- `HOST_HOLDER_KIND_AGENT_HOME`: A person's agent's home (AgentVolume).", + "x-enum-descriptions": [ + "", + "A person's own workspace, in their workspaces list.", + "A workspace of a team, in its members' lists.", + "A prebuild's build: kept stopped as its prebuild's anchor, and in nobody's list.", + "The disk of a workspace in its owner's trash.", + "A person's agent's home (AgentVolume)." + ] + }, "spin.v1.HostNetworkPolicy": { "type": "object", "properties": { @@ -19801,199 +21229,87 @@ "additionalProperties": false, "description": "InjectionStatus is one header the egress proxy sets on the workspace's requests to a brokered\n name, and whether the workspace's team holds what it is set from." }, - "spin.v1.InstallationSettings": { + "spin.v1.InstallationEventType": { + "type": "string", + "title": "InstallationEventType", + "enum": [ + "INSTALLATION_EVENT_TYPE_UNSPECIFIED", + "INSTALLATION_EVENT_TYPE_ALERT_FIRING", + "INSTALLATION_EVENT_TYPE_ALERT_RESOLVED" + ], + "description": "What happened to the installation itself, which its administrators are told of: an event of no\n workspace, recorded where the control plane hears it.\n\n- `INSTALLATION_EVENT_TYPE_ALERT_FIRING`: One of the release's alert rules fired in the installation's Grafana\n- `INSTALLATION_EVENT_TYPE_ALERT_RESOLVED`: A rule that fired is no longer past its threshold", + "x-enum-descriptions": [ + "", + "One of the release's alert rules fired in the installation's Grafana", + "A rule that fired is no longer past its threshold" + ] + }, + "spin.v1.InstallationPlace": { "type": "object", "properties": { - "allowedImages": { - "type": "array", - "items": { - "type": "string" - }, - "title": "allowed_images", - "description": "Whitelist of allowed images (empty = all allowed)" + "provider": { + "type": "string", + "title": "provider", + "description": "The provider the installation was made on, as its document names it: \"aws\", \"self-hosted\"." }, - "maxWorkspacesPerUser": { - "type": "integer", - "title": "max_workspaces_per_user", - "format": "int32", - "description": "Maximum workspaces per user (0 = unlimited)" + "account": { + "type": "string", + "title": "account", + "description": "The cloud account it runs in, as that cloud names it." }, - "defaultNetworkTags": { - "type": "array", - "items": { - "type": "string" - }, - "title": "default_network_tags", - "description": "What a workspace created without a network tag of its own runs under, by policy name.\n Empty means \"offline\", the policy every host has and which allows nothing: no value of\n this field means open. An installation that wants such a workspace out declares a policy\n saying what it may reach and names it here." + "region": { + "type": "string", + "title": "region" }, - "updatedAt": { + "release": { + "type": "string", + "title": "release", + "description": "The release the control plane runs, \"v20261112.01\"." + }, + "machineImage": { + "type": "string", + "title": "machine_image", + "description": "The machine image the control plane's machine booted, as its cloud names it." + } + }, + "title": "InstallationPlace", + "additionalProperties": false, + "description": "InstallationPlace is where the installation runs, as its control plane's machine read it once\n when it started - never asked of the cloud again per request - and the release it runs. What\n a cloud did not say, or an installation with no cloud (a development stack, a machine of one's\n own), is empty." + }, + "spin.v1.Job": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "name" + }, + "intervalSeconds": { + "type": "string", + "title": "interval_seconds", + "format": "int64", + "description": "Zero for a job only run by hand, which has no next_run_at." + }, + "running": { + "type": "boolean", + "title": "running" + }, + "nextRunAt": { "allOf": [ { "$ref": "#/components/schemas/google.protobuf.Timestamp" } ], - "title": "updated_at" + "title": "next_run_at", + "description": "When the schedule next starts it." }, - "telemetryTracesKeepPercent": { - "type": "integer", - "title": "telemetry_traces_keep_percent", - "format": "int32", - "description": "What the installation's collector keeps, decided at the collector\n (internal/controlplane/domain/telemetrypolicy). A trace with an error in any span is always kept, and so\n is one slower than telemetry_traces_slow_ms (0: none is kept for being slow); of the rest,\n telemetry_traces_keep_percent, 0 to 100 and 100 until an admin says otherwise." - }, - "telemetryTracesSlowMs": { - "type": "integer", - "title": "telemetry_traces_slow_ms", - "format": "int32" - }, - "telemetryMetricsDrop": { - "type": "array", - "items": { - "type": "string" - }, - "title": "telemetry_metrics_drop", - "description": "The metrics that are not kept, by name; a pattern may begin or end with *." - }, - "telemetryPerVolumeHistograms": { - "type": "array", - "items": { - "type": "string" - }, - "title": "telemetry_per_volume_histograms", - "description": "Read only: the metrics that cost most to keep, a histogram per volume, which a surface may\n offer to drop as one." - }, - "workspaceTrashDays": { - "type": "integer", - "title": "workspace_trash_days", - "format": "int32", - "description": "How many days a deleted workspace stays in the trash, whole, for its owner to undelete\n before it is erased: 0 is no trash, and 7 is what an installation that says nothing keeps." - }, - "identityAudiences": { - "type": "array", - "items": { - "type": "string" - }, - "title": "identity_audiences", - "description": "Who a workspace's identity token may be for; empty is anybody. What the installation's\n issuer gives, not who trusts it: a relying party still decides which subjects it admits." - }, - "volumeRpoSeconds": { - "type": "integer", - "title": "volume_rpo_seconds", - "format": "int32", - "description": "How far behind the object store a workspace's volume may fall, in seconds, where its preset\n does not say: what it commits on (v6 §11). 0 is none - it commits on its size and its\n snapshots alone - and 300 is what an installation that says nothing keeps." - }, - "diskReservePercent": { - "type": "integer", - "title": "disk_reserve_percent", - "format": "int32", - "description": "How a host's disk is lent to workspaces. A volume holds what it wrote, not its size: a host\n is charged, per volume, the larger of disk_reserve_percent of its size and what it wrote,\n and takes new ones up to 80% of its device; disk_commit_max_percent bounds the sizes\n summed - every volume filling at once. 50 and 200 are what an installation that says\n nothing lends; 100 and 100 lends nothing past what the device holds." - }, - "diskCommitMaxPercent": { - "type": "integer", - "title": "disk_commit_max_percent", - "format": "int32" - }, - "workspaceIdleSuspendMinutes": { - "type": "integer", - "title": "workspace_idle_suspend_minutes", - "format": "int32", - "description": "How many minutes a running workspace may go unused - nobody working over its ssh, editor or\n forwarded ports, and its cores all but still - before it is suspended with its processes,\n which its next start resumes. 0 suspends none; 60 is what an installation that says nothing\n keeps, and a week is the most." - }, - "workspaceMaxRunningMinutes": { - "type": "integer", - "title": "workspace_max_running_minutes", - "format": "int32", - "description": "How many minutes a workspace may run at a stretch, used or not, before it is suspended the\n same way: a process that keeps its cores busy is use to the rule above, and this is what\n ends it. Counted from its machine's start, which a resume is too. 0 caps none; 720 is what\n an installation that says nothing keeps, and a week is the most." - }, - "workspaceLeaseMaxMinutes": { - "type": "integer", - "title": "workspace_lease_max_minutes", - "format": "int32", - "description": "How many minutes a process may keep its workspace awake at a stretch (a lease:\n `spin-supervisor keep -- \u003ccmd\u003e`, a .spin.yaml task with keep_awake). While a lease is held\n and within this of its start, nobody is asked, nothing idle is suspended, and the running\n cap waits for the lease's end. 0 honours no lease; 480 is what an installation that says\n nothing keeps, and a week is the most." - }, - "teamSecretsRole": { - "type": "string", - "title": "team_secrets_role", - "description": "The IAM role a team's secret kept in Secrets Manager or Parameter Store is read under, in a\n session tagged spin-team-id with the team: its policy lets that session read only what carries\n the same tag. Empty, no secret is kept as a reference." - }, - "projectCreation": { - "type": "string", - "title": "project_creation", - "description": "Who makes projects (ProjectService.CreateProject): \"everyone\" signed in, or only the\n instance's \"admins\". Empty is everyone." - }, - "autoscalingIdleMinutes": { - "type": "integer", - "title": "autoscaling_idle_minutes", - "format": "int32", - "description": "How the runner fleet is sized (GetFleet): the minutes it may be idle before it is emptied,\n above zero; the quiet hours, HH:MM-HH:MM in the IANA time zone, when it is emptied at once,\n empty for none; and the most hosts it is asked for, under the group's own maximum - zero is\n that maximum. Each takes effect at the autoscaler's next pass." - }, - "autoscalingQuietHours": { - "type": "string", - "title": "autoscaling_quiet_hours" - }, - "autoscalingTimeZone": { - "type": "string", - "title": "autoscaling_time_zone" - }, - "autoscalingMaxHosts": { - "type": "integer", - "title": "autoscaling_max_hosts", - "format": "int32" - }, - "hostShellNeedsApproval": { - "type": "boolean", - "title": "host_shell_needs_approval", - "description": "A root shell on a host (HostShellService): whether a second administrator approves each one\n before its host is touched, and the most minutes one may be open, 30 where unset." - }, - "hostShellMaxMinutes": { - "type": "integer", - "title": "host_shell_max_minutes", - "format": "int32" - }, - "prebuildRetireUnusedDays": { - "type": "integer", - "title": "prebuild_retire_unused_days", - "format": "int32", - "description": "How many days a ready prebuild may go without a workspace opened from it before it is retired\n and its disk given back - the newest of its ref too, so a project nobody opens stops holding\n one, and its next open starts from the image. It is not built again until its ref moves to\n another commit, or an admin runs it. Counted from its build for one never opened. 0, what an\n installation that says nothing keeps, retires none for this; a year is the most." - } - }, - "title": "InstallationSettings", - "additionalProperties": false, - "description": "InstallationSettings contains global settings for the Spin installation" - }, - "spin.v1.Job": { - "type": "object", - "properties": { - "name": { - "type": "string", - "title": "name" - }, - "intervalSeconds": { - "type": "string", - "title": "interval_seconds", - "format": "int64", - "description": "Zero for a job only run by hand, which has no next_run_at." - }, - "running": { - "type": "boolean", - "title": "running" - }, - "nextRunAt": { - "allOf": [ - { - "$ref": "#/components/schemas/google.protobuf.Timestamp" - } - ], - "title": "next_run_at", - "description": "When the schedule next starts it." - }, - "lastRun": { - "allOf": [ - { - "$ref": "#/components/schemas/spin.v1.JobRun" - } - ], - "title": "last_run", - "description": "Unset until it has run on this installation." + "lastRun": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.JobRun" + } + ], + "title": "last_run", + "description": "Unset until it has run on this installation." }, "lastSucceededAt": { "allOf": [ @@ -20008,10 +21324,15 @@ "title": "title", "description": "The job as a person names it: \"Storage collection\" for storage-gc." }, - "purpose": { + "does": { "type": "string", - "title": "purpose", - "description": "One sentence of what it does and what stays undone while it fails." + "title": "does", + "description": "A sentence of what it does." + }, + "whileFailing": { + "type": "string", + "title": "while_failing", + "description": "What stays undone while it fails, said after \"While it fails, \": \"new workspaces start from\n an older prebuild\". What a failure's verdict says, so whoever reads it knows how soon it\n needs them." }, "recentRuns": { "type": "array", @@ -20079,7 +21400,7 @@ "traceId": { "type": "string", "title": "trace_id", - "description": "The run's trace, empty when it was not recorded." + "description": "The run's trace id, which every record it logged carries; empty when it was not recorded.\n Whether the store kept the trace is LogService.KeptTraces's to say." }, "askedBy": { "type": "string", @@ -20136,6 +21457,36 @@ "title": "KeepWorkspaceResponse", "additionalProperties": false }, + "spin.v1.KeptTracesRequest": { + "type": "object", + "properties": { + "traceIds": { + "type": "array", + "items": { + "type": "string" + }, + "title": "trace_ids", + "description": "Hex, as a log record carries them: at most 1000, a page's." + } + }, + "title": "KeptTracesRequest", + "additionalProperties": false + }, + "spin.v1.KeptTracesResponse": { + "type": "object", + "properties": { + "traceIds": { + "type": "array", + "items": { + "type": "string" + }, + "title": "trace_ids", + "description": "Those of the request's the store holds, each once." + } + }, + "title": "KeptTracesResponse", + "additionalProperties": false + }, "spin.v1.ListAPIKeysRequest": { "type": "object", "properties": { @@ -20232,6 +21583,25 @@ "title": "ListAgentVolumesResponse", "additionalProperties": false }, + "spin.v1.ListAlertsRequest": { + "type": "object", + "title": "ListAlertsRequest", + "additionalProperties": false + }, + "spin.v1.ListAlertsResponse": { + "type": "object", + "properties": { + "alerts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.Alert" + }, + "title": "alerts" + } + }, + "title": "ListAlertsResponse", + "additionalProperties": false + }, "spin.v1.ListAllowedEmailsRequest": { "type": "object", "properties": { @@ -20498,6 +21868,38 @@ "title": "ListHostClassesResponse", "additionalProperties": false }, + "spin.v1.ListHostProblemsRequest": { + "type": "object", + "properties": { + "hostId": { + "type": "string", + "title": "host_id", + "description": "The one host asked about; empty for every host of the fleet." + } + }, + "title": "ListHostProblemsRequest", + "additionalProperties": false + }, + "spin.v1.ListHostProblemsResponse": { + "type": "object", + "properties": { + "problems": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.Problem" + }, + "title": "problems", + "description": "At most 20, hosts that are not connected first; problem_count is how many there are." + }, + "problemCount": { + "type": "integer", + "title": "problem_count", + "format": "int32" + } + }, + "title": "ListHostProblemsResponse", + "additionalProperties": false + }, "spin.v1.ListHostShellsRequest": { "type": "object", "properties": { @@ -20733,6 +22135,26 @@ "title": "ListNotificationsResponse", "additionalProperties": false }, + "spin.v1.ListOwnAgentThreadsRequest": { + "type": "object", + "title": "ListOwnAgentThreadsRequest", + "additionalProperties": false + }, + "spin.v1.ListOwnAgentThreadsResponse": { + "type": "object", + "properties": { + "workspaces": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.WorkspaceAgentThreads" + }, + "title": "workspaces", + "description": "One per workspace of the caller's whose supervisor reported a chat, in project then workspace\n name order; a workspace in the trash is not here." + } + }, + "title": "ListOwnAgentThreadsResponse", + "additionalProperties": false + }, "spin.v1.ListPasskeysRequest": { "type": "object", "title": "ListPasskeysRequest", @@ -20846,6 +22268,25 @@ "title": "ListProjectsResponse", "additionalProperties": false }, + "spin.v1.ListRefusedVolumesRequest": { + "type": "object", + "title": "ListRefusedVolumesRequest", + "additionalProperties": false + }, + "spin.v1.ListRefusedVolumesResponse": { + "type": "object", + "properties": { + "volumes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.RefusedVolume" + }, + "title": "volumes" + } + }, + "title": "ListRefusedVolumesResponse", + "additionalProperties": false + }, "spin.v1.ListRegistrationTokensRequest": { "type": "object", "properties": { @@ -21307,12 +22748,124 @@ "title": "ListTeamsResponse", "additionalProperties": false }, - "spin.v1.ListUserAPIKeysRequest": { + "spin.v1.ListTimelineRequest": { "type": "object", + "anyOf": [ + { + "type": "object", + "properties": { + "hostId": { + "type": "string", + "title": "host_id" + } + }, + "title": "host_id" + }, + { + "type": "object", + "properties": { + "projectId": { + "type": "string", + "title": "project_id" + } + }, + "title": "project_id" + }, + { + "type": "object", + "properties": { + "teamId": { + "type": "string", + "title": "team_id" + } + }, + "title": "team_id" + }, + { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "title": "workspace_id", + "description": "The one sample: a request names one of these at most." + } + }, + "title": "workspace_id" + } + ], + "unevaluatedProperties": false, + "not": { + "allOf": [ + { + "anyOf": [ + { + "required": [ + "hostId" + ] + }, + { + "required": [ + "projectId" + ] + }, + { + "required": [ + "teamId" + ] + }, + { + "required": [ + "workspaceId" + ] + } + ] + }, + { + "not": { + "oneOf": [ + { + "required": [ + "hostId" + ] + }, + { + "required": [ + "projectId" + ] + }, + { + "required": [ + "teamId" + ] + }, + { + "required": [ + "workspaceId" + ] + } + ] + } + } + ] + }, "properties": { - "userId": { - "type": "string", - "title": "user_id" + "since": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "since", + "description": "Inclusive; unset reads from as far back as the records go." + }, + "until": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "until", + "description": "Exclusive; unset is now." }, "page": { "allOf": [ @@ -21320,21 +22873,21 @@ "$ref": "#/components/schemas/spin.v1.PageRequest" } ], - "title": "page" + "title": "page", + "description": "page_size is at most 200, and zero is 50. total_count is not counted." } }, - "title": "ListUserAPIKeysRequest", - "additionalProperties": false + "title": "ListTimelineRequest" }, - "spin.v1.ListUserAPIKeysResponse": { + "spin.v1.ListTimelineResponse": { "type": "object", "properties": { - "apiKeys": { + "events": { "type": "array", "items": { - "$ref": "#/components/schemas/spin.v1.APIKey" + "$ref": "#/components/schemas/spin.v1.TimelineEvent" }, - "title": "api_keys" + "title": "events" }, "page": { "allOf": [ @@ -21343,14 +22896,24 @@ } ], "title": "page" + }, + "keptDays": { + "type": "integer", + "title": "kept_days", + "format": "int32", + "description": "kept_days is how long what the timeline reads is kept (ListWorkspaceTimelineResponse)." } }, - "title": "ListUserAPIKeysResponse", + "title": "ListTimelineResponse", "additionalProperties": false }, - "spin.v1.ListUsersRequest": { + "spin.v1.ListUserAPIKeysRequest": { "type": "object", "properties": { + "userId": { + "type": "string", + "title": "user_id" + }, "page": { "allOf": [ { @@ -21358,9 +22921,46 @@ } ], "title": "page" - }, - "query": { - "type": "string", + } + }, + "title": "ListUserAPIKeysRequest", + "additionalProperties": false + }, + "spin.v1.ListUserAPIKeysResponse": { + "type": "object", + "properties": { + "apiKeys": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.APIKey" + }, + "title": "api_keys" + }, + "page": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.PageResponse" + } + ], + "title": "page" + } + }, + "title": "ListUserAPIKeysResponse", + "additionalProperties": false + }, + "spin.v1.ListUsersRequest": { + "type": "object", + "properties": { + "page": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.PageRequest" + } + ], + "title": "page" + }, + "query": { + "type": "string", "title": "query", "description": "Optional: filter by name or email" }, @@ -21475,6 +23075,72 @@ "title": "ListWorkspaceQuarantineDenialsResponse", "additionalProperties": false }, + "spin.v1.ListWorkspaceTimelineRequest": { + "type": "object", + "properties": { + "id": { + "type": "string", + "title": "id" + }, + "since": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "since", + "description": "Inclusive; unset reads from as far back as the records go." + }, + "until": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "until", + "description": "Exclusive; unset is now." + }, + "page": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.PageRequest" + } + ], + "title": "page", + "description": "page_size is at most 200, and zero is 50. total_count is not counted." + } + }, + "title": "ListWorkspaceTimelineRequest", + "additionalProperties": false + }, + "spin.v1.ListWorkspaceTimelineResponse": { + "type": "object", + "properties": { + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.TimelineEvent" + }, + "title": "events" + }, + "page": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.PageResponse" + } + ], + "title": "page" + }, + "keptDays": { + "type": "integer", + "title": "kept_days", + "format": "int32", + "description": "kept_days is how long what the timeline reads is kept: before it, an empty timeline is the\n records gone, not nothing having happened." + } + }, + "title": "ListWorkspaceTimelineResponse", + "additionalProperties": false + }, "spin.v1.ListWorkspacesRequest": { "type": "object", "properties": { @@ -22081,10 +23747,19 @@ "email": { "type": "boolean", "title": "email" + }, + "installationEvent": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.InstallationEventType" + } + ], + "title": "installation_event" } }, "title": "NotificationPreference", - "additionalProperties": false + "additionalProperties": false, + "description": "One kind of event and whether the caller is emailed about it: a workspace's event, or the\n installation's (an administrator's alone). Exactly one of event and installation_event is set." }, "spin.v1.ObservedDestination": { "type": "object", @@ -22385,6 +24060,28 @@ "title": "PasswordLoginResponse", "additionalProperties": false }, + "spin.v1.PlatformCost": { + "type": "object", + "properties": { + "role": { + "type": "string", + "title": "role", + "description": "As the resources carry it (on AWS, their spin:role tag); empty where they carry none, which\n is said as untagged." + }, + "service": { + "type": "string", + "title": "service" + }, + "micros": { + "type": "string", + "title": "micros", + "format": "int64" + } + }, + "title": "PlatformCost", + "additionalProperties": false, + "description": "What one role's resources of one of the cloud's services cost, in millionths of the bill's\n currency: the control plane, the proxy and the database are three roles of one EC2." + }, "spin.v1.PlatformImage": { "type": "object", "properties": { @@ -22695,6 +24392,15 @@ "title": "stored_bytes", "format": "int64", "description": "What it keeps in the object store, as storage-gc last read it; unset before a reading\n counted it." + }, + "buildWorkspaceId": { + "type": "string", + "title": "build_workspace_id", + "description": "The workspace that ran its build (workspaces.prebuild_id), while its row is kept, and whose it\n is: its events, logs and traces are its owner's to read, and no list of workspaces shows it." + }, + "buildWorkspaceOwnerId": { + "type": "string", + "title": "build_workspace_owner_id" } }, "title": "Prebuild", @@ -22741,6 +24447,37 @@ "Superseded and given back: its snapshot is being deleted." ] }, + "spin.v1.PrebuildsKept": { + "type": "object", + "properties": { + "storedBytes": { + "type": "string", + "title": "stored_bytes", + "format": "int64", + "description": "As the store was last read (Admin's Storage, PREBUILD)." + }, + "day": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "day", + "description": "The billed day the rate is from: its first instant, UTC. Unset, with month_micros, where no day\n before the reading billed the bucket, or the prebuilds keep nothing." + }, + "monthMicros": { + "type": [ + "string", + "null" + ], + "title": "month_micros", + "format": "int64" + } + }, + "title": "PrebuildsKept", + "additionalProperties": false, + "description": "What a project's prebuilds keep in the volumes' bucket, and what that would cost a month at what\n the last billed day charged: an estimate, never said without the day it is from." + }, "spin.v1.PreemptionSource": { "type": "string", "title": "PreemptionSource", @@ -22752,6 +24489,237 @@ ], "description": "PreemptionSource mirrors spin.agent.v1.PreemptionSource, which is what reaches the host." }, + "spin.v1.Problem": { + "type": "object", + "properties": { + "cause": { + "type": "string", + "title": "cause", + "description": "cause says in a line what was found." + }, + "since": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "since", + "description": "since is when what decided it was so, as HealthCheck.known_at is: a host's command stream\n last heard, a check's last run, a job's failed run. Unset where nothing says." + }, + "impact": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.ProblemImpact" + } + ], + "title": "impact" + }, + "evidence": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.ProblemEvidence" + }, + "title": "evidence", + "description": "What shows it, each a thing the console has a page for." + }, + "runbookId": { + "type": "string", + "title": "runbook_id", + "description": "The runbook to follow (Runbook.id), of the runbooks this release serves: never empty." + }, + "actions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.ProblemAction" + }, + "title": "actions", + "description": "What the console itself can do about it, each on the host or the job the problem is of." + }, + "hostId": { + "type": "string", + "title": "host_id", + "description": "The host the problem is of, and the name its machine goes by; empty for one that is not a\n host's." + }, + "hostname": { + "type": "string", + "title": "hostname" + }, + "job": { + "type": "string", + "title": "job", + "description": "The job (Job.name) the problem is of, and its title; empty for one that is not a job's." + }, + "jobTitle": { + "type": "string", + "title": "job_title" + } + }, + "title": "Problem", + "additionalProperties": false, + "description": "Problem is one thing wrong with the installation, said whole: why, what it takes down, what\n shows it and what to do. Nothing is kept of it - it is read off the installation as it is now,\n and is gone when what caused it is." + }, + "spin.v1.ProblemAction": { + "type": "string", + "title": "ProblemAction", + "enum": [ + "PROBLEM_ACTION_UNSPECIFIED", + "PROBLEM_ACTION_CORDON_HOST", + "PROBLEM_ACTION_DRAIN_HOST", + "PROBLEM_ACTION_RUN_JOB", + "PROBLEM_ACTION_RECOVER_WORKSPACE" + ], + "description": "ProblemAction is something the console can do about a problem, each an RPC it has.\n\n- `PROBLEM_ACTION_CORDON_HOST`: DrainHost without suspend: the host takes no new workspace and keeps what it runs.\n- `PROBLEM_ACTION_DRAIN_HOST`: DrainHost with suspend: its workspaces are moved to other hosts.\n- `PROBLEM_ACTION_RUN_JOB`: RunJobNow: the job is run again, now.\n- `PROBLEM_ACTION_RECOVER_WORKSPACE`: RecoverUserWorkspace, of each workspace the problem names: its disk is on a host that is gone,\n and it runs again only once moved off it.", + "x-enum-descriptions": [ + "", + "DrainHost without suspend: the host takes no new workspace and keeps what it runs.", + "DrainHost with suspend: its workspaces are moved to other hosts.", + "RunJobNow: the job is run again, now.", + "RecoverUserWorkspace, of each workspace the problem names: its disk is on a host that is gone,\n and it runs again only once moved off it." + ] + }, + "spin.v1.ProblemEvidence": { + "type": "object", + "anyOf": [ + { + "type": "object", + "properties": { + "hostId": { + "type": "string", + "title": "host_id", + "description": "A host: its page under Admin → Runners." + } + }, + "title": "host_id" + }, + { + "type": "object", + "properties": { + "job": { + "type": "string", + "title": "job", + "description": "A job (Job.name): its runs under Admin → Jobs." + } + }, + "title": "job" + }, + { + "type": "object", + "properties": { + "logQuery": { + "type": "string", + "title": "log_query", + "description": "A query of the log store, as SearchPlatformLogs takes it." + } + }, + "title": "log_query" + }, + { + "type": "object", + "properties": { + "traceId": { + "type": "string", + "title": "trace_id", + "description": "A trace: a failed job run's." + } + }, + "title": "trace_id" + } + ], + "unevaluatedProperties": false, + "not": { + "allOf": [ + { + "anyOf": [ + { + "required": [ + "hostId" + ] + }, + { + "required": [ + "job" + ] + }, + { + "required": [ + "logQuery" + ] + }, + { + "required": [ + "traceId" + ] + } + ] + }, + { + "not": { + "oneOf": [ + { + "required": [ + "hostId" + ] + }, + { + "required": [ + "job" + ] + }, + { + "required": [ + "logQuery" + ] + }, + { + "required": [ + "traceId" + ] + } + ] + } + } + ] + }, + "title": "ProblemEvidence", + "description": "ProblemEvidence names one thing that shows a problem. The console turns each into a link to\n its own page; none is a URL." + }, + "spin.v1.ProblemImpact": { + "type": "object", + "properties": { + "stops": { + "type": "string", + "title": "stops", + "description": "What stops working, in a line: \"log lines are not kept\". Empty where the rows say it." + }, + "runningWorkspaces": { + "type": "integer", + "title": "running_workspaces", + "format": "int32", + "description": "The workspaces it affects, counted whole: running on the host now, and at rest with their\n disk only there - stopped or failed, each one's next start is on that host. For workspaces\n waiting for a host, waiting_workspaces." + }, + "restingWorkspaces": { + "type": "integer", + "title": "resting_workspaces", + "format": "int32" + }, + "waitingWorkspaces": { + "type": "integer", + "title": "waiting_workspaces", + "format": "int32" + }, + "workspaces": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.AffectedWorkspace" + }, + "title": "workspaces", + "description": "At most 10 of them, the running first, then by name: the counts above are the whole." + } + }, + "title": "ProblemImpact", + "additionalProperties": false, + "description": "ProblemImpact is what a problem takes down: the workspaces under it as rows of the database,\n or, for a part with nothing under it, what stops working." + }, "spin.v1.Project": { "type": "object", "properties": { @@ -23050,54 +25018,31 @@ "spin.v1.QuarantineWorkspaceResponse": { "type": "object", "properties": { - "workspace": { + "workspaceId": { + "type": "string", + "title": "workspace_id" + }, + "name": { + "type": "string", + "title": "name" + }, + "state": { "allOf": [ { - "$ref": "#/components/schemas/spin.v1.Workspace" + "$ref": "#/components/schemas/spin.v1.WorkspaceState" } ], - "title": "workspace" - } - }, - "title": "QuarantineWorkspaceResponse", - "additionalProperties": false - }, - "spin.v1.RateLimitSettings": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "title": "enabled", - "description": "Enable rate limiting" - }, - "authRequestsPerMinute": { - "type": "integer", - "title": "auth_requests_per_minute", - "format": "int32", - "description": "Auth endpoints (login, token exchange, etc.) Requests per minute for auth endpoints" - }, - "authBurst": { - "type": "integer", - "title": "auth_burst", - "format": "int32", - "description": "Burst allowance for auth endpoints" - }, - "apiRequestsPerMinute": { - "type": "integer", - "title": "api_requests_per_minute", - "format": "int32", - "description": "API endpoints (all other endpoints) Requests per minute for API endpoints" + "title": "state" }, - "apiBurst": { - "type": "integer", - "title": "api_burst", - "format": "int32", - "description": "Burst allowance for API endpoints" + "quarantineHeld": { + "type": "boolean", + "title": "quarantine_held", + "description": "Held, as Workspace.quarantine_held: a running workspace answers STOPPING, and this is what\n says the stop is the quarantine's." } }, - "title": "RateLimitSettings", + "title": "QuarantineWorkspaceResponse", "additionalProperties": false, - "description": "RateLimitSettings configures API rate limiting" + "description": "The workspace as the quarantine left it, and no more of it: an administrator acts on a\n workspace that need not be theirs, and the rest of its row - its env - is its owner's (I27)." }, "spin.v1.ReadFileRequest": { "type": "object", @@ -23127,6 +25072,43 @@ "title": "ReadFileResponse", "additionalProperties": false }, + "spin.v1.RecoverUserWorkspaceRequest": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "title": "workspace_id", + "description": "The workspace's id." + }, + "acceptDataLoss": { + "type": "boolean", + "title": "accept_data_loss", + "description": "False asks what it would cost. True accepts that cost, for its owner, and does it." + }, + "reason": { + "type": "string", + "title": "reason", + "description": "Why: required, kept on the audit entry and on the workspace's history for its owner." + } + }, + "title": "RecoverUserWorkspaceRequest", + "additionalProperties": false + }, + "spin.v1.RecoverUserWorkspaceResponse": { + "type": "object", + "properties": { + "recovery": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.RecoverWorkspaceResponse" + } + ], + "title": "recovery" + } + }, + "title": "RecoverUserWorkspaceResponse", + "additionalProperties": false + }, "spin.v1.RecoverWorkspaceRequest": { "type": "object", "properties": { @@ -23202,14 +25184,70 @@ "title": "port", "description": "For tcp and udp; zero otherwise." }, - "packets": { + "packets": { + "type": "string", + "title": "packets", + "format": "int64" + } + }, + "title": "RefusedDestination", + "additionalProperties": false + }, + "spin.v1.RefusedVolume": { + "type": "object", + "properties": { + "volumeId": { + "type": "string", + "title": "volume_id" + }, + "refusal": { + "type": "string", + "title": "refusal", + "description": "The token an alert keys on, and the sentence the host sent with it (VolumeStatus)." + }, + "refusalDetail": { + "type": "string", + "title": "refusal_detail" + }, + "hostId": { + "type": "string", + "title": "host_id", + "description": "The host refusing it; empty for a disk placed nowhere." + }, + "hostName": { + "type": "string", + "title": "host_name" + }, + "workspaceId": { + "type": "string", + "title": "workspace_id", + "description": "The workspace it is the disk of; empty for a disk no workspace runs on." + }, + "workspaceName": { + "type": "string", + "title": "workspace_name" + }, + "workspaceState": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.WorkspaceState" + } + ], + "title": "workspace_state" + }, + "ownerId": { + "type": "string", + "title": "owner_id", + "description": "Whose the workspace is." + }, + "ownerEmail": { "type": "string", - "title": "packets", - "format": "int64" + "title": "owner_email" } }, - "title": "RefusedDestination", - "additionalProperties": false + "title": "RefusedVolume", + "additionalProperties": false, + "description": "RefusedVolume is a disk its host is not serving, and the workspace that cannot run for it." }, "spin.v1.RegisterPasskeyRequest": { "type": "object", @@ -23413,17 +25451,30 @@ "spin.v1.ReleaseWorkspaceQuarantineResponse": { "type": "object", "properties": { - "workspace": { + "workspaceId": { + "type": "string", + "title": "workspace_id" + }, + "name": { + "type": "string", + "title": "name" + }, + "state": { "allOf": [ { - "$ref": "#/components/schemas/spin.v1.Workspace" + "$ref": "#/components/schemas/spin.v1.WorkspaceState" } ], - "title": "workspace" + "title": "state" + }, + "quarantineHeld": { + "type": "boolean", + "title": "quarantine_held" } }, "title": "ReleaseWorkspaceQuarantineResponse", - "additionalProperties": false + "additionalProperties": false, + "description": "The workspace as the release left it, and no more of it, as QuarantineWorkspaceResponse." }, "spin.v1.ReleaseWorkspaceResourcesRequest": { "type": "object", @@ -23473,6 +25524,16 @@ "id": { "type": "string", "title": "id" + }, + "taken": { + "type": "boolean", + "title": "taken", + "description": "The host is believed taken - compromised - rather than only no longer wanted. Its credentials\n are deleted and its stream cut before its group is asked anything, and every team's disk whose\n key it was given is marked for re-keying. A routine removal - a scale-in, a machine reclaimed -\n leaves it unset, and marks none." + }, + "leaveWorkspaces": { + "type": "boolean", + "title": "leave_workspaces", + "description": "Remove a taken host although it is the only home of workspaces' disks. Refused without it,\n naming them; with it each runs again only once it is recovered onto another host\n (RecoverWorkspace), which gives up what this host had not published. Only with taken: a\n routine removal loses no disk." } }, "title": "RemoveHostRequest", @@ -23499,6 +25560,17 @@ "type": "boolean", "title": "forgotten", "description": "forgotten is the host's row gone. A host given back while connected is not: it drains under\n its termination hook, and its row goes when its stream ends." + }, + "markedForRekey": { + "type": "integer", + "title": "marked_for_rekey", + "format": "int32", + "description": "marked_for_rekey is how many teams' disks were marked for re-keying: those whose key a host\n removed as taken was given. Zero for a routine removal." + }, + "kept": { + "type": "string", + "title": "kept", + "description": "kept is why the row was not forgotten, where it was not and should have been: the workspace\n whose disk is only there, or the volume that would not leave it and whose that is. Empty\n when forgotten, and for a host given back while connected." } }, "title": "RemoveHostResponse", @@ -23723,7 +25795,7 @@ "type": "integer", "title": "rpo_seconds", "format": "int32", - "description": "How far behind the object store a workspace of it may fall, in seconds; 0 is the\n installation's (InstallationSettings.volume_rpo_seconds)." + "description": "How far behind the object store a workspace of it may fall, in seconds; 0 is the\n installation's (the setting volume_rpo_seconds)." }, "hostClass": { "type": "string", @@ -23740,6 +25812,12 @@ "type": "boolean", "title": "from_config", "description": "Seeded or applied from the installation's config file (the release's presets where it names\n none); false is one an administrator added. An edit since does not change it." + }, + "minMemoryMb": { + "type": "integer", + "title": "min_memory_mb", + "format": "int32", + "description": "The least any preset may start its workspaces at, in MB: memory_mb for a fixed one,\n burst_floor_memory_mb for a burst one. A create or update below it is refused; one written\n before it was asked keeps what it has until an administrator changes it." } }, "title": "ResourcePreset", @@ -23966,6 +26044,24 @@ "title": "RevokeUserAPIKeyResponse", "additionalProperties": false }, + "spin.v1.RoleCost": { + "type": "object", + "properties": { + "role": { + "type": "string", + "title": "role", + "description": "Empty where the resources carry none." + }, + "micros": { + "type": "string", + "title": "micros", + "format": "int64" + } + }, + "title": "RoleCost", + "additionalProperties": false, + "description": "What one role cost on one day, its services summed." + }, "spin.v1.RunJobNowRequest": { "type": "object", "properties": { @@ -24464,46 +26560,15 @@ "additionalProperties": false, "description": "The spans found, each marked as about the workspace asked for, and how many the store holds." }, - "spin.v1.SecuritySettings": { + "spin.v1.SendTestAlertRequest": { "type": "object", - "properties": { - "rateLimit": { - "allOf": [ - { - "$ref": "#/components/schemas/spin.v1.RateLimitSettings" - } - ], - "title": "rate_limit", - "description": "Rate limiting configuration" - }, - "sessionDurationHours": { - "type": "integer", - "title": "session_duration_hours", - "format": "int32", - "description": "Session configuration Session token lifetime in hours (default: 168 = 7 days)" - }, - "allowWorkspaceSharing": { - "type": "boolean", - "title": "allow_workspace_sharing", - "description": "Access control Allow users to share workspaces" - }, - "allowPublicWorkspaces": { - "type": "boolean", - "title": "allow_public_workspaces", - "description": "Allow publicly accessible workspace URLs" - }, - "updatedAt": { - "allOf": [ - { - "$ref": "#/components/schemas/google.protobuf.Timestamp" - } - ], - "title": "updated_at" - } - }, - "title": "SecuritySettings", - "additionalProperties": false, - "description": "SecuritySettings contains security-related configuration" + "title": "SendTestAlertRequest", + "additionalProperties": false + }, + "spin.v1.SendTestAlertResponse": { + "type": "object", + "title": "SendTestAlertResponse", + "additionalProperties": false }, "spin.v1.ServiceCost": { "type": "object", @@ -24760,34 +26825,36 @@ "title": "SetPortAccessResponse", "additionalProperties": false }, - "spin.v1.SetRegistrationModeRequest": { + "spin.v1.SetSettingsRequest": { "type": "object", "properties": { - "mode": { - "allOf": [ - { - "$ref": "#/components/schemas/spin.v1.RegistrationMode" - } - ], - "title": "mode" + "values": { + "type": "object", + "title": "values", + "additionalProperties": { + "type": "string", + "title": "value" + }, + "description": "The settings to write, by key, as text of each one's type. Only ADMIN settings are taken." } }, - "title": "SetRegistrationModeRequest", + "title": "SetSettingsRequest", "additionalProperties": false }, - "spin.v1.SetRegistrationModeResponse": { + "spin.v1.SetSettingsResponse": { "type": "object", "properties": { - "mode": { - "allOf": [ - { - "$ref": "#/components/schemas/spin.v1.RegistrationMode" - } - ], - "title": "mode" + "values": { + "type": "object", + "title": "values", + "additionalProperties": { + "type": "string", + "title": "value" + }, + "description": "Every value in force once written, as GetSettings answers them." } }, - "title": "SetRegistrationModeResponse", + "title": "SetSettingsResponse", "additionalProperties": false }, "spin.v1.SetSnapshotVisibilityRequest": { @@ -24877,7 +26944,7 @@ "ref": { "type": "string", "title": "ref", - "description": "In place of value: the ARN of a Secrets Manager secret or a Parameter Store parameter the team\n keeps it in, read as the team (InstallationSettings.team_secrets_role) now and whenever a host\n asks for it." + "description": "In place of value: the ARN of a Secrets Manager secret or a Parameter Store parameter the team\n keeps it in, read as the team (the setting team_secrets_role) now and whenever a host\n asks for it." } }, "title": "SetTeamSecretRequest", @@ -24908,18 +26975,32 @@ "spin.v1.SetWorkspaceBandwidthResponse": { "type": "object", "properties": { - "workspace": { + "workspaceId": { + "type": "string", + "title": "workspace_id" + }, + "name": { + "type": "string", + "title": "name" + }, + "state": { "allOf": [ { - "$ref": "#/components/schemas/spin.v1.Workspace" + "$ref": "#/components/schemas/spin.v1.WorkspaceState" } ], - "title": "workspace" + "title": "state" + }, + "bandwidthMbps": { + "type": "integer", + "title": "bandwidth_mbps", + "format": "int32", + "description": "Megabits a second each way now in force; zero is unshaped." } }, "title": "SetWorkspaceBandwidthResponse", "additionalProperties": false, - "description": "SetWorkspaceBandwidthResponse is the workspace as recorded, which its host is then sent: a host\n that cannot take the value leaves the machine as it was and is asked again by the next set." + "description": "SetWorkspaceBandwidthResponse is the bandwidth as recorded, which its host is then sent: a host\n that cannot take the value leaves the machine as it was and is asked again by the next set. It\n names the workspace and no more of it: the rest of its row - its env - is its owner's (I27)." }, "spin.v1.SetWorkspaceNetworkTagsRequest": { "type": "object", @@ -24991,6 +27072,91 @@ "title": "SetWorkspaceNetworkWatchResponse", "additionalProperties": false }, + "spin.v1.SettingDefinition": { + "type": "object", + "properties": { + "key": { + "type": "string", + "title": "key" + }, + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.SettingType" + } + ], + "title": "type" + }, + "defaultValue": { + "type": "string", + "title": "default_value", + "description": "What is in force where the installation says nothing, as text of the type." + }, + "min": { + "type": [ + "string", + "null" + ], + "title": "min", + "format": "int64" + }, + "max": { + "type": [ + "string", + "null" + ], + "title": "max", + "format": "int64" + }, + "choices": { + "type": "array", + "items": { + "type": "string" + }, + "title": "choices", + "description": "The values a STRING setting takes; empty is any." + }, + "reach": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.SettingReach" + } + ], + "title": "reach", + "description": "What it touches once saved." + }, + "restart": { + "type": "boolean", + "title": "restart", + "description": "It is read when the control plane starts: a change is in force after its next restart." + }, + "section": { + "type": "string", + "title": "section", + "description": "Which page it is on: general, workspaces, fleet, network, security, registration,\n telemetry, logs, bill, email, storage, installation, control_plane." + }, + "label": { + "type": "string", + "title": "label", + "description": "A few words that name it, and a sentence that says what it does and what its zero means." + }, + "summary": { + "type": "string", + "title": "summary" + }, + "writer": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.SettingWriter" + } + ], + "title": "writer" + } + }, + "title": "SettingDefinition", + "additionalProperties": false, + "description": "SettingDefinition is one setting of the installation as the code defines it." + }, "spin.v1.SettingReach": { "type": "string", "title": "SettingReach", @@ -25002,7 +27168,7 @@ "SETTING_REACH_NEXT_REQUEST", "SETTING_REACH_NEXT_PASS" ], - "description": "SettingReach is what a saved installation setting touches, and when: each setting declares one\n beside its key (internal/controlplane/settings), so the screen that edits it can say so before\n the save.\n\n- `SETTING_REACH_RUNNING_WORKSPACES`: The workspaces running now, at the control plane's next look at them.\n- `SETTING_REACH_NEW_WORKSPACES`: Workspaces created from now on; those that exist keep what they were made with.\n- `SETTING_REACH_NEXT_HEARTBEAT`: Each runner at its next heartbeat, and the workspaces running on it.\n- `SETTING_REACH_NEXT_REQUEST`: What is asked from now on - a project made, a shell opened, a workspace deleted; what was\n done before keeps the terms it was done under.\n- `SETTING_REACH_NEXT_PASS`: The next pass of the job that applies it: the autoscaler, the prebuilds' retirement, the\n collector's read of its policy, the daily look for a release.", + "description": "SettingReach is what a saved installation setting touches, and when: each setting's definition\n declares one (internal/controlplane/settings), so the screen that edits it can say so before\n the save.\n\n- `SETTING_REACH_RUNNING_WORKSPACES`: The workspaces running now, at the control plane's next look at them.\n- `SETTING_REACH_NEW_WORKSPACES`: Workspaces created from now on; those that exist keep what they were made with.\n- `SETTING_REACH_NEXT_HEARTBEAT`: Each runner at its next heartbeat, and the workspaces running on it.\n- `SETTING_REACH_NEXT_REQUEST`: What is asked from now on - a project made, a shell opened, a workspace deleted; what was\n done before keeps the terms it was done under.\n- `SETTING_REACH_NEXT_PASS`: The next pass of the job that applies it: the autoscaler, the prebuilds' retirement, the\n collector's read of its policy, the daily look for a release.", "x-enum-descriptions": [ "", "The workspaces running now, at the control plane's next look at them.", @@ -25012,6 +27178,48 @@ "The next pass of the job that applies it: the autoscaler, the prebuilds' retirement, the\n collector's read of its policy, the daily look for a release." ] }, + "spin.v1.SettingType": { + "type": "string", + "title": "SettingType", + "enum": [ + "SETTING_TYPE_UNSPECIFIED", + "SETTING_TYPE_INT", + "SETTING_TYPE_BOOL", + "SETTING_TYPE_STRING", + "SETTING_TYPE_LIST", + "SETTING_TYPE_JSON", + "SETTING_TYPE_DURATION" + ], + "description": "SettingType is how a setting's value is written as text, which is how GetSettings answers it\n and SetSettings takes it.\n\n- `SETTING_TYPE_INT`: A whole number in decimal, within the definition's min and max.\n- `SETTING_TYPE_BOOL`: \"true\" or \"false\".\n- `SETTING_TYPE_STRING`: Text; a definition with choices takes only those.\n- `SETTING_TYPE_LIST`: A JSON array of strings.\n- `SETTING_TYPE_JSON`: A JSON document, as the code that reads it defines it.\n- `SETTING_TYPE_DURATION`: A Go duration (\"60s\"); min and max are seconds.", + "x-enum-descriptions": [ + "", + "A whole number in decimal, within the definition's min and max.", + "\"true\" or \"false\".", + "Text; a definition with choices takes only those.", + "A JSON array of strings.", + "A JSON document, as the code that reads it defines it.", + "A Go duration (\"60s\"); min and max are seconds." + ] + }, + "spin.v1.SettingWriter": { + "type": "string", + "title": "SettingWriter", + "enum": [ + "SETTING_WRITER_UNSPECIFIED", + "SETTING_WRITER_ADMIN", + "SETTING_WRITER_FILE", + "SETTING_WRITER_STORE", + "SETTING_WRITER_CONTROL_PLANE" + ], + "description": "SettingWriter is who writes a setting, and so where an administrator changes it.\n\n- `SETTING_WRITER_ADMIN`: SetSettings, and the installation's file seeds it.\n- `SETTING_WRITER_FILE`: The installation's file alone: what whoever made the installation knows, and a change of\n which the dashboard cannot make whole - the proxy holds the base domain too.\n- `SETTING_WRITER_STORE`: A page of its own, which checks it against the real thing before it is written: the object\n store, the mail server.\n- `SETTING_WRITER_CONTROL_PLANE`: The control plane, for itself.", + "x-enum-descriptions": [ + "", + "SetSettings, and the installation's file seeds it.", + "The installation's file alone: what whoever made the installation knows, and a change of\n which the dashboard cannot make whole - the proxy holds the base domain too.", + "A page of its own, which checks it against the real thing before it is written: the object\n store, the mail server.", + "The control plane, for itself." + ] + }, "spin.v1.ShareProjectRequest": { "type": "object", "properties": { @@ -25302,6 +27510,41 @@ "additionalProperties": false, "description": "Span is one operation of a trace, as OpenTelemetry names its parts." }, + "spin.v1.StandbyCost": { + "type": "object", + "properties": { + "day": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "day", + "description": "The billed day it is from: its first instant, UTC." + }, + "platform": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.RoleCost" + }, + "title": "platform", + "description": "The platform by role, costliest first." + }, + "idleMicros": { + "type": "string", + "title": "idle_micros", + "format": "int64" + }, + "unstoredMicros": { + "type": "string", + "title": "unstored_micros", + "format": "int64" + } + }, + "title": "StandbyCost", + "additionalProperties": false, + "description": "What the installation cost on its last billed day before the reading with nobody's work\n counted: the platform, the runners' capacity no workspace held, and the bucket's bytes no\n workspace keeps. An estimate of a day nobody works: that day is over, the next may be charged\n otherwise, and a day people worked held some of the runners - so it is never said without its\n day (finops.StandbyOf)." + }, "spin.v1.StartAppCreationRequest": { "type": "object", "properties": { @@ -25592,6 +27835,52 @@ "The supervisor reports a failing health check." ] }, + "spin.v1.StopUserWorkspaceRequest": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "title": "workspace_id", + "description": "The workspace's id: an administrator names no workspace of somebody else's by its name." + }, + "force": { + "type": "boolean", + "title": "force", + "description": "Give up what only its host has rather than publish it first, as StopWorkspace's force does." + }, + "reason": { + "type": "string", + "title": "reason", + "description": "Why, kept on the audit entry." + } + }, + "title": "StopUserWorkspaceRequest", + "additionalProperties": false + }, + "spin.v1.StopUserWorkspaceResponse": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "title": "workspace_id" + }, + "name": { + "type": "string", + "title": "name" + }, + "state": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.WorkspaceState" + } + ], + "title": "state" + } + }, + "title": "StopUserWorkspaceResponse", + "additionalProperties": false, + "description": "The workspace as the stop left it, and no more of it: the rest of its row is its owner's." + }, "spin.v1.StopWorkspaceRequest": { "type": "object", "properties": { @@ -26092,6 +28381,30 @@ "title": "TeamSecret", "additionalProperties": false }, + "spin.v1.TeamWorkspaceCost": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "title": "workspace_id" + }, + "name": { + "type": "string", + "title": "name" + }, + "share": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.CostShare" + } + ], + "title": "share" + } + }, + "title": "TeamWorkspaceCost", + "additionalProperties": false, + "description": "What one of a team's workspaces cost in the month." + }, "spin.v1.TelemetryFlow": { "type": "object", "properties": { @@ -26258,6 +28571,118 @@ "title": "ThirdPartyTermsItem", "additionalProperties": false }, + "spin.v1.TimelineActor": { + "type": "string", + "title": "TimelineActor", + "enum": [ + "TIMELINE_ACTOR_UNSPECIFIED", + "TIMELINE_ACTOR_PERSON", + "TIMELINE_ACTOR_CONTROL_PLANE", + "TIMELINE_ACTOR_HOST" + ], + "description": "TimelineActor is who or what did what a TimelineEvent says.\n\n- `TIMELINE_ACTOR_PERSON`: A person signed in, named by actor_id.\n- `TIMELINE_ACTOR_CONTROL_PLANE`: The control plane, on its own: a reconciliation, a sweep, a job, a decision nobody asked for.\n- `TIMELINE_ACTOR_HOST`: A host, of itself: it joined, said it was going, lost its stream or came back.", + "x-enum-descriptions": [ + "", + "A person signed in, named by actor_id.", + "The control plane, on its own: a reconciliation, a sweep, a job, a decision nobody asked for.", + "A host, of itself: it joined, said it was going, lost its stream or came back." + ] + }, + "spin.v1.TimelineEvent": { + "type": "object", + "properties": { + "source": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.TimelineSource" + } + ], + "title": "source", + "description": "The record it is read from, and that record's id there: the evidence a reader opens." + }, + "id": { + "type": "string", + "title": "id" + }, + "at": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "at" + }, + "actor": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.TimelineActor" + } + ], + "title": "actor", + "description": "Who or what did it." + }, + "actorId": { + "type": "string", + "title": "actor_id", + "description": "The person, when actor is PERSON: empty for one whose account has since been deleted, and\n the email is what their row says now." + }, + "actorEmail": { + "type": "string", + "title": "actor_email" + }, + "what": { + "type": "string", + "title": "what", + "description": "What happened, in its source's own words: an audit action (host_state_changed), a workspace\n event type without its prefix (FAILED), a failed job run's job (storage-gc), or for a\n prebuild prebuild_started, prebuild_built or prebuild_failed." + }, + "resourceType": { + "type": "string", + "title": "resource_type", + "description": "What it happened to: an audit entry's resource_type and id (workspace, host, settings, job by\n its name), the workspace of a workspace event, the job of a run, the project of a prebuild." + }, + "resourceId": { + "type": "string", + "title": "resource_id" + }, + "resourceName": { + "type": "string", + "title": "resource_name", + "description": "The name a person knows it by, where the installation still has its row: a workspace's, a\n host's machine's, a team's, a project's. Empty otherwise." + }, + "details": { + "type": "string", + "title": "details", + "description": "The JSON the record keeps, verbatim: an audit entry's details, a workspace event's, a failed\n run's counts and error, a prebuild's ref, commit and error." + }, + "traceId": { + "type": "string", + "title": "trace_id", + "description": "The trace of the request or the run that did it; empty when none was sampled. Whether the\n store kept it is LogService.KeptTraces's to say." + } + }, + "title": "TimelineEvent", + "additionalProperties": false, + "description": "TimelineEvent is one thing that happened, read from the record that keeps it - the audit log, a\n workspace's events, a job's runs, a project's prebuilds - and never a copy of it." + }, + "spin.v1.TimelineSource": { + "type": "string", + "title": "TimelineSource", + "enum": [ + "TIMELINE_SOURCE_UNSPECIFIED", + "TIMELINE_SOURCE_AUDIT", + "TIMELINE_SOURCE_WORKSPACE_EVENT", + "TIMELINE_SOURCE_JOB_RUN", + "TIMELINE_SOURCE_PREBUILD" + ], + "description": "TimelineSource is the record a TimelineEvent is read from.\n\n- `TIMELINE_SOURCE_AUDIT`: An audit entry (AuditEntry.id).\n- `TIMELINE_SOURCE_WORKSPACE_EVENT`: A workspace's event (WorkspaceEvent.id).\n- `TIMELINE_SOURCE_JOB_RUN`: A job's run that failed (JobRun.run_id).\n- `TIMELINE_SOURCE_PREBUILD`: A project's prebuild (Prebuild.id).", + "x-enum-descriptions": [ + "", + "An audit entry (AuditEntry.id).", + "A workspace's event (WorkspaceEvent.id).", + "A job's run that failed (JobRun.run_id).", + "A project's prebuild (Prebuild.id)." + ] + }, "spin.v1.UndeleteWorkspaceRequest": { "type": "object", "properties": { @@ -26420,45 +28845,6 @@ "title": "UpdateHostClassResponse", "additionalProperties": false }, - "spin.v1.UpdateInstallationSettingsRequest": { - "type": "object", - "properties": { - "settings": { - "allOf": [ - { - "$ref": "#/components/schemas/spin.v1.InstallationSettings" - } - ], - "title": "settings" - }, - "updateMask": { - "allOf": [ - { - "$ref": "#/components/schemas/google.protobuf.FieldMask" - } - ], - "title": "update_mask", - "description": "Required: only the named fields of settings are written, so a form that edits one\n setting cannot reset the others to their zero values." - } - }, - "title": "UpdateInstallationSettingsRequest", - "additionalProperties": false - }, - "spin.v1.UpdateInstallationSettingsResponse": { - "type": "object", - "properties": { - "settings": { - "allOf": [ - { - "$ref": "#/components/schemas/spin.v1.InstallationSettings" - } - ], - "title": "settings" - } - }, - "title": "UpdateInstallationSettingsResponse", - "additionalProperties": false - }, "spin.v1.UpdateNetworkPolicyRequest": { "type": "object", "properties": { @@ -26704,36 +29090,6 @@ "title": "UpdateResourcePresetResponse", "additionalProperties": false }, - "spin.v1.UpdateSecuritySettingsRequest": { - "type": "object", - "properties": { - "settings": { - "allOf": [ - { - "$ref": "#/components/schemas/spin.v1.SecuritySettings" - } - ], - "title": "settings" - } - }, - "title": "UpdateSecuritySettingsRequest", - "additionalProperties": false - }, - "spin.v1.UpdateSecuritySettingsResponse": { - "type": "object", - "properties": { - "settings": { - "allOf": [ - { - "$ref": "#/components/schemas/spin.v1.SecuritySettings" - } - ], - "title": "settings" - } - }, - "title": "UpdateSecuritySettingsResponse", - "additionalProperties": false - }, "spin.v1.UpdateStorageSettingsRequest": { "type": "object", "properties": { @@ -27742,6 +30098,52 @@ "Boot a suspended workspace from its disk, dropping its memory (StartWorkspaceRequest.from_disk):\n offered when that memory's machine is run by no host (Workspace.memory_machine_gone)." ] }, + "spin.v1.WorkspaceAgentThreads": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "title": "workspace_id" + }, + "workspaceName": { + "type": "string", + "title": "workspace_name" + }, + "state": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.WorkspaceState" + } + ], + "title": "state" + }, + "projectId": { + "type": "string", + "title": "project_id", + "description": "Empty for a workspace that opened no project." + }, + "projectName": { + "type": "string", + "title": "project_name" + }, + "environmentId": { + "type": "string", + "title": "environment_id", + "description": "As ListAgentThreadsResponse.environment_id: the first part of a thread's page." + }, + "threads": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.AgentThread" + }, + "title": "threads", + "description": "Newest first." + } + }, + "title": "WorkspaceAgentThreads", + "additionalProperties": false, + "description": "WorkspaceAgentThreads is one workspace's chats with what a rail names it by: the workspace, its\n state, and the project it opened." + }, "spin.v1.WorkspaceAttempt": { "type": "object", "properties": { @@ -27840,6 +30242,61 @@ "additionalProperties": false, "description": "What one workspace cost in the month, in millionths of the bill's currency, and whose it was on\n the last day it cost anything." }, + "spin.v1.WorkspaceDeparture": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "title": "workspace_id" + }, + "workspaceName": { + "type": "string", + "title": "workspace_name" + }, + "ownerEmail": { + "type": "string", + "title": "owner_email" + }, + "state": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.WorkspaceState" + } + ], + "title": "state" + }, + "drain": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.DepartureFate" + } + ], + "title": "drain", + "description": "What a drain that moves the host's workspaces (DrainHostRequest.suspend) does to it: MOVES or\n STAYS." + }, + "removal": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.DepartureFate" + } + ], + "title": "removal", + "description": "What Host.removal does to it: LOSES_PLACE or HOLDS. UNSPECIFIED where the host has no removal." + }, + "taken": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.DepartureFate" + } + ], + "title": "taken", + "description": "What removing the host as taken (RemoveHostRequest.taken) does to it: LOSES_PLACE or STOPS.\n UNSPECIFIED for a host that is revoked, whose revoke already is that." + } + }, + "title": "WorkspaceDeparture", + "additionalProperties": false, + "description": "WorkspaceDeparture is one workspace on a host and what each way of taking the host out does to it." + }, "spin.v1.WorkspaceDurability": { "type": "object", "properties": { @@ -27957,9 +30414,12 @@ "WORKSPACE_EVENT_TYPE_KEPT", "WORKSPACE_EVENT_TYPE_UNRESPONSIVE", "WORKSPACE_EVENT_TYPE_REHOMED", - "WORKSPACE_EVENT_TYPE_HELD" + "WORKSPACE_EVENT_TYPE_HELD", + "WORKSPACE_EVENT_TYPE_RECOVERED_BY_ADMIN", + "WORKSPACE_EVENT_TYPE_OUT_OF_MEMORY", + "WORKSPACE_EVENT_TYPE_OVERSIZED" ], - "description": "- `WORKSPACE_EVENT_TYPE_CREATED`: Workspace was created\n- `WORKSPACE_EVENT_TYPE_STARTED`: Workspace was started\n- `WORKSPACE_EVENT_TYPE_STOPPED`: Workspace was stopped; its disk is kept, and no snapshot is taken\n- `WORKSPACE_EVENT_TYPE_SNAPSHOT_CREATED`: Manual snapshot\n- `WORKSPACE_EVENT_TYPE_DELETED`: Workspace was deleted\n- `WORKSPACE_EVENT_TYPE_FAILED`: Workspace start failed\n- `WORKSPACE_EVENT_TYPE_RESTORED`: Its disk was put back to a snapshot\n- `WORKSPACE_EVENT_TYPE_RESUMED`: It went on from a snapshot's memory\n- `WORKSPACE_EVENT_TYPE_BOOTED`: Suspended, its memory could not be resumed, and its disk was booted\n- `WORKSPACE_EVENT_TYPE_QUARANTINED`: An administrator held it: stopped, and startable by nobody until released\n- `WORKSPACE_EVENT_TYPE_UNQUARANTINED`: The hold was released: back to stopped, where it was held from\n- `WORKSPACE_EVENT_TYPE_PLACED`: A workspace that waited for a host was given one, and its disk there\n- `WORKSPACE_EVENT_TYPE_TRASHED`: Deleted into the trash: its disk kept, its owner able to undelete it\n- `WORKSPACE_EVENT_TYPE_UNDELETED`: Taken back out of the trash\n- `WORKSPACE_EVENT_TYPE_MOVED`: Suspended on its host and resumed on another, which had room for what it was granted\n- `WORKSPACE_EVENT_TYPE_DISPLACED`: Its host was drained or went away: suspended there, it is resumed on another on its own\n- `WORKSPACE_EVENT_TYPE_STOP_BACKUP_FAILED`: A stop on a host that can be taken away could not publish its disk first, so it runs on\n- `WORKSPACE_EVENT_TYPE_IDLE_SUSPENDED`: Nobody used it for as long as the installation allows: suspended with its processes, a start resumes them\n- `WORKSPACE_EVENT_TYPE_RUNNING_CAP_SUSPENDED`: It ran at a stretch for as long as the installation allows: suspended with its processes, a start resumes them\n- `WORKSPACE_EVENT_TYPE_SUSPENSION_DUE`: A suspension is minutes away and the question was asked: its terminals, its page, the CLI; a keep answers it\n- `WORKSPACE_EVENT_TYPE_KEPT`: Somebody kept it awake until a time: no suspension before it\n- `WORKSPACE_EVENT_TYPE_UNRESPONSIVE`: Its supervisor said nothing for longer than the control plane waits: stopped by force, and a start brings it back\n- `WORKSPACE_EVENT_TYPE_REHOMED`: Its host stopped answering and it was moved to another on its own, giving up what that host had not published\n- `WORKSPACE_EVENT_TYPE_HELD`: Its host stopped answering and moving it would give up more than the installation does on its own: it waits for its owner", + "description": "- `WORKSPACE_EVENT_TYPE_CREATED`: Workspace was created\n- `WORKSPACE_EVENT_TYPE_STARTED`: Workspace was started\n- `WORKSPACE_EVENT_TYPE_STOPPED`: Workspace was stopped; its disk is kept, and no snapshot is taken\n- `WORKSPACE_EVENT_TYPE_SNAPSHOT_CREATED`: Manual snapshot\n- `WORKSPACE_EVENT_TYPE_DELETED`: Workspace was deleted\n- `WORKSPACE_EVENT_TYPE_FAILED`: Workspace start failed\n- `WORKSPACE_EVENT_TYPE_RESTORED`: Its disk was put back to a snapshot\n- `WORKSPACE_EVENT_TYPE_RESUMED`: It went on from a snapshot's memory\n- `WORKSPACE_EVENT_TYPE_BOOTED`: Suspended, its memory could not be resumed, and its disk was booted\n- `WORKSPACE_EVENT_TYPE_QUARANTINED`: An administrator held it: stopped, and startable by nobody until released\n- `WORKSPACE_EVENT_TYPE_UNQUARANTINED`: The hold was released: back to stopped, where it was held from\n- `WORKSPACE_EVENT_TYPE_PLACED`: A workspace that waited for a host was given one, and its disk there\n- `WORKSPACE_EVENT_TYPE_TRASHED`: Deleted into the trash: its disk kept, its owner able to undelete it\n- `WORKSPACE_EVENT_TYPE_UNDELETED`: Taken back out of the trash\n- `WORKSPACE_EVENT_TYPE_MOVED`: Suspended on its host and resumed on another, which had room for what it was granted\n- `WORKSPACE_EVENT_TYPE_DISPLACED`: Its host was drained or went away: suspended there, it is resumed on another on its own\n- `WORKSPACE_EVENT_TYPE_STOP_BACKUP_FAILED`: A stop on a host that can be taken away could not publish its disk first, so it runs on\n- `WORKSPACE_EVENT_TYPE_IDLE_SUSPENDED`: Nobody used it for as long as the installation allows: suspended with its processes, a start resumes them\n- `WORKSPACE_EVENT_TYPE_RUNNING_CAP_SUSPENDED`: It ran at a stretch for as long as the installation allows: suspended with its processes, a start resumes them\n- `WORKSPACE_EVENT_TYPE_SUSPENSION_DUE`: A suspension is minutes away and the question was asked: its terminals, its page, the CLI; a keep answers it\n- `WORKSPACE_EVENT_TYPE_KEPT`: Somebody kept it awake until a time: no suspension before it\n- `WORKSPACE_EVENT_TYPE_UNRESPONSIVE`: Its supervisor said nothing for longer than the control plane waits: stopped by force, and a start brings it back\n- `WORKSPACE_EVENT_TYPE_REHOMED`: Its host stopped answering and it was moved to another on its own, giving up what that host had not published\n- `WORKSPACE_EVENT_TYPE_HELD`: Its host stopped answering and moving it would give up more than the installation does on its own: it waits for its owner\n- `WORKSPACE_EVENT_TYPE_RECOVERED_BY_ADMIN`: An administrator moved it off a host that is gone, giving up for its owner what that host had not published; its details say who and why\n- `WORKSPACE_EVENT_TYPE_OUT_OF_MEMORY`: It ran out of memory: its guest's kernel killed a process (cause \"guest\", with the kills and\n their victims), its host found it short at its ceiling for a while (cause \"ceiling\"), or its\n host killed the machine (cause \"host\"). Its details say what it held, its grant and its\n ceiling. Said, never acted on: nothing resizes a workspace on its own.\n- `WORKSPACE_EVENT_TYPE_OVERSIZED`: It held far more than it used for a week: the most memory its processes used stayed under half\n its own, and a smaller preset would fit what it used. Its details say what it used, what it\n holds, and that preset. Said, never acted on: nothing resizes a workspace on its own.", "x-enum-descriptions": [ "", "Workspace was created", @@ -27985,7 +30445,10 @@ "Somebody kept it awake until a time: no suspension before it", "Its supervisor said nothing for longer than the control plane waits: stopped by force, and a start brings it back", "Its host stopped answering and it was moved to another on its own, giving up what that host had not published", - "Its host stopped answering and moving it would give up more than the installation does on its own: it waits for its owner" + "Its host stopped answering and moving it would give up more than the installation does on its own: it waits for its owner", + "An administrator moved it off a host that is gone, giving up for its owner what that host had not published; its details say who and why", + "It ran out of memory: its guest's kernel killed a process (cause \"guest\", with the kills and\n their victims), its host found it short at its ceiling for a while (cause \"ceiling\"), or its\n host killed the machine (cause \"host\"). Its details say what it held, its grant and its\n ceiling. Said, never acted on: nothing resizes a workspace on its own.", + "It held far more than it used for a week: the most memory its processes used stayed under half\n its own, and a smaller preset would fit what it used. Its details say what it used, what it\n holds, and that preset. Said, never acted on: nothing resizes a workspace on its own." ] }, "spin.v1.WorkspaceFailure": { @@ -28083,6 +30546,15 @@ "hostClass": { "type": "string", "title": "host_class" + }, + "machineType": { + "type": "string", + "title": "machine_type", + "description": "The host's machine as its cloud names it, said when the host joined (Host.machine_type,\n Host.zone): what kind of machine the workspace runs on, and where. Empty for a host that\n joined with no cloud. The machine's id and whether it may be taken back stay an\n administrator's." + }, + "zone": { + "type": "string", + "title": "zone" } }, "title": "WorkspaceHostStatus", @@ -28178,6 +30650,28 @@ "title": "WorkspaceLogFieldValuesResponse", "additionalProperties": false }, + "spin.v1.WorkspaceNetworkStatus": { + "type": "object", + "properties": { + "policy": { + "type": "string", + "title": "policy" + }, + "declared": { + "type": "boolean", + "title": "declared", + "description": "declared says a policy of this name exists: the installation's, or a team's." + }, + "installed": { + "type": "boolean", + "title": "installed", + "description": "installed says the workspace's host last reported enforcing a policy of this name. False\n for a workspace on no host." + } + }, + "title": "WorkspaceNetworkStatus", + "additionalProperties": false, + "description": "WorkspaceNetworkStatus is one policy a workspace runs under, and whether it holds there: the\n installation declares it, and the workspace's host reports having installed it. A tag no policy\n is declared for, or one its host has not installed, is what a start is refused over." + }, "spin.v1.WorkspacePhase": { "type": "string", "title": "WorkspacePhase", @@ -28555,6 +31049,12 @@ { "name": "AuthService" }, + { + "name": "WorkspaceService" + }, + { + "name": "SettingsService" + }, { "name": "AdminService", "description": "AdminService manages installation-wide settings, user management, and resource presets\n Only accessible to instance administrators --- Installation Settings ---" @@ -28580,17 +31080,11 @@ }, { "name": "ProjectService", - "description": "ProjectService is the installation's projects (spin#720): a repository and the shape of the\n workspace that opens it (CreateWorkspaceRequest.project_id). Anybody signed in makes one where\n the installation lets everybody (InstallationSettings.project_creation), and is its first admin.\n A project is seen by everybody while it is shared with everyone, and otherwise by its admins and\n whom it is shared with; the instance's admins see and administer every one. Whoever sees one\n opens workspaces from it, in a team of theirs." + "description": "ProjectService is the installation's projects (spin#720): a repository and the shape of the\n workspace that opens it (CreateWorkspaceRequest.project_id). Anybody signed in makes one where\n the installation lets everybody (the setting project_creation), and is its first admin.\n A project is seen by everybody while it is shared with everyone, and otherwise by its admins and\n whom it is shared with; the instance's admins see and administer every one. Whoever sees one\n opens workspaces from it, in a team of theirs." }, { "name": "RunnerTokenService" }, - { - "name": "WorkspaceService" - }, - { - "name": "SettingsService" - }, { "name": "SetupService", "description": "SetupService handles initial platform setup and admin bootstrap.\n Most endpoints require admin authentication, except GetSetupStatus and PasswordLogin." diff --git a/src/assets/shots/snapshots.png b/src/assets/shots/snapshots.png index 29ff62d663f32dcec05a15fe351ff1f31f7127c8..0ed4a28688539e8bba2580efebf0c833f88d412a 100644 GIT binary patch literal 67377 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 BV;2Ab diff --git a/src/assets/shots/workspace.png b/src/assets/shots/workspace.png index 95014c6eb6692761640c5352ef6b256cc1216981..5dd53977ef38c788b71e4ed725f1b9e6e17db672 100644 GIT binary patch literal 102889 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

?-E;jCx8uZw!pD2)uRlfK}p9f1Xr*^VE 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 Po`*<_D~Oef=>PaX6=9|d literal 108458 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⪙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 diff --git a/src/assets/shots/workspaces.png b/src/assets/shots/workspaces.png index fc7f800f25241f6452e2371acc86ae63061a4c39..61a40990a1e1b729c7345519f865dddac653ac77 100644 GIT binary patch literal 49793 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 diff --git a/src/content/docs/reference/api/adminservice.md b/src/content/docs/reference/api/adminservice.md index 1777dc8..f267b5b 100644 --- a/src/content/docs/reference/api/adminservice.md +++ b/src/content/docs/reference/api/adminservice.md @@ -4,7 +4,7 @@ description: "spin.v1.AdminService: each procedure, its request and its response source: "spin:internal/controlplane/apidocs/spin.v1.openapi.json" editUrl: false sidebar: - order: 3 + order: 5 --- @@ -241,7 +241,7 @@ What the installation cost in a month, as its cloud's bill says: by day and serv `POST /spin.v1.AdminService/GetCosts` -A month of the bill shared out to the workspaces that caused it: the runners' by what each workspace held of them, the volumes' bucket by what its volumes kept. What nobody caused is said apart and never spread: the runners' capacity nobody held, the bucket's bytes no workspace keeps, and the platform's own cost by service (internal/controlplane/domain/finops). +A month of the bill shared out to the workspaces that caused it: the runners' by what each workspace held of them, the volumes' bucket by what its volumes kept. What nobody caused is said apart and never spread: the runners' capacity nobody held, the bucket's bytes no workspace keeps, and the platform's own cost by role and service; and, from those, what the installation costs a day with nobody working (internal/controlplane/domain/finops). **Request** @@ -258,7 +258,10 @@ A month of the bill shared out to the workspaces that caused it: the runners' by | `workspaces` | list of [WorkspaceCost](/reference/api/types/#workspacecost) | Costliest first. | | `idleMicros` | string (int64) | What the runners cost that no workspace held. | | `unstoredMicros` | string (int64) | What the volumes' bucket cost for bytes no workspace keeps: the images, what nothing references any more. | -| `platform` | list of [ServiceCost](/reference/api/types/#servicecost) | Every other cost - the control plane, the proxy, keys, logs - by service, costliest first. | +| `platform` | list of [PlatformCost](/reference/api/types/#platformcost) | Every other cost - the control plane, the proxy, keys, logs - by role and service, costliest first. | +| `standby` | [StandbyCost](/reference/api/types/#standbycost) | What the installation costs a day with nobody working; unset where no day before the reading billed anything. | +| `readAt` | `Timestamp` | When the month's bill was last read; unset where it never was, and then nothing is answered. | +| `trend` | list of [CostMonth](/reference/api/types/#costmonth) | The year up to this month, oldest first, this month last: each month the bill was read in, shared out as this one is. A month never read is not among them. | ## GetEmailSettings @@ -312,25 +315,6 @@ No fields: `{}`. | `status` | [HealthStatus](/reference/api/types/#healthstatus) | status is the worst of the checks'. | | `checks` | list of [HealthCheck](/reference/api/types/#healthcheck) | One per part the installation has: a part it does not have - a database archive on a development stack, a log store where none is kept, a collector that never reported, jobs on a control plane that does not lead - is left out rather than answered for. | -## GetInstallationSettings - -`POST /spin.v1.AdminService/GetInstallationSettings` - -Get installation settings - -**Request** - -No fields: `{}`. - -**Response** - -| Field | Type | What it is | -|---|---|---| -| `settings` | [InstallationSettings](/reference/api/types/#installationsettings) | | -| `reaches` | map of string to [SettingReach](/reference/api/types/#settingreach) | What each setting touches when saved, by its update_mask path: every path UpdateInstallationSettings accepts, and no other. | -| `runningWorkspaces` | integer (int32) | How many workspaces are running now: what a RUNNING_WORKSPACES setting reaches, and what a NEW_WORKSPACES one leaves as it is. | -| `connectedRunners` | integer or null (int32) | How many runners hold their stream to this control plane now: what a NEXT_HEARTBEAT setting reaches. Unset where this control plane cannot tell. | - ## GetMonitoring `POST /spin.v1.AdminService/GetMonitoring` @@ -366,22 +350,6 @@ No fields: `{}`. | `supervisorReleases` | list of [ExtensionRelease](/reference/api/types/#extensionrelease) | Every release of the supervisor, newest first. | | `agentReleases` | list of [ExtensionRelease](/reference/api/types/#extensionrelease) | Every release of the agents' programs (Claude Code, Codex and T3 Code, one extension), newest first. | -## GetRegistrationMode - -`POST /spin.v1.AdminService/GetRegistrationMode` - -Get registration mode (open, whitelist, closed) - -**Request** - -No fields: `{}`. - -**Response** - -| Field | Type | What it is | -|---|---|---| -| `mode` | [RegistrationMode](/reference/api/types/#registrationmode) | | - ## GetRunbook `POST /spin.v1.AdminService/GetRunbook` @@ -402,11 +370,11 @@ One runbook, its markdown and where its file is at the pinned commit. NOT_FOUND | `markdown` | string | Its body, markdown without the front matter: the app renders it and nothing else (no raw HTML). | | `sourceUrl` | string | The file at the commit this release pins, to propose a change from. | -## GetSecuritySettings +## GetSettings -`POST /spin.v1.AdminService/GetSecuritySettings` +`POST /spin.v1.AdminService/GetSettings` -Get security settings +Every setting of the installation as it is in force, and what each is: its type, its default, its bounds, what it reaches when saved and who writes it (internal/controlplane/settings, the one registry the file, the dashboard and the CLI are made from). **Request** @@ -416,7 +384,11 @@ No fields: `{}`. | Field | Type | What it is | |---|---|---| -| `settings` | [SecuritySettings](/reference/api/types/#securitysettings) | | +| `values` | map of string to string | Every definition's value in force, by key, as text of its type: what the installation says, or the default where it says nothing. The control plane's own are left out. | +| `definitions` | list of [SettingDefinition](/reference/api/types/#settingdefinition) | Every setting an administrator is shown, in the registry's order. | +| `runningWorkspaces` | integer (int32) | How many workspaces are running now: what a RUNNING_WORKSPACES setting reaches, and what a NEW_WORKSPACES one leaves as it is. | +| `connectedRunners` | integer or null (int32) | How many runners hold their stream to this control plane now: what a NEXT_HEARTBEAT setting reaches. Unset where this control plane cannot tell. | +| `place` | [InstallationPlace](/reference/api/types/#installationplace) | Where the installation runs and what it runs, read-only. | ## GetStorageSettings @@ -472,6 +444,7 @@ No fields: `{}`. | `windowSeconds` | integer (int32) | How long the counts below are over. | | `spans` | [TelemetryFlow](/reference/api/types/#telemetryflow) | Into the installation's store, after the traces policy chose which to keep. | | `samples` | [TelemetryFlow](/reference/api/types/#telemetryflow) | Into the installation's store of metrics. | +| `perVolumeHistograms` | list of string | The metrics that cost most to keep, a histogram per volume, which a surface may offer to drop as one (the setting telemetry_metrics_drop). | ## GetThirdPartyTerms @@ -491,6 +464,25 @@ No fields: `{}`. | `text` | list of string | The terms, a paragraph each. | | `items` | list of [ThirdPartyTermsItem](/reference/api/types/#thirdpartytermsitem) | | +## GetUserWorkspaceEgress + +`POST /spin.v1.AdminService/GetUserWorkspaceEgress` + +Where a workspace sends, as its owner's GetWorkspaceEgress answers it: the host's counters by destination, nothing of what was carried. Audited, as a reading of somebody else's. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `workspaceId` | string | The workspace's id. | +| `reason` | string | Why, kept on the audit entry. | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `egress` | [GetWorkspaceEgressResponse](/reference/api/workspaceservice/#getworkspaceegress) | | + ## GetVSCodeServers `POST /spin.v1.AdminService/GetVSCodeServers` @@ -527,6 +519,22 @@ The names of the workspaces ids are, whoever owns them and whatever state they a |---|---|---| | `names` | map of string to string | Each id asked for that the installation holds a row for, to its workspace's name. | +## ListAlerts + +`POST /spin.v1.AdminService/ListAlerts` + +What the release's alert rules said in the installation's Grafana, newest first: each firing and each resolution the control plane heard, with its runbook and how many administrators it reached. + +**Request** + +No fields: `{}`. + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `alerts` | list of [Alert](/reference/api/types/#alert) | | + ## ListAllowedEmails `POST /spin.v1.AdminService/ListAllowedEmails` @@ -603,6 +611,25 @@ No fields: `{}`. |---|---|---| | `classes` | list of [HostClass](/reference/api/types/#hostclass) | | +## ListHostProblems + +`POST /spin.v1.AdminService/ListHostProblems` + +What is wrong with the fleet's hosts, one problem per host that is not connected or fails a check of its own: the same problems GetInstallationHealth's HOSTS part lists, for the pages that read one host or the fleet and nothing else of the installation. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `hostId` | string | The one host asked about; empty for every host of the fleet. | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `problems` | list of [Problem](/reference/api/types/#problem) | At most 20, hosts that are not connected first; problem_count is how many there are. | +| `problemCount` | integer (int32) | | + ## ListJobRuns `POST /spin.v1.AdminService/ListJobRuns` @@ -638,6 +665,22 @@ No fields: `{}`. |---|---|---| | `jobs` | list of [Job](/reference/api/types/#job) | | +## ListRefusedVolumes + +`POST /spin.v1.AdminService/ListRefusedVolumes` + +The disks a host refuses to serve, each with the workspace it is the disk of and whose that is. Audited. + +**Request** + +No fields: `{}`. + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `volumes` | list of [RefusedVolume](/reference/api/types/#refusedvolume) | | + ## ListRekeys `POST /spin.v1.AdminService/ListRekeys` @@ -690,6 +733,28 @@ No fields: `{}`. |---|---|---| | `runbooks` | list of [Runbook](/reference/api/types/#runbook) | | +## ListTimeline + +`POST /spin.v1.AdminService/ListTimeline` + +What happened, newest first, between two instants, to one workspace, host, team or project, or to the whole installation: read from the audit log, the workspaces' events, the jobs' failed runs and the projects' prebuilds as they are, never copied. Sign-ins and what is done inside a workspace (a session, a command) are the audit log's alone: they outnumber everything else. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `since` | `Timestamp` | Inclusive; unset reads from as far back as the records go. | +| `until` | `Timestamp` | Exclusive; unset is now. | +| `page` | [PageRequest](/reference/api/types/#pagerequest) | page_size is at most 200, and zero is 50. total_count is not counted. | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `events` | list of [TimelineEvent](/reference/api/types/#timelineevent) | | +| `page` | [PageResponse](/reference/api/types/#pageresponse) | | +| `keptDays` | integer (int32) | kept_days is how long what the timeline reads is kept (ListWorkspaceTimelineResponse). | + ## ListUserAPIKeys `POST /spin.v1.AdminService/ListUserAPIKeys` @@ -750,6 +815,26 @@ Publish the servers of the newest stable VS Code releases, or of the commits nam No fields: `{}`. +## RecoverUserWorkspace + +`POST /spin.v1.AdminService/RecoverUserWorkspace` + +Move a workspace off a host that is gone, as its owner's RecoverWorkspace does, and with the same question first: without accept_data_loss it answers what the move would give up and changes nothing. The work given up is its owner's, so a reason is required, kept on the audit entry, and written with who asked on the workspace's history, which its owner reads (WORKSPACE_EVENT_TYPE_RECOVERED_BY_ADMIN). Refused for a workspace held in quarantine. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `workspaceId` | string | The workspace's id. | +| `acceptDataLoss` | boolean | False asks what it would cost. True accepts that cost, for its owner, and does it. | +| `reason` | string | Why: required, kept on the audit entry and on the workspace's history for its owner. | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `recovery` | [RecoverWorkspaceResponse](/reference/api/workspaceservice/#recoverworkspace) | | + ## RekeyVolume `POST /spin.v1.AdminService/RekeyVolume` @@ -863,23 +948,59 @@ Run a job now rather than when it is next due. Refused while it is running: a se No fields: `{}`. -## SetRegistrationMode +## SendTestAlert + +`POST /spin.v1.AdminService/SendTestAlert` + +Has Grafana test its contact point, which sends a test alert the whole way an alert goes: Grafana, the control plane, an email to every administrator who has not opted out. FAILED_PRECONDITION where this control plane serves no Grafana, or Grafana could not reach the control plane. + +**Request** + +No fields: `{}`. + +**Response** + +No fields: `{}`. + +## SetSettings + +`POST /spin.v1.AdminService/SetSettings` + +Writes the settings named, each checked by its definition and all of them together before any is written: a refused one writes nothing. -`POST /spin.v1.AdminService/SetRegistrationMode` +**Request** + +| Field | Type | What it is | +|---|---|---| +| `values` | map of string to string | The settings to write, by key, as text of each one's type. Only ADMIN settings are taken. | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `values` | map of string to string | Every value in force once written, as GetSettings answers them. | + +## StopUserWorkspace -Set registration mode +`POST /spin.v1.AdminService/StopUserWorkspace` + +Stop a workspace, as its owner's StopWorkspace does: one whose stop could not publish its disk runs on and holds its host until somebody stops it. Audited. **Request** | Field | Type | What it is | |---|---|---| -| `mode` | [RegistrationMode](/reference/api/types/#registrationmode) | | +| `workspaceId` | string | The workspace's id: an administrator names no workspace of somebody else's by its name. | +| `force` | boolean | Give up what only its host has rather than publish it first, as StopWorkspace's force does. | +| `reason` | string | Why, kept on the audit entry. | **Response** | Field | Type | What it is | |---|---|---| -| `mode` | [RegistrationMode](/reference/api/types/#registrationmode) | | +| `workspaceId` | string | | +| `name` | string | | +| `state` | [WorkspaceState](/reference/api/types/#workspacestate) | | ## UntagImage @@ -935,25 +1056,6 @@ Set the SMTP server, checked against it - connected to and signed in to - before |---|---|---| | `class` | [HostClass](/reference/api/types/#hostclass) | | -## UpdateInstallationSettings - -`POST /spin.v1.AdminService/UpdateInstallationSettings` - -Update installation settings - -**Request** - -| Field | Type | What it is | -|---|---|---| -| `settings` | [InstallationSettings](/reference/api/types/#installationsettings) | | -| `updateMask` | `FieldMask` | Required: only the named fields of settings are written, so a form that edits one setting cannot reset the others to their zero values. | - -**Response** - -| Field | Type | What it is | -|---|---|---| -| `settings` | [InstallationSettings](/reference/api/types/#installationsettings) | | - ## UpdateNetworkPolicy `POST /spin.v1.AdminService/UpdateNetworkPolicy` @@ -1000,24 +1102,6 @@ Update a resource preset |---|---|---| | `preset` | [ResourcePreset](/reference/api/types/#resourcepreset) | | -## UpdateSecuritySettings - -`POST /spin.v1.AdminService/UpdateSecuritySettings` - -Update security settings - -**Request** - -| Field | Type | What it is | -|---|---|---| -| `settings` | [SecuritySettings](/reference/api/types/#securitysettings) | | - -**Response** - -| Field | Type | What it is | -|---|---|---| -| `settings` | [SecuritySettings](/reference/api/types/#securitysettings) | | - ## UpdateStorageSettings `POST /spin.v1.AdminService/UpdateStorageSettings` diff --git a/src/content/docs/reference/api/authservice.md b/src/content/docs/reference/api/authservice.md index e965fbf..9b3a24a 100644 --- a/src/content/docs/reference/api/authservice.md +++ b/src/content/docs/reference/api/authservice.md @@ -138,7 +138,7 @@ Create API key | `scopes` | list of string | e.g., ["workspace:read", "workspace:write"] | | `expiresAt` | `Timestamp` | | | `stepUp` | [PasskeyAssertion](/reference/api/types/#passkeyassertion) | An assertion of a passkey of the caller's over a PASSKEY_PURPOSE_CREATE_EXEC_KEY challenge naming the key, asked for a key with workspace:exec alone: that key is a shell, which a session alone does not open. | -| `teamId` | string | What it reaches and what its tree may hold: as APIKey's. Asked by a key holding keys:delegate, it is that key's child, and holds no more than it (delegation.Within). | +| `teamId` | string | What it reaches and what its tree may have running at once: as APIKey's, where what is counted is said. Asked by a key holding keys:delegate, it is that key's child, and holds no more than it (delegation.Within). | | `projectIds` | list of string | | | `maxWorkspaces` | integer or null (int32) | | | `maxCores` | integer or null (int32) | | diff --git a/src/content/docs/reference/api/execservice.md b/src/content/docs/reference/api/execservice.md index f728612..4059910 100644 --- a/src/content/docs/reference/api/execservice.md +++ b/src/content/docs/reference/api/execservice.md @@ -4,7 +4,7 @@ description: "spin.v1.ExecService: each procedure, its request and its response. source: "spin:internal/controlplane/apidocs/spin.v1.openapi.json" editUrl: false sidebar: - order: 4 + order: 6 --- diff --git a/src/content/docs/reference/api/forgeservice.md b/src/content/docs/reference/api/forgeservice.md index 84f1539..e5eb174 100644 --- a/src/content/docs/reference/api/forgeservice.md +++ b/src/content/docs/reference/api/forgeservice.md @@ -4,7 +4,7 @@ description: "spin.v1.ForgeService: each procedure, its request and its response source: "spin:internal/controlplane/apidocs/spin.v1.openapi.json" editUrl: false sidebar: - order: 5 + order: 7 --- diff --git a/src/content/docs/reference/api/hostservice.md b/src/content/docs/reference/api/hostservice.md index f8bba47..f97f529 100644 --- a/src/content/docs/reference/api/hostservice.md +++ b/src/content/docs/reference/api/hostservice.md @@ -4,7 +4,7 @@ description: "spin.v1.HostService: each procedure, its request and its response. source: "spin:internal/controlplane/apidocs/spin.v1.openapi.json" editUrl: false sidebar: - order: 6 + order: 8 --- @@ -88,6 +88,7 @@ Get host details (admin only) | Field | Type | What it is | |---|---|---| | `host` | [Host](/reference/api/types/#host) | | +| `departure` | [HostDeparture](/reference/api/types/#hostdeparture) | What taking the host out would do to each workspace on it, as the server would do it: asked of one host, because it reads every workspace there. | ## GetHostPolicy @@ -133,13 +134,15 @@ List all hosts (admin only) `POST /spin.v1.HostService/RemoveHost` -Takes a machine of an autoscaling group out of the fleet (admin only), as Host.removal says: given back to its group (GIVE_BACK), or forgotten (FORGET). A host whose removal is REVOKE is refused: RevokeRunner is its removal. +Takes a machine of an autoscaling group out of the fleet (admin only), as Host.removal says: given back to its group (GIVE_BACK), or forgotten (FORGET). A host whose removal is REVOKE is refused: RevokeRunner is its removal. Asked with taken, the host leaves as one believed compromised: its credentials revoked and every team's disk whose key it was given marked for re-keying (ListRekeys), as RevokeRunner does, and its machine given back all the same. **Request** | Field | Type | What it is | |---|---|---| | `id` | string | | +| `taken` | boolean | The host is believed taken - compromised - rather than only no longer wanted. Its credentials are deleted and its stream cut before its group is asked anything, and every team's disk whose key it was given is marked for re-keying. A routine removal - a scale-in, a machine reclaimed - leaves it unset, and marks none. | +| `leaveWorkspaces` | boolean | Remove a taken host although it is the only home of workspaces' disks. Refused without it, naming them; with it each runs again only once it is recovered onto another host (RecoverWorkspace), which gives up what this host had not published. Only with taken: a routine removal loses no disk. | **Response** @@ -148,6 +151,8 @@ Takes a machine of an autoscaling group out of the fleet (admin only), as Host.r | `removal` | [HostRemoval](/reference/api/types/#hostremoval) | removal is what was done: GIVE_BACK or FORGET. | | `givenBack` | boolean | given_back is the machine terminated and its group asked for one less; false where the group no longer had it. | | `forgotten` | boolean | forgotten is the host's row gone. A host given back while connected is not: it drains under its termination hook, and its row goes when its stream ends. | +| `markedForRekey` | integer (int32) | marked_for_rekey is how many teams' disks were marked for re-keying: those whose key a host removed as taken was given. Zero for a routine removal. | +| `kept` | string | kept is why the row was not forgotten, where it was not and should have been: the workspace whose disk is only there, or the volume that would not leave it and whose that is. Empty when forgotten, and for a host given back while connected. | ## SetHostPolicy diff --git a/src/content/docs/reference/api/hostshellservice.md b/src/content/docs/reference/api/hostshellservice.md index 8be481e..8a3e69d 100644 --- a/src/content/docs/reference/api/hostshellservice.md +++ b/src/content/docs/reference/api/hostshellservice.md @@ -4,7 +4,7 @@ description: "spin.v1.HostShellService: each procedure, its request and its resp source: "spin:internal/controlplane/apidocs/spin.v1.openapi.json" editUrl: false sidebar: - order: 7 + order: 9 --- diff --git a/src/content/docs/reference/api/index.md b/src/content/docs/reference/api/index.md index f027cb8..c0be152 100644 --- a/src/content/docs/reference/api/index.md +++ b/src/content/docs/reference/api/index.md @@ -22,18 +22,18 @@ curl -s https://app.example.com/spin.v1.WorkspaceService/ListWorkspaces \ - [PasskeyService](/reference/api/passkeyservice/): PasskeyService is a person's passkeys: WebAuthn credentials of their account, under the. installation's base domain (internal/passkey). A passkey signs a challenge the control plane. issued, never a document: what turns a session into a key that logs in (SSHKeyService.AddSSHKey) is an assertion of one, so a session alone - stolen, or an agent's - is no shell. - [AuthService](/reference/api/authservice/): 16 procedures +- [WorkspaceService](/reference/api/workspaceservice/): 57 procedures +- [SettingsService](/reference/api/settingsservice/): 6 procedures - [AdminService](/reference/api/adminservice/): AdminService manages installation-wide settings, user management, and resource presets. Only accessible to instance administrators. - [ExecService](/reference/api/execservice/): ExecService runs commands and moves files in a running workspace, as its root, for a caller who. is no terminal: a program or an agent holding a key with workspace:exec. The control plane logs. in over the same session a terminal's goes over (a host's stream from the guest's vsock, met at. the control plane rather than at the relay) with a certificate of its own for five minutes, and. every call is recorded with who made it and on which credential (audit: workspace_exec). - [ForgeService](/reference/api/forgeservice/): ForgeService is a person's account on a forge, connected through the installation's GitHub App. (spin#758): the control plane keeps the token, lists the person's repositories with it, and a. host's egress proxy sets it on their workspaces' brokered requests. No workspace holds it. - [HostService](/reference/api/hostservice/): 9 procedures - [HostShellService](/reference/api/hostshellservice/): HostShellService is a root shell on a host, asked for by an administrator, for a while, with a. reason (spin#712). The host is emptied of its workspaces first - unless the request is an. incident's, which says so - and retired after, whatever happened in it: once a person has had root. on a host it runs no workspace again. Every session is recorded by the control plane, which. carries it; the terminal itself is a WebSocket at /api/host-shells/<id>/terminal. (internal/hostshell). - [LogService](/reference/api/logservice/): LogService is what the installation logged, as its store of logs and traces keeps it. (internal/logstore). Every search is confined by the control plane to what the caller may see; what the caller types is searched inside that and cannot widen it. -- [ProjectService](/reference/api/projectservice/): ProjectService is the installation's projects (spin#720): a repository and the shape of the. workspace that opens it (CreateWorkspaceRequest.project_id). Anybody signed in makes one where. the installation lets everybody (InstallationSettings.project_creation), and is its first admin. A project is seen by everybody while it is shared with everyone, and otherwise by its admins and. whom it is shared with; the instance's admins see and administer every one. Whoever sees one. opens workspaces from it, in a team of theirs. +- [ProjectService](/reference/api/projectservice/): ProjectService is the installation's projects (spin#720): a repository and the shape of the. workspace that opens it (CreateWorkspaceRequest.project_id). Anybody signed in makes one where. the installation lets everybody (the setting project_creation), and is its first admin. A project is seen by everybody while it is shared with everyone, and otherwise by its admins and. whom it is shared with; the instance's admins see and administer every one. Whoever sees one. opens workspaces from it, in a team of theirs. - [RunnerTokenService](/reference/api/runnertokenservice/): 4 procedures -- [WorkspaceService](/reference/api/workspaceservice/): 53 procedures -- [SettingsService](/reference/api/settingsservice/): 6 procedures - [SetupService](/reference/api/setupservice/): SetupService handles initial platform setup and admin bootstrap. Most endpoints require admin authentication, except GetSetupStatus and PasswordLogin. - [ShareService](/reference/api/shareservice/): ShareService manages snapshot sharing. Snapshots can be shared with specific users or made public. Users can create new workspaces from shared snapshots. - [SSHKeyService](/reference/api/sshkeyservice/): SSHKeyService is the keys that log in as the person, to every workspace that lets them in: a key. of their own, for good, or a browser's or a CLI's enrolled for twelve hours. Each is added with an. assertion of a passkey of theirs (PasskeyService), so a session alone adds none. -- [TeamService](/reference/api/teamservice/): 18 procedures +- [TeamService](/reference/api/teamservice/): 19 procedures - [Types](/reference/api/types/): every message and enum the procedures name diff --git a/src/content/docs/reference/api/logservice.md b/src/content/docs/reference/api/logservice.md index 38dd57a..6f6b92c 100644 --- a/src/content/docs/reference/api/logservice.md +++ b/src/content/docs/reference/api/logservice.md @@ -4,7 +4,7 @@ description: "spin.v1.LogService: each procedure, its request and its response." source: "spin:internal/controlplane/apidocs/spin.v1.openapi.json" editUrl: false sidebar: - order: 8 + order: 10 --- @@ -91,6 +91,24 @@ HistogramWorkspaceLogs is how many of those records each interval of the window |---|---|---| | `intervals` | list of [LogInterval](/reference/api/types/#loginterval) | | +## KeptTraces + +`POST /spin.v1.LogService/KeptTraces` + +KeptTraces is which of the trace ids a page shows the store holds: those, and only those, are links. A trace id is written where its span began, before the collector decides whether to keep the trace, and it stays after the store's retention has deleted it. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `traceIds` | list of string | Hex, as a log record carries them: at most 1000, a page's. | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `traceIds` | list of string | Those of the request's the store holds, each once. | + ## ListLogIndexes `POST /spin.v1.LogService/ListLogIndexes` diff --git a/src/content/docs/reference/api/projectservice.md b/src/content/docs/reference/api/projectservice.md index a2b402f..34e63b5 100644 --- a/src/content/docs/reference/api/projectservice.md +++ b/src/content/docs/reference/api/projectservice.md @@ -4,12 +4,12 @@ description: "spin.v1.ProjectService: each procedure, its request and its respon source: "spin:internal/controlplane/apidocs/spin.v1.openapi.json" editUrl: false sidebar: - order: 9 + order: 11 --- -ProjectService is the installation's projects (spin#720): a repository and the shape of the. workspace that opens it (CreateWorkspaceRequest.project_id). Anybody signed in makes one where. the installation lets everybody (InstallationSettings.project_creation), and is its first admin. A project is seen by everybody while it is shared with everyone, and otherwise by its admins and. whom it is shared with; the instance's admins see and administer every one. Whoever sees one. opens workspaces from it, in a team of theirs. +ProjectService is the installation's projects (spin#720): a repository and the shape of the. workspace that opens it (CreateWorkspaceRequest.project_id). Anybody signed in makes one where. the installation lets everybody (the setting project_creation), and is its first admin. A project is seen by everybody while it is shared with everyone, and otherwise by its admins and. whom it is shared with; the instance's admins see and administer every one. Whoever sees one. opens workspaces from it, in a team of theirs. ## CreateProject @@ -87,6 +87,28 @@ One of them whole, with what its build's create tasks wrote, to whoever sees the |---|---|---| | `project` | [Project](/reference/api/types/#project) | | +## GetProjectCosts + +`POST /spin.v1.ProjectService/GetProjectCosts` + +What a project cost in the month in progress, to its admins and nobody else, as ListProjectWorkspaces: everybody's workspaces of it summed, its prebuilds' builds included, and a month of what its prebuilds keep. A sum, never by workspace: one workspace's cost says how much its owner works, which a project's admin who is not their team's is not told. Read from the bill as the installation last read it, never from the cloud. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `projectId` | string | | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `month` | `Timestamp` | The month in progress: its first instant, UTC. | +| `readAt` | `Timestamp` | When the bill was last read; unset where it never was - an installation with no bill scope - and then nothing below is known and nothing is to be drawn. | +| `currency` | string | ISO 4217; every amount here is in millionths of it. | +| `workspaces` | [CostShare](/reference/api/types/#costshare) | Its workspaces' shares summed, deleted ones and its prebuilds' builds included: a workspace is the project's it opened, whoever's it was. | +| `prebuilds` | [PrebuildsKept](/reference/api/types/#prebuildskept) | | + ## ListPrebuilds `POST /spin.v1.ProjectService/ListPrebuilds` diff --git a/src/content/docs/reference/api/runnertokenservice.md b/src/content/docs/reference/api/runnertokenservice.md index f5b100d..efd0698 100644 --- a/src/content/docs/reference/api/runnertokenservice.md +++ b/src/content/docs/reference/api/runnertokenservice.md @@ -4,7 +4,7 @@ description: "spin.v1.RunnerTokenService: each procedure, its request and its re source: "spin:internal/controlplane/apidocs/spin.v1.openapi.json" editUrl: false sidebar: - order: 10 + order: 12 --- diff --git a/src/content/docs/reference/api/settingsservice.md b/src/content/docs/reference/api/settingsservice.md index 2f92d8a..ea81f35 100644 --- a/src/content/docs/reference/api/settingsservice.md +++ b/src/content/docs/reference/api/settingsservice.md @@ -4,7 +4,7 @@ description: "spin.v1.SettingsService: each procedure, its request and its respo source: "spin:internal/controlplane/apidocs/spin.v1.openapi.json" editUrl: false sidebar: - order: 12 + order: 4 --- @@ -13,7 +13,7 @@ sidebar: `POST /spin.v1.SettingsService/GetNotificationPreferences` -Which of those the caller is emailed about. +Which of those the caller is emailed about, and for an administrator which of the installation's events besides. **Request** @@ -23,7 +23,7 @@ No fields: `{}`. | Field | Type | What it is | |---|---|---| -| `preferences` | list of [NotificationPreference](/reference/api/types/#notificationpreference) | One per event a person may be told of, in the order they are shown. | +| `preferences` | list of [NotificationPreference](/reference/api/types/#notificationpreference) | One per event a person may be told of, in the order they are shown: an administrator's include the installation's. | | `emailConfigured` | boolean | | ## GetUserSettings diff --git a/src/content/docs/reference/api/teamservice.md b/src/content/docs/reference/api/teamservice.md index 925f6b4..bbaab55 100644 --- a/src/content/docs/reference/api/teamservice.md +++ b/src/content/docs/reference/api/teamservice.md @@ -153,6 +153,28 @@ Get team by ID or path | `team` | [Team](/reference/api/types/#team) | | | `currentUserRole` | [TeamRole](/reference/api/types/#teamrole) | Role of the requesting user in this team | +## GetTeamCosts + +`POST /spin.v1.TeamService/GetTeamCosts` + +What the team's workspaces cost in the month in progress, each and summed, for the team's admins: a member reads their own workspace's (WorkspaceService.GetWorkspaceCost) and nobody else's. A workspace is the team's whose it was on the last day it cost anything; a team below this one is not counted in it. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `teamId` | string | | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `month` | `Timestamp` | The month in progress: its first instant, UTC. | +| `readAt` | `Timestamp` | When the bill was last read; unset where it never was - an installation with no bill scope - and then nothing below is known and nothing is to be drawn. | +| `currency` | string | ISO 4217; every amount here is in millionths of it. | +| `total` | [CostShare](/reference/api/types/#costshare) | Its workspaces, summed. | +| `workspaces` | list of [TeamWorkspaceCost](/reference/api/types/#teamworkspacecost) | Costliest first. | + ## ListIdentityProviders `POST /spin.v1.TeamService/ListIdentityProviders` @@ -278,7 +300,7 @@ A team's secrets: what a brokered network rule has the host's egress proxy add t | `name` | string | Lower-case letters, digits and dashes, starting with a letter; what a rule names it by. | | `value` | string | At most 8 KiB of visible ASCII. Replaces what the name held. | | `hosts` | list of string | The exact names the secret may be sent to, 1 to 16: a brokered rule that injects it and names any other host is refused it. | -| `ref` | string | In place of value: the ARN of a Secrets Manager secret or a Parameter Store parameter the team keeps it in, read as the team (InstallationSettings.team_secrets_role) now and whenever a host asks for it. | +| `ref` | string | In place of value: the ARN of a Secrets Manager secret or a Parameter Store parameter the team keeps it in, read as the team (the setting team_secrets_role) now and whenever a host asks for it. | **Response** diff --git a/src/content/docs/reference/api/types.md b/src/content/docs/reference/api/types.md index 09cfd00..d6a3aca 100644 --- a/src/content/docs/reference/api/types.md +++ b/src/content/docs/reference/api/types.md @@ -24,9 +24,17 @@ sidebar: | `depth` | integer (int32) | | | `teamId` | string | The one team it reaches; empty for every team its person is in. Of that team, the projects it reaches; empty for any. | | `projectIds` | list of string | | -| `maxWorkspaces` | integer or null (int32) | What the workspaces its tree made may hold at once; unset for no bound past its person's. | +| `maxWorkspaces` | integer or null (int32) | How many of the workspaces its tree made - this key and every key delegated from it - may be on a runner at once, and how many cores those may hold: bounds on what runs, unset for none past its person's. A workspace counts while it is being made or started, runs, is stopping or waits for a runner. One that is stopped, suspended or in the trash counts for nothing, whatever disk it keeps, and is counted again when it is started: a start past the bound is refused as a create is, naming the workspaces that hold it. | | `maxCores` | integer or null (int32) | | +## AffectedWorkspace + +| Field | Type | What it is | +|---|---|---| +| `id` | string | | +| `name` | string | | +| `state` | [WorkspaceState](/reference/api/types/#workspacestate) | | + ## AgentThread AgentThread is one of the agent's threads as T3 Code names it: what a person is shown of a chat without opening it. @@ -52,6 +60,27 @@ AgentVolume is one agent home of the caller's. | `workspaceId` | string | The workspace mounting it, or empty for one no workspace mounts - which a new workspace may. | | `workspaceName` | string | The name of the workspace that mounts it, or mounted it last. | +## Alert + +Alert is one firing or one resolution of an alert rule, as Grafana sent it. + +| Field | Type | What it is | +|---|---|---| +| `id` | string | The installation event's id. | +| `event` | [InstallationEventType](/reference/api/types/#installationeventtype) | | +| `name` | string | The rule's title (Grafana's alertname). | +| `summary` | string | The rule's summary, rendered for what fired; empty where it has none. | +| `description` | string | | +| `severity` | string | critical, warning; empty where the rule says none. | +| `runbookUrl` | string | Where the dashboard's runbook for it is, as the rule names it: /admin/runbooks/<id>. | +| `labels` | map of string to string | What else the alert's series is labelled with: which host, which volume. | +| `startsAt` | `Timestamp` | When it began firing, and for a resolution when it stopped. | +| `endsAt` | `Timestamp` | | +| `createdAt` | `Timestamp` | When the control plane heard it. | +| `sent` | integer (int32) | How many administrators it was emailed to, is waiting for, and failed every attempt for. | +| `pending` | integer (int32) | | +| `failed` | integer (int32) | | + ## AllowedEmail Allowed email/domain entry @@ -160,6 +189,42 @@ What one item of the installation's config file is. - `CONFIG_ITEM_KIND_SETTING` One of: `CONFIG_ITEM_KIND_UNSPECIFIED`, `CONFIG_ITEM_KIND_SETTING`, `CONFIG_ITEM_KIND_EMAIL`, `CONFIG_ITEM_KIND_PRESET`, `CONFIG_ITEM_KIND_POLICY`, `CONFIG_ITEM_KIND_HOST_CLASS`. +## CostEstimate + +What a workspace would cost at what the last billed day charged. An estimate: that day is over and the next may be charged otherwise, so it is never said without the day it is from. + +| Field | Type | What it is | +|---|---|---| +| `day` | `Timestamp` | The billed day the rate is from: its first instant, UTC. | +| `runningHourMicros` | string or null (int64) | An hour of its machine running, for the cores and memory it holds; unset where that day billed no runner. | +| `stoppedMonthMicros` | string or null (int64) | A month of its disk kept while it is stopped, for the bytes it kept that day; unset where that day billed no volume, or the workspace was made since. | + +## CostMonth + +One month of the trend on Admin → Costs, in millionths of the bill's currency. An estimate of what nobody caused, from the reading it names: a month's last days are revised by the cloud into the next, and read again until they settle. + +| Field | Type | What it is | +|---|---|---| +| `month` | `Timestamp` | Its first instant, UTC. | +| `readAt` | `Timestamp` | The reading its costs are from. | +| `currency` | string | ISO 4217. | +| `totalMicros` | string (int64) | Every cost of its days; idle and unstored are parts of it. | +| `idleMicros` | string (int64) | What the runners cost that no workspace held. | +| `unstoredMicros` | string (int64) | What the volumes' bucket cost for bytes no workspace keeps. | +| `budgetLimitMicros` | string or null (int64) | The installation's budget as the month's last reading in it said; unset where it had none. | + +## CostShare + +What was caused in a month of the cloud's bill, as the installation shares it out (AdminService.GetCosts): by one workspace, or by several summed. In millionths of the bill's currency. A share is of days already billed, never of this hour: the bill is read from the cloud a few times a day. + +| Field | Type | What it is | +|---|---|---| +| `computeMicros` | string (int64) | Of the runners: what was held of them. | +| `storageMicros` | string (int64) | Of the volumes' bucket: what the volumes kept. | +| `sentBytes` | string (int64) | What the traffic came to in the month: the machine's network out and back, and its sessions through the relay, both ways. Counted, not costed. | +| `receivedBytes` | string (int64) | | +| `forwardedBytes` | string (int64) | | + ## CpuUsagePoint CpuUsagePoint is the cores the machine used over a step, on average, against what it held: held_cores attached, lent ones included; cpu_cores its own; max_cpu_cores what it may be lent. @@ -184,6 +249,28 @@ DeletedWorkspace is a workspace in the trash. | `trashedUntil` | `Timestamp` | | | `agentVolumeId` | string | The agent's home it mounts, which its erase keeps for another workspace (ListAgentVolumes); empty for a workspace with none. | +## DeletionEffect + +DeletionEffect is one thing a workspace has and what a delete does to it, in words its owner reads before confirming. + +| Field | Type | What it is | +|---|---|---| +| `fate` | [DeletionFate](/reference/api/types/#deletionfate) | | +| `what` | string | What it is: "Its disk", "2 snapshots". | +| `detail` | string | What happens to it and what follows from that, one sentence. | + +## DeletionFate + +DeletionFate is what a delete does to one thing a workspace has. - `DELETION_FATE_ERASED`: Gone when the delete is done, and not undeleted. - `DELETION_FATE_TRASHED`: In the trash for GetWorkspaceDeletionResponse.trash_days, restored by an undelete, erased when they are up. - `DELETION_FATE_KEPT`: Outlives the workspace, the trash's days included. + +One of: `DELETION_FATE_UNSPECIFIED`, `DELETION_FATE_ERASED`, `DELETION_FATE_TRASHED`, `DELETION_FATE_KEPT`. + +## DepartureFate + +DepartureFate is what taking a host out does to one workspace on it. - `DEPARTURE_FATE_MOVES`: Suspended with its memory and resumed on another runner with room. - `DEPARTURE_FATE_STAYS`: Keeps its place on this runner: a drain moves only what runs. - `DEPARTURE_FATE_LOSES_PLACE`: Suspended at a published snapshot: its disk is let go of here, and its next start is on another runner, from what it published. - `DEPARTURE_FATE_HOLDS`: It keeps the host: the removal is refused while it is here. A group's machine is held by a disk only here, until it is stopped, which publishes it, or moved; a revoked host by any workspace that names it. - `DEPARTURE_FATE_STOPS`: Its disk is only here and is left here: it runs again only once recovered onto another runner, giving up what this one had not published. + +One of: `DEPARTURE_FATE_UNSPECIFIED`, `DEPARTURE_FATE_MOVES`, `DEPARTURE_FATE_STAYS`, `DEPARTURE_FATE_LOSES_PLACE`, `DEPARTURE_FATE_HOLDS`, `DEPARTURE_FATE_STOPS`. + ## DeviceLoginStatus - `DEVICE_LOGIN_STATUS_PENDING`: User hasn't completed login yet - `DEVICE_LOGIN_STATUS_COMPLETE`: Login complete, token available - `DEVICE_LOGIN_STATUS_EXPIRED`: Device code expired - `DEVICE_LOGIN_STATUS_DENIED`: User denied the request @@ -232,11 +319,10 @@ ExtensionRelease is one release of an extension: the supervisor, or the VS Code |---|---|---| | `version` | string | The release's own name: the control plane's version for the supervisor; for the VS Code servers, the versions it carries joined with +, unless it was named otherwise. | | `releasedAt` | `Timestamp` | | -| `workspaces` | string (int64) | How many workspaces run it; one that nothing runs and is not the newest is collectable. | | `newest` | boolean | Whether a start is given this one. | | `volumeId` | string | Its volume in the store, which RemoveStoredVolume takes when removable. | -| `removable` | boolean | Not the newest and nothing runs it: RemoveStoredVolume removes it, and so does the collect-releases job on its own. | -| `keptBecause` | string | Why it stays, in words, where it may not go. | +| `removable` | boolean | Not the newest, and open in no machine and no suspended memory: RemoveStoredVolume removes it, and so does the collect-releases job on its own. A release only stopped workspaces last ran is removable, since their next start is given the newest. | +| `keptBecause` | string | Why it stays, in words, where it may not go: how many machines and suspended memories have it open, or that it is the newest. | ## ExtensionVersion @@ -246,7 +332,7 @@ ExtensionVersion is a release and how many workspaces are on it: what an update |---|---|---| | `extension` | string | | | `version` | string | | -| `workspaces` | string (int64) | | +| `workspaces` | string (int64) | The machines that have it open and the suspended memories that do: a stopped workspace is given the newest at its next start, and is on none. | | `newest` | boolean | Whether a start now would choose this release. | ## FieldValue @@ -310,6 +396,8 @@ One host class's group, as the control plane last saw it. | `launchFailedAt` | `Timestamp` | | | `giveBackRefused` | string | A machine of the group the cloud would not take back, in its own words - a role or a policy somebody has to change - and when; it is asked again every quarter hour until it is taken. Empty while none is refused. | | `giveBackRefusedAt` | `Timestamp` | | +| `capacityRefused` | boolean | launch_failure is the cloud having no machine of the kind the class asks for - no spot capacity, or the spot quota spent - which the class's spot setting, or its fallback, is what changes; false for any other failure, and while there is none. | +| `onDemandUntil` | `Timestamp` | Set while a spot class's group starts on-demand machines because the cloud refused it spot (HostClass.fallback_on_demand): until this, and spot again after. Its class still says spot. | ## FleetHostVersion @@ -399,6 +487,8 @@ HealthCheck is one part of the installation as the control plane knows it. | `status` | [HealthStatus](/reference/api/types/#healthstatus) | | | `reason` | string | reason says in a line what was found, OK or not. | | `knownAt` | `Timestamp` | known_at is when what decided the status was so: the moment it was asked for a part asked now, the collector's last report, the last WAL file archived or failed, a failed job's run. | +| `problems` | list of [Problem](/reference/api/types/#problem) | What is wrong in this part, each on its own: one per host, one per job, one for a part that is a single thing. Empty while the part is OK. At most 20 are listed, the worst first; problem_count is how many there are. | +| `problemCount` | integer (int32) | | ## HealthCheckResult @@ -411,7 +501,7 @@ HealthCheck is one part of the installation as the control plane knows it. ## HealthPart -HealthPart is which part of the installation a check is of. - `HEALTH_PART_DATABASE`: The control plane's database answers a query. - `HEALTH_PART_DATABASE_ARCHIVE`: The database's continuous archive keeps up: its last WAL file sent and how many wait. Its base backups are taken by a timer outside the control plane, which records nothing it can read. - `HEALTH_PART_LOG_STORE`: The log store (Quickwit) beside the control plane answers that it is ready. - `HEALTH_PART_COLLECTOR`: The collector sends what it is given: spans to the trace store, samples to the metric store (GetTelemetryStatus). It is what says whether the metric store takes writes - the control plane is not one of the metric store's readers. - `HEALTH_PART_JOBS`: The control plane's periodic work: a job whose last run failed (ListJobs). - `HEALTH_PART_HOSTS`: The hosts registered and not taken out of the fleet, against those whose command stream is up. - `HEALTH_PART_WAITING_WORKSPACES`: Workspaces waiting for a runner, across the whole fleet. +HealthPart is which part of the installation a check is of. - `HEALTH_PART_DATABASE`: The control plane's database answers a query. - `HEALTH_PART_DATABASE_ARCHIVE`: The database's continuous archive keeps up: its last WAL file sent and how many wait. Its base backups are taken by a timer outside the control plane, which records nothing it can read. - `HEALTH_PART_LOG_STORE`: The log store (Quickwit) beside the control plane answers that it is ready. - `HEALTH_PART_COLLECTOR`: The collector sends what it is given: spans to the trace store, samples to the metric store (GetTelemetryStatus). It is what says whether the metric store takes writes - the control plane is not one of the metric store's readers. - `HEALTH_PART_JOBS`: The control plane's periodic work: a job whose last run failed (ListJobs). - `HEALTH_PART_HOSTS`: The hosts registered and not taken out of the fleet: those whose command stream is not up, and those that answer and fail a check of their own (HostCheck). - `HEALTH_PART_WAITING_WORKSPACES`: Workspaces waiting for a runner, across the whole fleet. One of: `HEALTH_PART_UNSPECIFIED`, `HEALTH_PART_DATABASE`, `HEALTH_PART_DATABASE_ARCHIVE`, `HEALTH_PART_LOG_STORE`, `HEALTH_PART_COLLECTOR`, `HEALTH_PART_JOBS`, `HEALTH_PART_HOSTS`, `HEALTH_PART_WAITING_WORKSPACES`. @@ -458,6 +548,14 @@ One of: `HEALTH_STATUS_UNSPECIFIED`, `HEALTH_STATUS_OK`, `HEALTH_STATUS_DEGRADED | `hostname` | string | hostname is the name the host's machine goes by, as it last registered it: how a person tells one host from another where its id says nothing. Empty for a host that has not registered since it was made. | | `removal` | [HostRemoval](/reference/api/types/#hostremoval) | removal is how this host leaves the fleet, decided by where it came from: the only removal the API takes for it, so the dashboard offers that one and no other. | | `removalRefused` | string | removal_refused is why that removal cannot run now - a workspace whose disk is there - in words an administrator acts on; empty while it can. | +| `keysGiven` | integer (int32) | keys_given is how many teams' disks this host was given the key of: what revoking it, or removing it as taken, marks for re-keying. | +| `machineId` | string | Where the host's machine is, as its cloud said when the host joined - never as the host said of itself: the machine's id and type as that cloud names them, its zone and its region. Each empty for a host that joined with no cloud (a registration token: a development stack, a machine of one's own), and for what its cloud did not say. | +| `machineType` | string | | +| `zone` | string | | +| `region` | string | | +| `reclaimable` | boolean or null | reclaimable is whether the cloud may take the machine back, as its cloud said of the instance when it joined - a spot machine is, whatever its class says: a group that fell back to on-demand, or one whose class was changed, starts machines its class does not describe. Unset where nothing says: a host that joined with no cloud, or one its cloud named nothing of. | +| `holders` | list of [HostHolder](/reference/api/types/#hostholder) | holders is what keeps this host in the fleet, from the database: the workspaces whose disk is only here - whichever list of theirs leaves them out, a prebuild's build, a team's, another person's, a failed one - and the volumes still here that are no such workspace's disk, a trashed workspace's or an agent's home, each of which forgetting the host must detach first. At most 10; holder_count is how many there are. | +| `holderCount` | integer (int32) | | ## HostCheck @@ -483,7 +581,39 @@ A kind of runner: the shape of the machines a group of the installation's cloud | `vcpusMax` | integer (int32) | | | `memoryMibPerVcpu` | integer (int32) | The least memory a vCPU of it has, in MiB; 0 is 2048. | | `spot` | boolean | A machine the cloud may take back (each host drains first), or an on-demand one. | -| `maxHosts` | integer (int32) | The most hosts of it; 0 is no limit of its own (InstallationSettings.autoscaling_max_hosts bounds them all). | +| `maxHosts` | integer (int32) | The most hosts of it; 0 is no limit of its own (the setting autoscaling_max_hosts bounds them all). | +| `fallbackOnDemand` | boolean | A spot class whose group the cloud refuses spot machines for capacity starts on-demand ones for a while, and then spot again (FleetClass.on_demand_until); spot itself is not changed. Off, the class's workspaces wait until somebody changes spot. Only a spot class has it. | + +## HostDeparture + +HostDeparture is what draining the host, and removing it as Host.removal says, would do to each workspace that names it - the ones a drain moves, the ones that stay, the ones that lose their place on it and the ones that hold it - so the confirmation says it before it is done. + +| Field | Type | What it is | +|---|---|---| +| `workspaces` | list of [WorkspaceDeparture](/reference/api/types/#workspacedeparture) | At most 20, the running first; count is how many there are. | +| `count` | integer (int32) | | + +## HostHolder + +HostHolder is one thing a host holds that its removal would lose or has to wait for, with whose it is and what last happened to it. + +| Field | Type | What it is | +|---|---|---| +| `kind` | [HostHolderKind](/reference/api/types/#hostholderkind) | | +| `workspaceId` | string | The workspace it is or was the disk of; for an agent's home, the workspace that mounts it, or that last did by name alone (workspace_id empty). | +| `workspaceName` | string | | +| `volumeId` | string | The volume, for a holder that is a volume (a trashed workspace's disk, an agent's home); empty for a workspace, whose disk the workspace names. | +| `ownerId` | string | Whose it is. | +| `ownerEmail` | string | | +| `state` | [WorkspaceState](/reference/api/types/#workspacestate) | The workspace's state; UNSPECIFIED for an agent's home no workspace mounts. | +| `lastEvent` | [WorkspaceEventType](/reference/api/types/#workspaceeventtype) | What last happened to the workspace, and when: its history's newest entry. UNSPECIFIED and unset where it has none. | +| `lastEventAt` | `Timestamp` | | + +## HostHolderKind + +HostHolderKind is what a holder is, which says which list of whose shows it. - `HOST_HOLDER_KIND_WORKSPACE`: A person's own workspace, in their workspaces list. - `HOST_HOLDER_KIND_TEAM_WORKSPACE`: A workspace of a team, in its members' lists. - `HOST_HOLDER_KIND_PREBUILD_BUILD`: A prebuild's build: kept stopped as its prebuild's anchor, and in nobody's list. - `HOST_HOLDER_KIND_TRASHED_WORKSPACE`: The disk of a workspace in its owner's trash. - `HOST_HOLDER_KIND_AGENT_HOME`: A person's agent's home (AgentVolume). + +One of: `HOST_HOLDER_KIND_UNSPECIFIED`, `HOST_HOLDER_KIND_WORKSPACE`, `HOST_HOLDER_KIND_TEAM_WORKSPACE`, `HOST_HOLDER_KIND_PREBUILD_BUILD`, `HOST_HOLDER_KIND_TRASHED_WORKSPACE`, `HOST_HOLDER_KIND_AGENT_HOME`. ## HostNetworkPolicy @@ -596,37 +726,23 @@ InjectionStatus is one header the egress proxy sets on the workspace's requests | `from` | string | What the header is set from: a team secret by name, "<forge> app", or "identity for <audience>". | | `held` | boolean | Whether the team holds it: the secret is set, the forge app is set, an identity is always held. False is a request refused with credentials. | -## InstallationSettings +## InstallationEventType + +What happened to the installation itself, which its administrators are told of: an event of no workspace, recorded where the control plane hears it. - `INSTALLATION_EVENT_TYPE_ALERT_FIRING`: One of the release's alert rules fired in the installation's Grafana - `INSTALLATION_EVENT_TYPE_ALERT_RESOLVED`: A rule that fired is no longer past its threshold + +One of: `INSTALLATION_EVENT_TYPE_UNSPECIFIED`, `INSTALLATION_EVENT_TYPE_ALERT_FIRING`, `INSTALLATION_EVENT_TYPE_ALERT_RESOLVED`. + +## InstallationPlace -InstallationSettings contains global settings for the Spin installation +InstallationPlace is where the installation runs, as its control plane's machine read it once when it started - never asked of the cloud again per request - and the release it runs. What a cloud did not say, or an installation with no cloud (a development stack, a machine of one's own), is empty. | Field | Type | What it is | |---|---|---| -| `allowedImages` | list of string | Whitelist of allowed images (empty = all allowed) | -| `maxWorkspacesPerUser` | integer (int32) | Maximum workspaces per user (0 = unlimited) | -| `defaultNetworkTags` | list of string | What a workspace created without a network tag of its own runs under, by policy name. Empty means "offline", the policy every host has and which allows nothing: no value of this field means open. An installation that wants such a workspace out declares a policy saying what it may reach and names it here. | -| `updatedAt` | `Timestamp` | | -| `telemetryTracesKeepPercent` | integer (int32) | What the installation's collector keeps, decided at the collector (internal/controlplane/domain/telemetrypolicy). A trace with an error in any span is always kept, and so is one slower than telemetry_traces_slow_ms (0: none is kept for being slow); of the rest, telemetry_traces_keep_percent, 0 to 100 and 100 until an admin says otherwise. | -| `telemetryTracesSlowMs` | integer (int32) | | -| `telemetryMetricsDrop` | list of string | The metrics that are not kept, by name; a pattern may begin or end with \*. | -| `telemetryPerVolumeHistograms` | list of string | Read only: the metrics that cost most to keep, a histogram per volume, which a surface may offer to drop as one. | -| `workspaceTrashDays` | integer (int32) | How many days a deleted workspace stays in the trash, whole, for its owner to undelete before it is erased: 0 is no trash, and 7 is what an installation that says nothing keeps. | -| `identityAudiences` | list of string | Who a workspace's identity token may be for; empty is anybody. What the installation's issuer gives, not who trusts it: a relying party still decides which subjects it admits. | -| `volumeRpoSeconds` | integer (int32) | How far behind the object store a workspace's volume may fall, in seconds, where its preset does not say: what it commits on (v6 §11). 0 is none - it commits on its size and its snapshots alone - and 300 is what an installation that says nothing keeps. | -| `diskReservePercent` | integer (int32) | How a host's disk is lent to workspaces. A volume holds what it wrote, not its size: a host is charged, per volume, the larger of disk_reserve_percent of its size and what it wrote, and takes new ones up to 80% of its device; disk_commit_max_percent bounds the sizes summed - every volume filling at once. 50 and 200 are what an installation that says nothing lends; 100 and 100 lends nothing past what the device holds. | -| `diskCommitMaxPercent` | integer (int32) | | -| `workspaceIdleSuspendMinutes` | integer (int32) | How many minutes a running workspace may go unused - nobody working over its ssh, editor or forwarded ports, and its cores all but still - before it is suspended with its processes, which its next start resumes. 0 suspends none; 60 is what an installation that says nothing keeps, and a week is the most. | -| `workspaceMaxRunningMinutes` | integer (int32) | How many minutes a workspace may run at a stretch, used or not, before it is suspended the same way: a process that keeps its cores busy is use to the rule above, and this is what ends it. Counted from its machine's start, which a resume is too. 0 caps none; 720 is what an installation that says nothing keeps, and a week is the most. | -| `workspaceLeaseMaxMinutes` | integer (int32) | How many minutes a process may keep its workspace awake at a stretch (a lease: `spin-supervisor keep -- <cmd>`, a .spin.yaml task with keep_awake). While a lease is held and within this of its start, nobody is asked, nothing idle is suspended, and the running cap waits for the lease's end. 0 honours no lease; 480 is what an installation that says nothing keeps, and a week is the most. | -| `teamSecretsRole` | string | The IAM role a team's secret kept in Secrets Manager or Parameter Store is read under, in a session tagged spin-team-id with the team: its policy lets that session read only what carries the same tag. Empty, no secret is kept as a reference. | -| `projectCreation` | string | Who makes projects (ProjectService.CreateProject): "everyone" signed in, or only the instance's "admins". Empty is everyone. | -| `autoscalingIdleMinutes` | integer (int32) | How the runner fleet is sized (GetFleet): the minutes it may be idle before it is emptied, above zero; the quiet hours, HH:MM-HH:MM in the IANA time zone, when it is emptied at once, empty for none; and the most hosts it is asked for, under the group's own maximum - zero is that maximum. Each takes effect at the autoscaler's next pass. | -| `autoscalingQuietHours` | string | | -| `autoscalingTimeZone` | string | | -| `autoscalingMaxHosts` | integer (int32) | | -| `hostShellNeedsApproval` | boolean | A root shell on a host (HostShellService): whether a second administrator approves each one before its host is touched, and the most minutes one may be open, 30 where unset. | -| `hostShellMaxMinutes` | integer (int32) | | -| `prebuildRetireUnusedDays` | integer (int32) | How many days a ready prebuild may go without a workspace opened from it before it is retired and its disk given back - the newest of its ref too, so a project nobody opens stops holding one, and its next open starts from the image. It is not built again until its ref moves to another commit, or an admin runs it. Counted from its build for one never opened. 0, what an installation that says nothing keeps, retires none for this; a year is the most. | +| `provider` | string | The provider the installation was made on, as its document names it: "aws", "self-hosted". | +| `account` | string | The cloud account it runs in, as that cloud names it. | +| `region` | string | | +| `release` | string | The release the control plane runs, "v20261112.01". | +| `machineImage` | string | The machine image the control plane's machine booted, as its cloud names it. | ## Job @@ -639,7 +755,8 @@ InstallationSettings contains global settings for the Spin installation | `lastRun` | [JobRun](/reference/api/types/#jobrun) | Unset until it has run on this installation. | | `lastSucceededAt` | `Timestamp` | | | `title` | string | The job as a person names it: "Storage collection" for storage-gc. | -| `purpose` | string | One sentence of what it does and what stays undone while it fails. | +| `does` | string | A sentence of what it does. | +| `whileFailing` | string | What stays undone while it fails, said after "While it fails, ": "new workspaces start from an older prebuild". What a failure's verdict says, so whoever reads it knows how soon it needs them. | | `recentRuns` | list of [JobRun](/reference/api/types/#jobrun) | Its newest runs, newest first, at most twenty: what a list of jobs shows each one's recent outcomes and durations from, without asking for every job's runs. Each has its id, start, end and outcome only; ListJobRuns has the rest. | ## JobRun @@ -653,7 +770,7 @@ InstallationSettings contains global settings for the Spin installation | `outcome` | [JobRunOutcome](/reference/api/types/#jobrunoutcome) | | | `counts` | map of string to string (int64) | What it did, by the job's own names for it: objects deleted, bytes freed, hosts forgotten. | | `error` | string | Why it failed; empty when it did not. | -| `traceId` | string | The run's trace, empty when it was not recorded. | +| `traceId` | string | The run's trace id, which every record it logged carries; empty when it was not recorded. Whether the store kept the trace is LogService.KeptTraces's to say. | | `askedBy` | string | The admin who ran it by hand; empty for a run the schedule started. | ## JobRunOutcome @@ -814,10 +931,13 @@ One of: `NOTIFICATION_DELIVERY_STATE_UNSPECIFIED`, `NOTIFICATION_DELIVERY_STATE_ ## NotificationPreference +One kind of event and whether the caller is emailed about it: a workspace's event, or the installation's (an administrator's alone). Exactly one of event and installation_event is set. + | Field | Type | What it is | |---|---|---| | `event` | [WorkspaceEventType](/reference/api/types/#workspaceeventtype) | | | `email` | boolean | | +| `installationEvent` | [InstallationEventType](/reference/api/types/#installationeventtype) | | ## ObservedDestination @@ -884,6 +1004,16 @@ PasskeyPurpose is what a ceremony's challenge is for. - `PASSKEY_PURPOSE_REGISTE One of: `PASSKEY_PURPOSE_UNSPECIFIED`, `PASSKEY_PURPOSE_REGISTER`, `PASSKEY_PURPOSE_ADD_PASSKEY`, `PASSKEY_PURPOSE_ADD_SSH_KEY`, `PASSKEY_PURPOSE_DELETE_PASSKEY`, `PASSKEY_PURPOSE_ADD_GUEST`, `PASSKEY_PURPOSE_CREATE_EXEC_KEY`. +## PlatformCost + +What one role's resources of one of the cloud's services cost, in millionths of the bill's currency: the control plane, the proxy and the database are three roles of one EC2. + +| Field | Type | What it is | +|---|---|---| +| `role` | string | As the resources carry it (on AWS, their spin:role tag); empty where they carry none, which is said as untagged. | +| `service` | string | | +| `micros` | string (int64) | | + ## PlatformImage | Field | Type | What it is | @@ -945,6 +1075,8 @@ A prebuild: one build of a project's ref at a commit, and the snapshot it left. | `reportedAt` | `Timestamp` | When its build's guest said the checkout and create tasks were done; unset before it did. | | `spinYaml` | boolean | Whether the checkout had a .spin.yaml at its root, as the guest reported: without one the build is the clone alone, with no create tasks run. Read only with reported_at. | | `storedBytes` | string or null (int64) | What it keeps in the object store, as storage-gc last read it; unset before a reading counted it. | +| `buildWorkspaceId` | string | The workspace that ran its build (workspaces.prebuild_id), while its row is kept, and whose it is: its events, logs and traces are its owner's to read, and no list of workspaces shows it. | +| `buildWorkspaceOwnerId` | string | | ## PrebuildRefNotFound @@ -961,12 +1093,63 @@ A prebuild ref the project's forge has not. One of: `PREBUILD_STATE_UNSPECIFIED`, `PREBUILD_STATE_BUILDING`, `PREBUILD_STATE_READY`, `PREBUILD_STATE_FAILED`, `PREBUILD_STATE_RETIRED`. +## PrebuildsKept + +What a project's prebuilds keep in the volumes' bucket, and what that would cost a month at what the last billed day charged: an estimate, never said without the day it is from. + +| Field | Type | What it is | +|---|---|---| +| `storedBytes` | string (int64) | As the store was last read (Admin's Storage, PREBUILD). | +| `day` | `Timestamp` | The billed day the rate is from: its first instant, UTC. Unset, with month_micros, where no day before the reading billed the bucket, or the prebuilds keep nothing. | +| `monthMicros` | string or null (int64) | | + ## PreemptionSource PreemptionSource mirrors spin.agent.v1.PreemptionSource, which is what reaches the host. One of: `PREEMPTION_SOURCE_UNSPECIFIED`, `PREEMPTION_SOURCE_AWS`, `PREEMPTION_SOURCE_GCP`, `PREEMPTION_SOURCE_AZURE`. +## Problem + +Problem is one thing wrong with the installation, said whole: why, what it takes down, what shows it and what to do. Nothing is kept of it - it is read off the installation as it is now, and is gone when what caused it is. + +| Field | Type | What it is | +|---|---|---| +| `cause` | string | cause says in a line what was found. | +| `since` | `Timestamp` | since is when what decided it was so, as HealthCheck.known_at is: a host's command stream last heard, a check's last run, a job's failed run. Unset where nothing says. | +| `impact` | [ProblemImpact](/reference/api/types/#problemimpact) | | +| `evidence` | list of [ProblemEvidence](/reference/api/types/#problemevidence) | What shows it, each a thing the console has a page for. | +| `runbookId` | string | The runbook to follow (Runbook.id), of the runbooks this release serves: never empty. | +| `actions` | list of [ProblemAction](/reference/api/types/#problemaction) | What the console itself can do about it, each on the host or the job the problem is of. | +| `hostId` | string | The host the problem is of, and the name its machine goes by; empty for one that is not a host's. | +| `hostname` | string | | +| `job` | string | The job (Job.name) the problem is of, and its title; empty for one that is not a job's. | +| `jobTitle` | string | | + +## ProblemAction + +ProblemAction is something the console can do about a problem, each an RPC it has. - `PROBLEM_ACTION_CORDON_HOST`: DrainHost without suspend: the host takes no new workspace and keeps what it runs. - `PROBLEM_ACTION_DRAIN_HOST`: DrainHost with suspend: its workspaces are moved to other hosts. - `PROBLEM_ACTION_RUN_JOB`: RunJobNow: the job is run again, now. - `PROBLEM_ACTION_RECOVER_WORKSPACE`: RecoverUserWorkspace, of each workspace the problem names: its disk is on a host that is gone, and it runs again only once moved off it. + +One of: `PROBLEM_ACTION_UNSPECIFIED`, `PROBLEM_ACTION_CORDON_HOST`, `PROBLEM_ACTION_DRAIN_HOST`, `PROBLEM_ACTION_RUN_JOB`, `PROBLEM_ACTION_RECOVER_WORKSPACE`. + +## ProblemEvidence + +ProblemEvidence names one thing that shows a problem. The console turns each into a link to its own page; none is a URL. + +No fields: `{}`. + +## ProblemImpact + +ProblemImpact is what a problem takes down: the workspaces under it as rows of the database, or, for a part with nothing under it, what stops working. + +| Field | Type | What it is | +|---|---|---| +| `stops` | string | What stops working, in a line: "log lines are not kept". Empty where the rows say it. | +| `runningWorkspaces` | integer (int32) | The workspaces it affects, counted whole: running on the host now, and at rest with their disk only there - stopped or failed, each one's next start is on that host. For workspaces waiting for a host, waiting_workspaces. | +| `restingWorkspaces` | integer (int32) | | +| `waitingWorkspaces` | integer (int32) | | +| `workspaces` | list of [AffectedWorkspace](/reference/api/types/#affectedworkspace) | At most 10 of them, the running first, then by name: the counts above are the whole. | + ## Project A project: a repository and the shape of the workspace that opens it. @@ -1029,18 +1212,6 @@ A workspace open on a project, as the project's admins read it: whose it is and | `details` | map of string to string | What the supervisor held of it, in its own words: which user in the guest, which process, why the policy refused. | | `at` | `Timestamp` | When the attempt was made, as the guest clock held it. | -## RateLimitSettings - -RateLimitSettings configures API rate limiting - -| Field | Type | What it is | -|---|---|---| -| `enabled` | boolean | Enable rate limiting | -| `authRequestsPerMinute` | integer (int32) | Auth endpoints (login, token exchange, etc.) Requests per minute for auth endpoints | -| `authBurst` | integer (int32) | Burst allowance for auth endpoints | -| `apiRequestsPerMinute` | integer (int32) | API endpoints (all other endpoints) Requests per minute for API endpoints | -| `apiBurst` | integer (int32) | Burst allowance for API endpoints | - ## RefusedDestination | Field | Type | What it is | @@ -1051,6 +1222,23 @@ RateLimitSettings configures API rate limiting | `port` | integer | For tcp and udp; zero otherwise. | | `packets` | string (int64) | | +## RefusedVolume + +RefusedVolume is a disk its host is not serving, and the workspace that cannot run for it. + +| Field | Type | What it is | +|---|---|---| +| `volumeId` | string | | +| `refusal` | string | The token an alert keys on, and the sentence the host sent with it (VolumeStatus). | +| `refusalDetail` | string | | +| `hostId` | string | The host refusing it; empty for a disk placed nowhere. | +| `hostName` | string | | +| `workspaceId` | string | The workspace it is the disk of; empty for a disk no workspace runs on. | +| `workspaceName` | string | | +| `workspaceState` | [WorkspaceState](/reference/api/types/#workspacestate) | | +| `ownerId` | string | Whose the workspace is. | +| `ownerEmail` | string | | + ## RegistrationMode Registration mode enum - `REGISTRATION_MODE_OPEN`: Anyone can register - `REGISTRATION_MODE_WHITELIST`: Only whitelisted emails/domains - `REGISTRATION_MODE_CLOSED`: No new registrations @@ -1108,10 +1296,11 @@ ResourcePreset is a class of workspace: its size, and how a workspace of it may | `burstFloorCpuCores` | integer (int32) | What a workspace of a burst mode starts with; at most cpu_cores and memory_mb. | | `burstFloorMemoryMb` | integer (int32) | | | `bandwidthMbps` | integer (int32) | What a workspace of it may carry each way, in megabits a second; 0 is unshaped. | -| `rpoSeconds` | integer (int32) | How far behind the object store a workspace of it may fall, in seconds; 0 is the installation's (InstallationSettings.volume_rpo_seconds). | +| `rpoSeconds` | integer (int32) | How far behind the object store a workspace of it may fall, in seconds; 0 is the installation's (the setting volume_rpo_seconds). | | `hostClass` | string | The host class its workspaces run on (HostClass). | | `agentMinMemoryMb` | integer (int32) | What a workspace has to hold for its agent to start there, in MB, for whoever picks a preset. | | `fromConfig` | boolean | Seeded or applied from the installation's config file (the release's presets where it names none); false is one an administrator added. An edit since does not change it. | +| `minMemoryMb` | integer (int32) | The least any preset may start its workspaces at, in MB: memory_mb for a fixed one, burst_floor_memory_mb for a burst one. A create or update below it is refused; one written before it was asked keeps what it has until an administrator changes it. | ## Resources @@ -1126,6 +1315,15 @@ Resource allocation for workspaces. Initial values (cpu_cores, memory_mb) are us | `maxMemoryMb` | integer (int32) | Max memory in MB (0 = unlimited) | | `bandwidthMbps` | integer (int32) | What a workspace's network carries each way, in megabits a second (0 = unshaped): its preset's, held on its host by a token bucket on each way out of its machine's namespace. Its vsock - ssh, the editor, forwarded ports - is not shaped. | +## RoleCost + +What one role cost on one day, its services summed. + +| Field | Type | What it is | +|---|---|---| +| `role` | string | Empty where the resources carry none. | +| `micros` | string (int64) | | + ## Runbook | Field | Type | What it is | @@ -1161,18 +1359,6 @@ User's uploaded SSH public key | `createdAt` | `Timestamp` | | | `expiresAt` | `Timestamp` | No last_used_at: a user's key authenticates inside the guest, over SSH, where the control plane is not, so the only honest answer it could give is "unknown". Compare ApiKey.last_used_at, which the control plane stamps because it is the thing being presented to. When an enrolled key stops logging in; unset for a key of the person's own. | -## SecuritySettings - -SecuritySettings contains security-related configuration - -| Field | Type | What it is | -|---|---|---| -| `rateLimit` | [RateLimitSettings](/reference/api/types/#ratelimitsettings) | Rate limiting configuration | -| `sessionDurationHours` | integer (int32) | Session configuration Session token lifetime in hours (default: 168 = 7 days) | -| `allowWorkspaceSharing` | boolean | Access control Allow users to share workspaces | -| `allowPublicWorkspaces` | boolean | Allow publicly accessible workspace URLs | -| `updatedAt` | `Timestamp` | | - ## ServiceCost What one of the cloud's services cost on one day, in millionths of the bill's currency. @@ -1204,12 +1390,43 @@ ServiceHealth is one service over a window: the traces begun in it - what it was | `traces` | string (int64) | | | `failedTraces` | string (int64) | | +## SettingDefinition + +SettingDefinition is one setting of the installation as the code defines it. + +| Field | Type | What it is | +|---|---|---| +| `key` | string | | +| `type` | [SettingType](/reference/api/types/#settingtype) | | +| `defaultValue` | string | What is in force where the installation says nothing, as text of the type. | +| `min` | string or null (int64) | | +| `max` | string or null (int64) | | +| `choices` | list of string | The values a STRING setting takes; empty is any. | +| `reach` | [SettingReach](/reference/api/types/#settingreach) | What it touches once saved. | +| `restart` | boolean | It is read when the control plane starts: a change is in force after its next restart. | +| `section` | string | Which page it is on: general, workspaces, fleet, network, security, registration, telemetry, logs, bill, email, storage, installation, control_plane. | +| `label` | string | A few words that name it, and a sentence that says what it does and what its zero means. | +| `summary` | string | | +| `writer` | [SettingWriter](/reference/api/types/#settingwriter) | | + ## SettingReach -SettingReach is what a saved installation setting touches, and when: each setting declares one beside its key (internal/controlplane/settings), so the screen that edits it can say so before the save. - `SETTING_REACH_RUNNING_WORKSPACES`: The workspaces running now, at the control plane's next look at them. - `SETTING_REACH_NEW_WORKSPACES`: Workspaces created from now on; those that exist keep what they were made with. - `SETTING_REACH_NEXT_HEARTBEAT`: Each runner at its next heartbeat, and the workspaces running on it. - `SETTING_REACH_NEXT_REQUEST`: What is asked from now on - a project made, a shell opened, a workspace deleted; what was done before keeps the terms it was done under. - `SETTING_REACH_NEXT_PASS`: The next pass of the job that applies it: the autoscaler, the prebuilds' retirement, the collector's read of its policy, the daily look for a release. +SettingReach is what a saved installation setting touches, and when: each setting's definition declares one (internal/controlplane/settings), so the screen that edits it can say so before the save. - `SETTING_REACH_RUNNING_WORKSPACES`: The workspaces running now, at the control plane's next look at them. - `SETTING_REACH_NEW_WORKSPACES`: Workspaces created from now on; those that exist keep what they were made with. - `SETTING_REACH_NEXT_HEARTBEAT`: Each runner at its next heartbeat, and the workspaces running on it. - `SETTING_REACH_NEXT_REQUEST`: What is asked from now on - a project made, a shell opened, a workspace deleted; what was done before keeps the terms it was done under. - `SETTING_REACH_NEXT_PASS`: The next pass of the job that applies it: the autoscaler, the prebuilds' retirement, the collector's read of its policy, the daily look for a release. One of: `SETTING_REACH_UNSPECIFIED`, `SETTING_REACH_RUNNING_WORKSPACES`, `SETTING_REACH_NEW_WORKSPACES`, `SETTING_REACH_NEXT_HEARTBEAT`, `SETTING_REACH_NEXT_REQUEST`, `SETTING_REACH_NEXT_PASS`. +## SettingType + +SettingType is how a setting's value is written as text, which is how GetSettings answers it and SetSettings takes it. - `SETTING_TYPE_INT`: A whole number in decimal, within the definition's min and max. - `SETTING_TYPE_BOOL`: "true" or "false". - `SETTING_TYPE_STRING`: Text; a definition with choices takes only those. - `SETTING_TYPE_LIST`: A JSON array of strings. - `SETTING_TYPE_JSON`: A JSON document, as the code that reads it defines it. - `SETTING_TYPE_DURATION`: A Go duration ("60s"); min and max are seconds. + +One of: `SETTING_TYPE_UNSPECIFIED`, `SETTING_TYPE_INT`, `SETTING_TYPE_BOOL`, `SETTING_TYPE_STRING`, `SETTING_TYPE_LIST`, `SETTING_TYPE_JSON`, `SETTING_TYPE_DURATION`. + +## SettingWriter + +SettingWriter is who writes a setting, and so where an administrator changes it. - `SETTING_WRITER_ADMIN`: SetSettings, and the installation's file seeds it. - `SETTING_WRITER_FILE`: The installation's file alone: what whoever made the installation knows, and a change of which the dashboard cannot make whole - the proxy holds the base domain too. - `SETTING_WRITER_STORE`: A page of its own, which checks it against the real thing before it is written: the object store, the mail server. - `SETTING_WRITER_CONTROL_PLANE`: The control plane, for itself. + +One of: `SETTING_WRITER_UNSPECIFIED`, `SETTING_WRITER_ADMIN`, `SETTING_WRITER_FILE`, `SETTING_WRITER_STORE`, `SETTING_WRITER_CONTROL_PLANE`. + ## Snapshot A snapshot is a rotation of a workspace's volume, published as a commit. It has no name outside its id. @@ -1271,6 +1488,17 @@ Span is one operation of a trace, as OpenTelemetry names its parts. | `attributes` | `Struct` | | | `events` | list of `Struct` | What happened during it, as the span recorded it: each event's name, time and attributes. | +## StandbyCost + +What the installation cost on its last billed day before the reading with nobody's work counted: the platform, the runners' capacity no workspace held, and the bucket's bytes no workspace keeps. An estimate of a day nobody works: that day is over, the next may be charged otherwise, and a day people worked held some of the runners - so it is never said without its day (finops.StandbyOf). + +| Field | Type | What it is | +|---|---|---| +| `day` | `Timestamp` | The billed day it is from: its first instant, UTC. | +| `platform` | list of [RoleCost](/reference/api/types/#rolecost) | The platform by role, costliest first. | +| `idleMicros` | string (int64) | | +| `unstoredMicros` | string (int64) | | + ## StatusDisagreement | Field | Type | What it is | @@ -1407,6 +1635,16 @@ One of: `TEAM_ROLE_UNSPECIFIED`, `TEAM_ROLE_OWNER`, `TEAM_ROLE_ADMIN`, `TEAM_ROL | `hosts` | list of string | | | `ref` | string | Where the team keeps the value; empty where the control plane does. | +## TeamWorkspaceCost + +What one of a team's workspaces cost in the month. + +| Field | Type | What it is | +|---|---|---| +| `workspaceId` | string | | +| `name` | string | | +| `share` | [CostShare](/reference/api/types/#costshare) | | + ## TelemetryFlow TelemetryFlow is what one exporter of the collector did over the last window. @@ -1454,6 +1692,37 @@ ThirdPartyPart is one program an item downloads, and the license it comes under. | `acceptance` | [ThirdPartyAcceptance](/reference/api/types/#thirdpartyacceptance) | Unset where nobody accepted the terms for it. | | `accepted` | boolean | Whether this installation downloads it: accepted, as the current text. | +## TimelineActor + +TimelineActor is who or what did what a TimelineEvent says. - `TIMELINE_ACTOR_PERSON`: A person signed in, named by actor_id. - `TIMELINE_ACTOR_CONTROL_PLANE`: The control plane, on its own: a reconciliation, a sweep, a job, a decision nobody asked for. - `TIMELINE_ACTOR_HOST`: A host, of itself: it joined, said it was going, lost its stream or came back. + +One of: `TIMELINE_ACTOR_UNSPECIFIED`, `TIMELINE_ACTOR_PERSON`, `TIMELINE_ACTOR_CONTROL_PLANE`, `TIMELINE_ACTOR_HOST`. + +## TimelineEvent + +TimelineEvent is one thing that happened, read from the record that keeps it - the audit log, a workspace's events, a job's runs, a project's prebuilds - and never a copy of it. + +| Field | Type | What it is | +|---|---|---| +| `source` | [TimelineSource](/reference/api/types/#timelinesource) | The record it is read from, and that record's id there: the evidence a reader opens. | +| `id` | string | | +| `at` | `Timestamp` | | +| `actor` | [TimelineActor](/reference/api/types/#timelineactor) | Who or what did it. | +| `actorId` | string | The person, when actor is PERSON: empty for one whose account has since been deleted, and the email is what their row says now. | +| `actorEmail` | string | | +| `what` | string | What happened, in its source's own words: an audit action (host_state_changed), a workspace event type without its prefix (FAILED), a failed job run's job (storage-gc), or for a prebuild prebuild_started, prebuild_built or prebuild_failed. | +| `resourceType` | string | What it happened to: an audit entry's resource_type and id (workspace, host, settings, job by its name), the workspace of a workspace event, the job of a run, the project of a prebuild. | +| `resourceId` | string | | +| `resourceName` | string | The name a person knows it by, where the installation still has its row: a workspace's, a host's machine's, a team's, a project's. Empty otherwise. | +| `details` | string | The JSON the record keeps, verbatim: an audit entry's details, a workspace event's, a failed run's counts and error, a prebuild's ref, commit and error. | +| `traceId` | string | The trace of the request or the run that did it; empty when none was sampled. Whether the store kept it is LogService.KeptTraces's to say. | + +## TimelineSource + +TimelineSource is the record a TimelineEvent is read from. - `TIMELINE_SOURCE_AUDIT`: An audit entry (AuditEntry.id). - `TIMELINE_SOURCE_WORKSPACE_EVENT`: A workspace's event (WorkspaceEvent.id). - `TIMELINE_SOURCE_JOB_RUN`: A job's run that failed (JobRun.run_id). - `TIMELINE_SOURCE_PREBUILD`: A project's prebuild (Prebuild.id). + +One of: `TIMELINE_SOURCE_UNSPECIFIED`, `TIMELINE_SOURCE_AUDIT`, `TIMELINE_SOURCE_WORKSPACE_EVENT`, `TIMELINE_SOURCE_JOB_RUN`, `TIMELINE_SOURCE_PREBUILD`. + ## User | Field | Type | What it is | @@ -1580,6 +1849,20 @@ WorkspaceAction is an act a person can ask of a workspace. - `WORKSPACE_ACTION_F One of: `WORKSPACE_ACTION_UNSPECIFIED`, `WORKSPACE_ACTION_START`, `WORKSPACE_ACTION_STOP`, `WORKSPACE_ACTION_FORCE_STOP`, `WORKSPACE_ACTION_DELETE`, `WORKSPACE_ACTION_FORCE_DELETE`, `WORKSPACE_ACTION_SUSPEND`, `WORKSPACE_ACTION_START_FROM_DISK`. +## WorkspaceAgentThreads + +WorkspaceAgentThreads is one workspace's chats with what a rail names it by: the workspace, its state, and the project it opened. + +| Field | Type | What it is | +|---|---|---| +| `workspaceId` | string | | +| `workspaceName` | string | | +| `state` | [WorkspaceState](/reference/api/types/#workspacestate) | | +| `projectId` | string | Empty for a workspace that opened no project. | +| `projectName` | string | | +| `environmentId` | string | As ListAgentThreadsResponse.environment_id: the first part of a thread's page. | +| `threads` | list of [AgentThread](/reference/api/types/#agentthread) | Newest first. | + ## WorkspaceAttempt WorkspaceAttempt is one attempt a host made at a workspace's generation that failed. @@ -1609,6 +1892,20 @@ What one workspace cost in the month, in millionths of the bill's currency, and | `receivedBytes` | string (int64) | | | `forwardedBytes` | string (int64) | | +## WorkspaceDeparture + +WorkspaceDeparture is one workspace on a host and what each way of taking the host out does to it. + +| Field | Type | What it is | +|---|---|---| +| `workspaceId` | string | | +| `workspaceName` | string | | +| `ownerEmail` | string | | +| `state` | [WorkspaceState](/reference/api/types/#workspacestate) | | +| `drain` | [DepartureFate](/reference/api/types/#departurefate) | What a drain that moves the host's workspaces (DrainHostRequest.suspend) does to it: MOVES or STAYS. | +| `removal` | [DepartureFate](/reference/api/types/#departurefate) | What Host.removal does to it: LOSES_PLACE or HOLDS. UNSPECIFIED where the host has no removal. | +| `taken` | [DepartureFate](/reference/api/types/#departurefate) | What removing the host as taken (RemoveHostRequest.taken) does to it: LOSES_PLACE or STOPS. UNSPECIFIED for a host that is revoked, whose revoke already is that. | + ## WorkspaceDurability WorkspaceDurability is what of a workspace's disk is published, so it survives its host. While a host serves the disk - running, or stopped with its disk kept there - it is that host's last report; once none does - suspended, or its disk handed back to the store - it is the newest published snapshot of the disk (snapshot_id), which is what a start boots from. @@ -1637,9 +1934,9 @@ Timeline event for workspace state changes ## WorkspaceEventType -- `WORKSPACE_EVENT_TYPE_CREATED`: Workspace was created - `WORKSPACE_EVENT_TYPE_STARTED`: Workspace was started - `WORKSPACE_EVENT_TYPE_STOPPED`: Workspace was stopped; its disk is kept, and no snapshot is taken - `WORKSPACE_EVENT_TYPE_SNAPSHOT_CREATED`: Manual snapshot - `WORKSPACE_EVENT_TYPE_DELETED`: Workspace was deleted - `WORKSPACE_EVENT_TYPE_FAILED`: Workspace start failed - `WORKSPACE_EVENT_TYPE_RESTORED`: Its disk was put back to a snapshot - `WORKSPACE_EVENT_TYPE_RESUMED`: It went on from a snapshot's memory - `WORKSPACE_EVENT_TYPE_BOOTED`: Suspended, its memory could not be resumed, and its disk was booted - `WORKSPACE_EVENT_TYPE_QUARANTINED`: An administrator held it: stopped, and startable by nobody until released - `WORKSPACE_EVENT_TYPE_UNQUARANTINED`: The hold was released: back to stopped, where it was held from - `WORKSPACE_EVENT_TYPE_PLACED`: A workspace that waited for a host was given one, and its disk there - `WORKSPACE_EVENT_TYPE_TRASHED`: Deleted into the trash: its disk kept, its owner able to undelete it - `WORKSPACE_EVENT_TYPE_UNDELETED`: Taken back out of the trash - `WORKSPACE_EVENT_TYPE_MOVED`: Suspended on its host and resumed on another, which had room for what it was granted - `WORKSPACE_EVENT_TYPE_DISPLACED`: Its host was drained or went away: suspended there, it is resumed on another on its own - `WORKSPACE_EVENT_TYPE_STOP_BACKUP_FAILED`: A stop on a host that can be taken away could not publish its disk first, so it runs on - `WORKSPACE_EVENT_TYPE_IDLE_SUSPENDED`: Nobody used it for as long as the installation allows: suspended with its processes, a start resumes them - `WORKSPACE_EVENT_TYPE_RUNNING_CAP_SUSPENDED`: It ran at a stretch for as long as the installation allows: suspended with its processes, a start resumes them - `WORKSPACE_EVENT_TYPE_SUSPENSION_DUE`: A suspension is minutes away and the question was asked: its terminals, its page, the CLI; a keep answers it - `WORKSPACE_EVENT_TYPE_KEPT`: Somebody kept it awake until a time: no suspension before it - `WORKSPACE_EVENT_TYPE_UNRESPONSIVE`: Its supervisor said nothing for longer than the control plane waits: stopped by force, and a start brings it back - `WORKSPACE_EVENT_TYPE_REHOMED`: Its host stopped answering and it was moved to another on its own, giving up what that host had not published - `WORKSPACE_EVENT_TYPE_HELD`: Its host stopped answering and moving it would give up more than the installation does on its own: it waits for its owner +- `WORKSPACE_EVENT_TYPE_CREATED`: Workspace was created - `WORKSPACE_EVENT_TYPE_STARTED`: Workspace was started - `WORKSPACE_EVENT_TYPE_STOPPED`: Workspace was stopped; its disk is kept, and no snapshot is taken - `WORKSPACE_EVENT_TYPE_SNAPSHOT_CREATED`: Manual snapshot - `WORKSPACE_EVENT_TYPE_DELETED`: Workspace was deleted - `WORKSPACE_EVENT_TYPE_FAILED`: Workspace start failed - `WORKSPACE_EVENT_TYPE_RESTORED`: Its disk was put back to a snapshot - `WORKSPACE_EVENT_TYPE_RESUMED`: It went on from a snapshot's memory - `WORKSPACE_EVENT_TYPE_BOOTED`: Suspended, its memory could not be resumed, and its disk was booted - `WORKSPACE_EVENT_TYPE_QUARANTINED`: An administrator held it: stopped, and startable by nobody until released - `WORKSPACE_EVENT_TYPE_UNQUARANTINED`: The hold was released: back to stopped, where it was held from - `WORKSPACE_EVENT_TYPE_PLACED`: A workspace that waited for a host was given one, and its disk there - `WORKSPACE_EVENT_TYPE_TRASHED`: Deleted into the trash: its disk kept, its owner able to undelete it - `WORKSPACE_EVENT_TYPE_UNDELETED`: Taken back out of the trash - `WORKSPACE_EVENT_TYPE_MOVED`: Suspended on its host and resumed on another, which had room for what it was granted - `WORKSPACE_EVENT_TYPE_DISPLACED`: Its host was drained or went away: suspended there, it is resumed on another on its own - `WORKSPACE_EVENT_TYPE_STOP_BACKUP_FAILED`: A stop on a host that can be taken away could not publish its disk first, so it runs on - `WORKSPACE_EVENT_TYPE_IDLE_SUSPENDED`: Nobody used it for as long as the installation allows: suspended with its processes, a start resumes them - `WORKSPACE_EVENT_TYPE_RUNNING_CAP_SUSPENDED`: It ran at a stretch for as long as the installation allows: suspended with its processes, a start resumes them - `WORKSPACE_EVENT_TYPE_SUSPENSION_DUE`: A suspension is minutes away and the question was asked: its terminals, its page, the CLI; a keep answers it - `WORKSPACE_EVENT_TYPE_KEPT`: Somebody kept it awake until a time: no suspension before it - `WORKSPACE_EVENT_TYPE_UNRESPONSIVE`: Its supervisor said nothing for longer than the control plane waits: stopped by force, and a start brings it back - `WORKSPACE_EVENT_TYPE_REHOMED`: Its host stopped answering and it was moved to another on its own, giving up what that host had not published - `WORKSPACE_EVENT_TYPE_HELD`: Its host stopped answering and moving it would give up more than the installation does on its own: it waits for its owner - `WORKSPACE_EVENT_TYPE_RECOVERED_BY_ADMIN`: An administrator moved it off a host that is gone, giving up for its owner what that host had not published; its details say who and why - `WORKSPACE_EVENT_TYPE_OUT_OF_MEMORY`: It ran out of memory: its guest's kernel killed a process (cause "guest", with the kills and their victims), its host found it short at its ceiling for a while (cause "ceiling"), or its host killed the machine (cause "host"). Its details say what it held, its grant and its ceiling. Said, never acted on: nothing resizes a workspace on its own. - `WORKSPACE_EVENT_TYPE_OVERSIZED`: It held far more than it used for a week: the most memory its processes used stayed under half its own, and a smaller preset would fit what it used. Its details say what it used, what it holds, and that preset. Said, never acted on: nothing resizes a workspace on its own. -One of: `WORKSPACE_EVENT_TYPE_UNSPECIFIED`, `WORKSPACE_EVENT_TYPE_CREATED`, `WORKSPACE_EVENT_TYPE_STARTED`, `WORKSPACE_EVENT_TYPE_STOPPED`, `WORKSPACE_EVENT_TYPE_SNAPSHOT_CREATED`, `WORKSPACE_EVENT_TYPE_DELETED`, `WORKSPACE_EVENT_TYPE_FAILED`, `WORKSPACE_EVENT_TYPE_RESTORED`, `WORKSPACE_EVENT_TYPE_RESUMED`, `WORKSPACE_EVENT_TYPE_BOOTED`, `WORKSPACE_EVENT_TYPE_QUARANTINED`, `WORKSPACE_EVENT_TYPE_UNQUARANTINED`, `WORKSPACE_EVENT_TYPE_PLACED`, `WORKSPACE_EVENT_TYPE_TRASHED`, `WORKSPACE_EVENT_TYPE_UNDELETED`, `WORKSPACE_EVENT_TYPE_MOVED`, `WORKSPACE_EVENT_TYPE_DISPLACED`, `WORKSPACE_EVENT_TYPE_STOP_BACKUP_FAILED`, `WORKSPACE_EVENT_TYPE_IDLE_SUSPENDED`, `WORKSPACE_EVENT_TYPE_RUNNING_CAP_SUSPENDED`, `WORKSPACE_EVENT_TYPE_SUSPENSION_DUE`, `WORKSPACE_EVENT_TYPE_KEPT`, `WORKSPACE_EVENT_TYPE_UNRESPONSIVE`, `WORKSPACE_EVENT_TYPE_REHOMED`, `WORKSPACE_EVENT_TYPE_HELD`. +One of: `WORKSPACE_EVENT_TYPE_UNSPECIFIED`, `WORKSPACE_EVENT_TYPE_CREATED`, `WORKSPACE_EVENT_TYPE_STARTED`, `WORKSPACE_EVENT_TYPE_STOPPED`, `WORKSPACE_EVENT_TYPE_SNAPSHOT_CREATED`, `WORKSPACE_EVENT_TYPE_DELETED`, `WORKSPACE_EVENT_TYPE_FAILED`, `WORKSPACE_EVENT_TYPE_RESTORED`, `WORKSPACE_EVENT_TYPE_RESUMED`, `WORKSPACE_EVENT_TYPE_BOOTED`, `WORKSPACE_EVENT_TYPE_QUARANTINED`, `WORKSPACE_EVENT_TYPE_UNQUARANTINED`, `WORKSPACE_EVENT_TYPE_PLACED`, `WORKSPACE_EVENT_TYPE_TRASHED`, `WORKSPACE_EVENT_TYPE_UNDELETED`, `WORKSPACE_EVENT_TYPE_MOVED`, `WORKSPACE_EVENT_TYPE_DISPLACED`, `WORKSPACE_EVENT_TYPE_STOP_BACKUP_FAILED`, `WORKSPACE_EVENT_TYPE_IDLE_SUSPENDED`, `WORKSPACE_EVENT_TYPE_RUNNING_CAP_SUSPENDED`, `WORKSPACE_EVENT_TYPE_SUSPENSION_DUE`, `WORKSPACE_EVENT_TYPE_KEPT`, `WORKSPACE_EVENT_TYPE_UNRESPONSIVE`, `WORKSPACE_EVENT_TYPE_REHOMED`, `WORKSPACE_EVENT_TYPE_HELD`, `WORKSPACE_EVENT_TYPE_RECOVERED_BY_ADMIN`, `WORKSPACE_EVENT_TYPE_OUT_OF_MEMORY`, `WORKSPACE_EVENT_TYPE_OVERSIZED`. ## WorkspaceFailure @@ -1667,6 +1964,8 @@ Whether the machine's host is reachable at all. A workspace cannot be healthier | `lastHeartbeat` | `Timestamp` | | | `hostname` | string | Which host it is, as a person reads it: the name its machine goes by (Host.hostname), and the class of the group that launched it ("default" for one no group launched). What its owner and guests are shown of the host and no more: its capacity, what else it runs and its policy are an administrator's (HostService). | | `hostClass` | string | | +| `machineType` | string | The host's machine as its cloud names it, said when the host joined (Host.machine_type, Host.zone): what kind of machine the workspace runs on, and where. Empty for a host that joined with no cloud. The machine's id and whether it may be taken back stay an administrator's. | +| `zone` | string | | ## WorkspaceLease @@ -1678,6 +1977,16 @@ WorkspaceLease is a process in the workspace keeping it awake while it lives. | `since` | `Timestamp` | | | `until` | `Timestamp` | until is when the lease stops counting whether or not the process lives: since plus the installation's workspace_lease_max_minutes. | +## WorkspaceNetworkStatus + +WorkspaceNetworkStatus is one policy a workspace runs under, and whether it holds there: the installation declares it, and the workspace's host reports having installed it. A tag no policy is declared for, or one its host has not installed, is what a start is refused over. + +| Field | Type | What it is | +|---|---|---| +| `policy` | string | | +| `declared` | boolean | declared says a policy of this name exists: the installation's, or a team's. | +| `installed` | boolean | installed says the workspace's host last reported enforcing a policy of this name. False for a workspace on no host. | + ## WorkspacePhase WorkspacePhase is what a host is doing to bring a workspace up. - `WORKSPACE_PHASE_DISK`: Waiting for its disk to be served on the host. - `WORKSPACE_PHASE_EXTENSIONS`: Holding the extension releases it runs with. - `WORKSPACE_PHASE_NETWORK`: Setting up its network. - `WORKSPACE_PHASE_MACHINE`: Booting its machine, or resuming it from a checkpoint. - `WORKSPACE_PHASE_FIRST_BOOT`: Its first boot of a disk another person's workspace was cloned from. - `WORKSPACE_PHASE_GUEST`: The machine is up and its workspace inside is starting. - `WORKSPACE_PHASE_BACKUP`: Stopping on a host that can be taken away: its disk is being published before the machine stops, the control plane's doing rather than the host's, and retried if it restarts. diff --git a/src/content/docs/reference/api/workspaceservice.md b/src/content/docs/reference/api/workspaceservice.md index b731f3e..7d36395 100644 --- a/src/content/docs/reference/api/workspaceservice.md +++ b/src/content/docs/reference/api/workspaceservice.md @@ -4,7 +4,7 @@ description: "spin.v1.WorkspaceService: each procedure, its request and its resp source: "spin:internal/controlplane/apidocs/spin.v1.openapi.json" editUrl: false sidebar: - order: 11 + order: 3 --- @@ -147,7 +147,7 @@ Create a new workspace | `name` | string | Optional, generated if empty | | `teamId` | string | Optional: team ID (personal workspace if empty) | | `image` | string | A published image (ListImages); required unless from_snapshot_id is set | -| `preset` | string | The preset it is sized by, by name (AdminService.ListResourcePresets): its cores, memory, disk and how it grows. Empty is the project's preset when project_id names one, otherwise the installation's default preset, or with none marked 1 core, 512 MB and 10 GB free. A disabled preset is refused. | +| `preset` | string | The preset it is sized by, by name (AdminService.ListResourcePresets): its cores, memory, disk and how it grows. Empty is the project's preset when project_id names one, otherwise the installation's default preset, or with none marked 1 core, 2048 MB and 10 GB free. A disabled preset is refused. | | `env` | map of string to string | Environment variables | | `fromSnapshotId` | string | Create workspace from a shared snapshot | | `networkTags` | list of string | network_tags are the network policies this workspace runs under, by name - the same idea as a GCP instance's network tags. The host's ruleset names the tag and holds the set of machines carrying it, so this decides which rules apply without naming a rule. Empty runs the workspace under the installation's default, and under "offline" where it declares none: a create that names nothing reaches nothing, rather than everything. A tag the host has no policy for fails the start rather than being ignored: a workspace asking for a policy the node does not have is a question with two answers, and quietly choosing "run it without" is how one ends up less contained than whoever launched it believes. | @@ -298,6 +298,48 @@ The tail of the workspace's serial console: the kernel, vminit, then the supervi | `truncated` | boolean | truncated says there are lines before the first one here, so what this begins with is not mistaken for the start of the boot. | | `hostId` | string | Which host answered. A console belongs to the machine that wrote it, and a workspace that has moved has nothing to say about the run that failed on the host it left. | +## GetWorkspaceCost + +`POST /spin.v1.WorkspaceService/GetWorkspaceCost` + +What the workspace cost in the month in progress and what it costs while it runs, for whoever reads the workspace itself: its owner, and a guest its owner let in. Nobody else is answered - one workspace's cost says how much another person works. Read from the bill as the installation last read it, never from the cloud. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `workspaceId` | string | | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `month` | `Timestamp` | The month in progress: its first instant, UTC. | +| `readAt` | `Timestamp` | When the bill was last read; unset where it never was - an installation with no bill scope, a cloud that sends none - and then nothing below is known and nothing is to be drawn. | +| `currency` | string | ISO 4217; every amount here is in millionths of it. | +| `share` | [CostShare](/reference/api/types/#costshare) | The month so far. | +| `estimate` | [CostEstimate](/reference/api/types/#costestimate) | Unset where no day before the reading was billed, or none says anything of this workspace. | + +## GetWorkspaceDeletion + +`POST /spin.v1.WorkspaceService/GetWorkspaceDeletion` + +What deleting a workspace would do, asked before it is done: what goes to the trash and for how long, what is erased at once, and what outlives it. It changes nothing. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `workspaceId` | string | | +| `permanently` | boolean | What DeleteWorkspaceRequest.permanently would do: an erase, whatever the trash keeps. | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `trashDays` | integer (int32) | How many days the delete keeps the workspace in the trash; 0 is an erase now - the installation keeps no trash, or permanently was asked. | +| `effects` | list of [DeletionEffect](/reference/api/types/#deletioneffect) | Everything the delete does to what the workspace has, ordered erased, trashed, kept. Only what this workspace has: one with no snapshot is told nothing of snapshots. | + ## GetWorkspaceEgress `POST /spin.v1.WorkspaceService/GetWorkspaceEgress` @@ -386,6 +428,7 @@ What every party believes about one workspace, and where they disagree. | `runtime` | [WorkspaceRuntime](/reference/api/types/#workspaceruntime) | What the machine has and uses now, asked of its host. Absent - not zero - when there is no machine to ask about: not running, on no connected host, or a host that did not answer in time. Zero cores would read as a machine that has none. | | `failure` | [WorkspaceFailure](/reference/api/types/#workspacefailure) | Which part failed, when state = FAILED; failure_reason is the detail. Workspace.failure. | | `injections` | list of [InjectionStatus](/reference/api/types/#injectionstatus) | Each header a brokered rule of the workspace's policies sets, and whether what it is set from is there to set: a request to a brokered name is refused when it is not, and this is where that is seen from outside the machine. | +| `network` | list of [WorkspaceNetworkStatus](/reference/api/types/#workspacenetworkstatus) | The policies the workspace's network is under (Workspace.network_tags), in their order, and whether each is declared and installed on its host. Empty for a workspace with no tag, which reaches anything beyond its host's own networks. | ## GetWorkspaceUsage @@ -577,6 +620,22 @@ No fields: `{}`. | `hostsEnforcing` | integer (int32) | Of the hosts connected, how many have installed what the installation declares. They are told on their next heartbeat, so the two differ for a moment after an apply - and go on differing when a host cannot install what was declared, which is the thing worth seeing. | | `hostsConnected` | integer (int32) | | +## ListOwnAgentThreads + +`POST /spin.v1.WorkspaceService/ListOwnAgentThreads` + +The caller's own chats across every workspace of theirs, each workspace's as its supervisor last reported them: what the dashboard's chat mode lists in one rail. Selected by the caller's id, never one from the request, and a key bound to a team or projects lists theirs alone. + +**Request** + +No fields: `{}`. + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `workspaces` | list of [WorkspaceAgentThreads](/reference/api/types/#workspaceagentthreads) | One per workspace of the caller's whose supervisor reported a chat, in project then workspace name order; a workspace in the trash is not here. | + ## ListSnapshots `POST /spin.v1.WorkspaceService/ListSnapshots` @@ -635,6 +694,29 @@ What a workspace attempted past its policy: the refusals its supervisor reported |---|---|---| | `denials` | list of [QuarantineDenial](/reference/api/types/#quarantinedenial) | Newest first. | +## ListWorkspaceTimeline + +`POST /spin.v1.WorkspaceService/ListWorkspaceTimeline` + +What happened to a workspace, newest first, between two instants: its own events and what the audit log records of it and its snapshots, each with who did it - for its owner, read as GetWorkspaceHistory is. AdminService.ListTimeline is the same reading of any workspace, a host, a team, a project or the whole installation. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `id` | string | | +| `since` | `Timestamp` | Inclusive; unset reads from as far back as the records go. | +| `until` | `Timestamp` | Exclusive; unset is now. | +| `page` | [PageRequest](/reference/api/types/#pagerequest) | page_size is at most 200, and zero is 50. total_count is not counted. | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `events` | list of [TimelineEvent](/reference/api/types/#timelineevent) | | +| `page` | [PageResponse](/reference/api/types/#pageresponse) | | +| `keptDays` | integer (int32) | kept_days is how long what the timeline reads is kept: before it, an empty timeline is the records gone, not nothing having happened. | + ## ListWorkspaces `POST /spin.v1.WorkspaceService/ListWorkspaces` @@ -717,7 +799,10 @@ Hold a workspace in quarantine: an administrator's decision, held until one rele | Field | Type | What it is | |---|---|---| -| `workspace` | [Workspace](/reference/api/types/#workspace) | | +| `workspaceId` | string | | +| `name` | string | | +| `state` | [WorkspaceState](/reference/api/types/#workspacestate) | | +| `quarantineHeld` | boolean | Held, as Workspace.quarantine_held: a running workspace answers STOPPING, and this is what says the stop is the quarantine's. | ## RecoverWorkspace @@ -758,7 +843,10 @@ Release what was quarantined: stopped, with its disk as it was - or, where the s | Field | Type | What it is | |---|---|---| -| `workspace` | [Workspace](/reference/api/types/#workspace) | | +| `workspaceId` | string | | +| `name` | string | | +| `state` | [WorkspaceState](/reference/api/types/#workspacestate) | | +| `quarantineHeld` | boolean | | ## ReleaseWorkspaceResources @@ -870,7 +958,10 @@ Set what a workspace's network carries each way, an instance admin's to change: | Field | Type | What it is | |---|---|---| -| `workspace` | [Workspace](/reference/api/types/#workspace) | | +| `workspaceId` | string | | +| `name` | string | | +| `state` | [WorkspaceState](/reference/api/types/#workspacestate) | | +| `bandwidthMbps` | integer (int32) | Megabits a second each way now in force; zero is unshaped. | ## SetWorkspaceNetworkTags diff --git a/src/content/docs/reference/cli/admin.md b/src/content/docs/reference/cli/admin.md index 547886f..453eb77 100644 --- a/src/content/docs/reference/cli/admin.md +++ b/src/content/docs/reference/cli/admin.md @@ -24,11 +24,13 @@ Available Commands: jobs The control plane's periodic work, and running a job now logs Search what the installation's processes logged runner Manage registered runners + settings The installation's settings: read them, and change one shell A root shell on a runner, for a while: asked for, recorded, and the runner retired after storage What the object store holds, and taking out what nothing needs token Manage runner registration tokens versions What is running where: this control plane, each runner and its machine - volume Re-key a workspace's disk + volume Re-key a workspace's disk, and list the disks hosts refuse + workspace Stop, recover or read the egress of a workspace that is somebody else's Flags: -h, --help[=true|false] help for admin @@ -75,7 +77,8 @@ Use "spin admin costs [command] --help" for more information about a command. A month of the bill shared out: the runners by what each workspace held of them - cores and memory, half each - and the volumes' bucket by what its volumes kept. What nobody caused is said apart and never spread: the runners' capacity nobody held (idle), the bucket's bytes no workspace -keeps (images, unreferenced), and the platform's own cost by service. +keeps (images, unreferenced), and the platform's own cost by role and service. First, the standby: +what the installation costs a day with nobody working, estimated from the last billed day. Usage: spin admin costs by [flags] @@ -350,12 +353,20 @@ A runner that is the only home of a workspace's disk is refused, naming them: st publishes each disk, or move them first. A runner registered with a token is revoked instead (spin admin runner revoke). +--taken is for a machine that may be compromised: its credentials are deleted and it is cut off +before its group is asked anything, and every team's disk whose key it was given is marked for +re-keying (spin admin volume rekeys lists them), as a revoke does. Its machine is given back all +the same. With --leave-workspaces it goes although workspaces' disks are only there: each runs +again only once recovered onto another runner (spin workspace recover). + Usage: spin admin runner remove [flags] Flags: - -h, --help[=true|false] help for remove - -y, --yes[=true|false] Skip confirmation + -h, --help[=true|false] help for remove + --leave-workspaces[=true|false] with --taken, remove although workspaces' disks are only on this runner; each runs again only once recovered elsewhere + --taken[=true|false] the machine may be compromised: revoke its credentials and mark every disk whose key it was given for re-keying + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -393,6 +404,71 @@ Global Flags: --traceparent string the W3C traceparent of the span this command is part of; its own span is sent to the installation unless the profile says telemetry: false ``` +### spin admin settings + +``` +The installation's settings: read them, and change one + +Usage: + spin admin settings [flags] + spin admin settings [command] + +Available Commands: + get Every setting as it is in force, or one + set Change one setting + +Flags: + -h, --help[=true|false] help for settings + +Global Flags: + --config string config file (default is $HOME/.spin/config.yaml) + -o, --output string text for a person, or json: one document of what the API answered, and no prose (default "text") + --profile string named profile to use; SPIN_PROFILE names it when this flag does not (default "default") + --traceparent string the W3C traceparent of the span this command is part of; its own span is sent to the installation unless the profile says telemetry: false + +Use "spin admin settings [command] --help" for more information about a command. +``` + +#### spin admin settings get + +``` +Every setting as it is in force - what the installation says, or its default - with where it is +changed and when a change reaches what it governs. With a key, that setting's value alone, as +'spin admin settings set' takes it. + +Usage: + spin admin settings get [key] [flags] + +Flags: + -h, --help[=true|false] help for get + +Global Flags: + --config string config file (default is $HOME/.spin/config.yaml) + -o, --output string text for a person, or json: one document of what the API answered, and no prose (default "text") + --profile string named profile to use; SPIN_PROFILE names it when this flag does not (default "default") + --traceparent string the W3C traceparent of the span this command is part of; its own span is sent to the installation unless the profile says telemetry: false +``` + +#### spin admin settings set + +``` +Change one setting, checked as the dashboard's save is: a number within its bounds, true or +false, one of its choices, a list as JSON (["a","b"]), a duration as 60s. The control plane +refuses anything else, and writes nothing. + +Usage: + spin admin settings set [flags] + +Flags: + -h, --help[=true|false] help for set + +Global Flags: + --config string config file (default is $HOME/.spin/config.yaml) + -o, --output string text for a person, or json: one document of what the API answered, and no prose (default "text") + --profile string named profile to use; SPIN_PROFILE names it when this flag does not (default "default") + --traceparent string the W3C traceparent of the span this command is part of; its own span is sent to the installation unless the profile says telemetry: false +``` + ### spin admin shell ``` @@ -776,13 +852,14 @@ Global Flags: ### spin admin volume ``` -Re-key a workspace's disk +Re-key a workspace's disk, and list the disks hosts refuse Usage: spin admin volume [flags] spin admin volume [command] Available Commands: + refused The disks a host refuses to serve, and whose workspace each is rekey Copy a workspace's disk under a key of its own and destroy the old one rekeys The disks being re-keyed, and the ones a revoked host's keys marked for it @@ -798,6 +875,25 @@ Global Flags: Use "spin admin volume [command] --help" for more information about a command. ``` +#### spin admin volume refused + +``` +List every disk its host refuses to serve, with why, the workspace that cannot run for it +and that workspace's owner. The listing is audited: it names workspaces that are not yours. + +Usage: + spin admin volume refused [flags] + +Flags: + -h, --help[=true|false] help for refused + +Global Flags: + --config string config file (default is $HOME/.spin/config.yaml) + -o, --output string text for a person, or json: one document of what the API answered, and no prose (default "text") + --profile string named profile to use; SPIN_PROFILE names it when this flag does not (default "default") + --traceparent string the W3C traceparent of the span this command is part of; its own span is sent to the installation unless the profile says telemetry: false +``` + #### spin admin volume rekey ``` @@ -840,3 +936,101 @@ Global Flags: --traceparent string the W3C traceparent of the span this command is part of; its own span is sent to the installation unless the profile says telemetry: false ``` +### spin admin workspace + +``` +Stop, recover or read the egress of a workspace that is somebody else's + +Usage: + spin admin workspace [flags] + spin admin workspace [command] + +Available Commands: + egress What somebody else's workspace has reached beyond this installation + recover Move somebody else's workspace off a host that is gone + stop Stop somebody else's workspace + +Flags: + -h, --help[=true|false] help for workspace + +Global Flags: + --config string config file (default is $HOME/.spin/config.yaml) + -o, --output string text for a person, or json: one document of what the API answered, and no prose (default "text") + --profile string named profile to use; SPIN_PROFILE names it when this flag does not (default "default") + --traceparent string the W3C traceparent of the span this command is part of; its own span is sent to the installation unless the profile says telemetry: false + +Use "spin admin workspace [command] --help" for more information about a command. +``` + +#### spin admin workspace egress + +``` +List every destination a running workspace that is not yours has been allowed to reach, +as its owner's 'spin workspace egress' does: the host's counters by destination, and nothing of +what was carried. The reading is audited, with the reason. + +Usage: + spin admin workspace egress [flags] + +Flags: + -h, --help[=true|false] help for egress + --reason string Why: kept on the audit entry for the reading + +Global Flags: + --config string config file (default is $HOME/.spin/config.yaml) + -o, --output string text for a person, or json: one document of what the API answered, and no prose (default "text") + --profile string named profile to use; SPIN_PROFILE names it when this flag does not (default "default") + --traceparent string the W3C traceparent of the span this command is part of; its own span is sent to the installation unless the profile says telemetry: false +``` + +#### spin admin workspace recover + +``` +Move a workspace that is not yours to another host after the one it was on died, as its +owner's 'spin workspace recover' does. + +The cost is the work the dead host had written and not yet published, and it is the owner's +work. Run without --accept-data-loss to see that cost; nothing is changed until you pass it. +--reason is required, and the server refuses a recover without one: it is kept on the audit +entry, and the owner reads it, with who asked, on the workspace's history. + +Usage: + spin admin workspace recover [flags] + +Flags: + --accept-data-loss[=true|false] go ahead and give up, for its owner, the work the old host had not published + -h, --help[=true|false] help for recover + --reason string Why (required): kept on the audit entry, and on the workspace's history for its owner + +Global Flags: + --config string config file (default is $HOME/.spin/config.yaml) + -o, --output string text for a person, or json: one document of what the API answered, and no prose (default "text") + --profile string named profile to use; SPIN_PROFILE names it when this flag does not (default "default") + --traceparent string the W3C traceparent of the span this command is part of; its own span is sent to the installation unless the profile says telemetry: false +``` + +#### spin admin workspace stop + +``` +Stop a workspace that is not yours, as its owner's 'spin workspace stop' does: what to do +with one whose stop could not publish its disk, which runs on and holds its host. + +--force gives up what only its host has rather than publish it first. The stop is audited with +the reason, and the workspace's own history names you as who stopped it. + +Usage: + spin admin workspace stop [flags] + +Flags: + --force[=true|false] give up what only its host has rather than publish it first + -h, --help[=true|false] help for stop + --reason string Why: kept on the audit entry for the stop + -y, --yes[=true|false] Skip confirmation + +Global Flags: + --config string config file (default is $HOME/.spin/config.yaml) + -o, --output string text for a person, or json: one document of what the API answered, and no prose (default "text") + --profile string named profile to use; SPIN_PROFILE names it when this flag does not (default "default") + --traceparent string the W3C traceparent of the span this command is part of; its own span is sent to the installation unless the profile says telemetry: false +``` + diff --git a/src/content/docs/reference/cli/api-key.md b/src/content/docs/reference/cli/api-key.md index 509dcff..4b30521 100644 --- a/src/content/docs/reference/cli/api-key.md +++ b/src/content/docs/reference/cli/api-key.md @@ -71,8 +71,8 @@ Usage: Flags: --expires string How long the key lasts, at most a year: a whole number of d, w or y (30d, 2w, 1y), or a duration like 36h (default "90d") -h, --help[=true|false] help for create - --max-cores int32 How many cores their workspaces may hold at once - --max-workspaces int32 How many workspaces the key and the keys it delegates may hold at once + --max-cores int32 How many cores their workspaces may hold on runners at once: a stopped one's do not count + --max-workspaces int32 How many workspaces the key and the keys it delegates may have on a runner at once: stopped ones do not count --project strings A project whose workspaces the key reaches, by id (can be repeated; default: any) --scope strings Scopes for the key (can be repeated) --team string The one team whose workspaces the key reaches (default: every team you are in) diff --git a/src/content/docs/reference/cli/open.md b/src/content/docs/reference/cli/open.md index 990e6f1..64f1365 100644 --- a/src/content/docs/reference/cli/open.md +++ b/src/content/docs/reference/cli/open.md @@ -17,8 +17,8 @@ its repository among the projects you see; with more than one, --project says wh workspace is made in --team, or your personal team. A repository no project has is one to make a project of first ('spin project create'). -The workspace is the project's shape, sized by its preset unless --preset names another, and its first access is signed here with a key of your -keyring. It ends in 'spin ssh' unless --no-connect. +The workspace is the project's shape, sized by its preset unless --preset names another. It ends +in 'spin ssh', which logs in with a key you added ('spin ssh-key add'), unless --no-connect. Examples: spin open https://github.com/spin-stack/qboot diff --git a/src/content/docs/reference/cli/project.md b/src/content/docs/reference/cli/project.md index de74304..e4cec1e 100644 --- a/src/content/docs/reference/cli/project.md +++ b/src/content/docs/reference/cli/project.md @@ -12,8 +12,8 @@ sidebar: ``` A project is a repository and the shape of the workspace that opens it: the image, the preset and the network policies, and the ref it opens at. 'spin workspace create --project ' makes a -workspace of that shape, whose guest clones the repository into /workspace/ once -you approve its settings, and runs the repository's own .spin.yaml tasks there. +workspace of that shape, whose guest clones the repository into /workspace/ and +runs the repository's own .spin.yaml tasks there. Projects are the installation's. Whoever makes one is its admin, and it is seen by everybody until its admins share it with only some people and teams ('spin project share'). A private repository @@ -140,9 +140,7 @@ Global Flags: ``` List a project's prebuilds: each build of one of its prebuild refs at a commit, what became of it, -and the snapshot opening the project at that ref is cloned from once it is ready. A ready one is -what its host signed it to be; spin shows that claim, and holds it to its own anchors, when a -workspace opened from it asks you to approve its settings. +and the snapshot opening the project at that ref is cloned from once it is ready. Usage: spin project prebuilds [flags] diff --git a/src/content/docs/reference/cli/ssh-config.md b/src/content/docs/reference/cli/ssh-config.md index b2a6fdf..9cc5d7c 100644 --- a/src/content/docs/reference/cli/ssh-config.md +++ b/src/content/docs/reference/cli/ssh-config.md @@ -16,6 +16,10 @@ reaches a workspace as the host spin.: ssh, scp, rsync, VS Code's Rem Each connection gets a fresh five-minute certificate for your key, and is carried through the platform like 'spin ssh'. A workspace has to be running: a start under way is waited for. +The block asks for the one key exchange a workspace accepts, mlkem768x25519-sha256, which +OpenSSH has from 9.9. An older ssh refuses the whole of ~/.ssh/config over it, for every host, +so nothing is written for one. + Examples: spin ssh-config ssh spin.my-workspace diff --git a/src/content/docs/reference/cli/ssh.md b/src/content/docs/reference/cli/ssh.md index 621b110..08e5199 100644 --- a/src/content/docs/reference/cli/ssh.md +++ b/src/content/docs/reference/cli/ssh.md @@ -15,6 +15,10 @@ Connect to a workspace via SSH. The connection is tunneled through the platform using WebSocket, so no direct network access to the workspace is required. +It runs your ssh, which has to be OpenSSH 9.9 or newer: a workspace accepts only the +post-quantum key exchange mlkem768x25519-sha256, and an older ssh is refused before anything +is asked of the workspace. + Examples: spin ssh my-workspace spin ssh my-workspace -- -L 8080:localhost:80 diff --git a/src/content/docs/reference/cli/vscode.md b/src/content/docs/reference/cli/vscode.md index 7afc900..5a3a489 100644 --- a/src/content/docs/reference/cli/vscode.md +++ b/src/content/docs/reference/cli/vscode.md @@ -17,7 +17,7 @@ Usage: spin vscode [command] Available Commands: - install Install the Spinbox extension that carries this CLI's release into VS Code + install Install the Spinbox extension that carries this CLI's release, and Spinbox Remote, into VS Code Flags: -h, --help[=true|false] help for vscode @@ -36,7 +36,13 @@ Use "spin vscode [command] --help" for more information about a command. ``` Install the Spinbox extension (spin-stack.spinbox) into VS Code, from the release of spin-stack/vscode-spinbox whose VSIXs carry this CLI's release, pulled anonymously from its -public package ghcr.io/spin-stack/vscode-spinbox-release (tag spin-). +public package ghcr.io/spin-stack/vscode-spinbox-release (tag spin-), and beside +it Spinbox Remote (spin-stack.spinbox-remote), which opens the spin+ remote it opens +workspaces through. + +Spinbox Remote uses VS Code's proposed resolvers API, which the Marketplace refuses, so it is +downloaded from the spin-stack/open-remote-ssh release this CLI's release pins, and held to the +SHA-256 pinned with it. Both VSIXs are checked before either is given to the editor. The extension runs a spin CLI it carries, and an installation serves a CLI of its own release alone, so the extension installed is the one carrying this CLI's release - not the newest. Its diff --git a/src/content/docs/reference/configuration/file.md b/src/content/docs/reference/configuration/file.md index e9ddd33..8ff4fd0 100644 --- a/src/content/docs/reference/configuration/file.md +++ b/src/content/docs/reference/configuration/file.md @@ -25,8 +25,9 @@ The file an installation starts from - `installation_config` in Terraform. It se # Every block is optional. settings: - # What a workspace may be created from. Declared and empty is refused: it would allow - # nothing at all. Leave the key out for the installation's default. + # What a workspace may be created from. Empty, or left out, is the release's default image + # alone. Every key under settings is one of internal/controlplane/settings/registry.go, checked + # by the same definition the dashboard and `spin admin settings set` are. allowed_images: - ghcr.io/acme/sandbox:v1 # Zero is no limit. @@ -67,6 +68,10 @@ settings: # image. It is built again when its ref moves to another commit, or when an admin runs it. # Counted from its build for one never opened. 0 or unset retires none for this; at most 365. # prebuild_retire_unused_days: 30 + # A root shell on a host: whether a second administrator approves each before its host is + # touched (off where unset), and the most minutes one may be open, 1 to 1440 (30 where unset). + # host_shell_needs_approval: true + # host_shell_max_minutes: 30 # What a workspace created without a tag of its own runs under, by policy name - the # network_policies block below, or a host's own. Unset, it is "offline", the policy every # host has and which allows nothing: a workspace nobody chose a policy for reaches nothing @@ -129,10 +134,11 @@ registration: - contractor@example.com # What a person may choose when creating a workspace. One preset may be the default. Left out, -# the installation is given the release's: one, "default", 1 core and 512 MB that grow to what its -# host has, on 10 GB. `presets: []` gives it none. +# the installation is given the release's: one, "default", 1 core and 2048 MB that grow to what +# its host has, on 10 GB. `presets: []` gives it none. A preset starts its workspaces at 2048 MB or +# more, which an editor's server needs beside what runs in the workspace. # burst says how a workspace of it grows: fixed (the default) runs at its size; to_preset -# starts at the floor (burst_floor_cpu, burst_floor_memory_mb; 1 and 1024 if left out) and +# starts at the floor (burst_floor_cpu, burst_floor_memory_mb; 1 and 2048 if left out) and # grows to its size; to_host starts at the floor and grows to what its host has. # bandwidth_mbps is what its network carries each way (left out: 100; 0: unshaped, a bill with # no bound that has to be asked for); ssh, the editor and forwarded ports are not held to it. diff --git a/src/content/docs/reference/security/known-gaps.md b/src/content/docs/reference/security/known-gaps.md index 05a884a..56cdfc5 100644 --- a/src/content/docs/reference/security/known-gaps.md +++ b/src/content/docs/reference/security/known-gaps.md @@ -9,7 +9,7 @@ sidebar: -The open items of Spinbox's security model, from spin's [`docs/security/README.md`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/docs/security/README.md) at `b7ba5206f`. The numbers are [its rules](/reference/security/rules/). +The open items of Spinbox's security model, from spin's [`docs/security/README.md`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/docs/security/README.md) at `911f516bc`. The numbers are [its rules](/reference/security/rules/). What no line keeps yet. Each is a design change, not a patch, which is why it is here. @@ -149,13 +149,16 @@ What no line keeps yet. Each is a design change, not a patch, which is why it is frames, is the release's signed files on the proxy image's verity root, under a Caddyfile spin-boot carries, so the control plane does not change it; a proxy running other code serves any code in that frame. -- **The published key set is the identity key's first version, as the proxy serves it.** - `id.` is written on the proxy from the first version of `identity/issuer.json` and its CA, - which no role may delete, so another key the control plane writes publishes - nothing; a proxy running other code publishes any key set. A self-hosted installation +- **The published key set is the identity key's first version and the keys the proxy's document + lists, as the proxy serves it.** `id.` is written on the proxy from the first version of + `identity/issuer.json`, each key under `identity/keys/` whose kid the document Terraform writes + lists (`identity.KeySet`), and each one's CA, signed by its key; so a key the control plane makes + and the apply does not list publishes nothing, and the control plane's exchange verifies against + the same set. A proxy running other code publishes any key set; an apply listing a kid the + control plane printed trusts what the control plane made then. A self-hosted installation serves none. - **I19 holds the identity key to the image a host booted, not to the host.** Every host shares - the key, because the published key set is one key: a runner running other code signs for any + the key it signs with, the newest listed: a runner running other code signs for any subject. A self-hosted installation has no key service, and its control plane keeps the key it grants. diff --git a/src/content/docs/reference/security/rules.md b/src/content/docs/reference/security/rules.md index c14fdc1..8c7aed1 100644 --- a/src/content/docs/reference/security/rules.md +++ b/src/content/docs/reference/security/rules.md @@ -9,7 +9,7 @@ sidebar: -The rules every entry point must keep, from spin's [`docs/security/README.md`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/docs/security/README.md) at `b7ba5206f`. Code cites a rule's number at the line that keeps it. **Gate** is what fails a build when the rule is broken; *none* marks a rule kept only by each place remembering it. What is still open is on [Known gaps](/reference/security/known-gaps/). +The rules every entry point must keep, from spin's [`docs/security/README.md`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/docs/security/README.md) at `911f516bc`. Code cites a rule's number at the line that keeps it. **Gate** is what fails a build when the rule is broken; *none* marks a rule kept only by each place remembering it. What is still open is on [Known gaps](/reference/security/known-gaps/). | # | Rule | Gate | |---|---|---| @@ -19,8 +19,8 @@ The rules every entry point must keep, from spin's [`docs/security/README.md`](h | I4 | Membership and role are asked at the time of the action, not only when the resource was made. | `TestOnlyTheListedProceduresSkipTheTeam`, `TestAnOwnerRemovedFromTheTeamCannotUseItsWorkspace`, `TestAPortOfATeamsWorkspaceIsReachedOnlyByWhoIsInTheTeam`, `TestAStreamIntoATeamsWorkspaceEndsWithItsViewersMembership` - the gate reads handlers that resolve a workspace, and a port's decision is not one, so a new way in that decides for itself is held by a test of its own and not by the gate | | I5 | A cookie-authenticated request that changes state or opens a socket names the dashboard's origin (or none). | `TestAPageOnAnotherSiteCannotSpendTheVisitorsCookie`, `TestEveryHTTPRouteIsMountedBehindAuth`, `TestOnlyTheDashboardIsTheDashboardsOrigin` | | I6 | A credential is minted from `crypto/rand`, stored only hashed or sealed with its resource as AAD, compared in constant time, and revoked with what issued it. A guest's supervisor holds none to the control plane: its host carries the supervisor's stream under the host's own (I8), and revoking the host cuts every stream it carries. A workload may hold a key it exchanged its identity for (I26), a client's credential, which the host carries as a client's call and never as its own. | `TestAGuestsStreamIsCarriedByItsHostAndCutWithIt`; otherwise *none* | -| I7 | Bytes a guest controls are bounded (size, count, time) and made valid (UTF-8, paths) where they cross into the host. | the `CHECK`s; `TestWhatAGuestWritesIsBoundedBeforeItIsARow`, `TestAnAgentsThreadIndexIsBoundedAndReplacedWhole` | -| I8 | A host is trusted only for what is placed on it, and says only what a host may say - its guests' supervisors included, whose streams it carries under its own token. | `runnerMessageBinding` and its two tests; `TestAHostCarriesOnlyTheSupervisorsOfWorkspacesPlacedOnIt`, `TestWhatReachesTheControlPlaneIsTheSupervisorsCall`; `TestAHostsMintedCredentialWritesOnlyItsOwnSubtree`, against the store; `TestAHostsCredentialsLastAQuarterOfAnHour`, `TestAKeyForgottenIsAskedForAgainAndRefused`, `TestARevokedHostsVolumesArePendingRekey`, `TestARekeyedVolumeOpensWithItsOwnKeyAlone`, `TestAHeadWrittenByAHostThatLeftIsPassedOverAndSaid`, the DST's `a-share-opens-only-its-snapshot` and `a-rekeyed-volume-depends-on-no-other-key`; `TestAMovedVolumeIsRestoredFromItsHoldersHistory`, `TestAMoveGrantsTheVolumeOverItsHistory`, the DST's `a-moved-volume-restores-its-new-holders-history`, the storage lane's `TestAMoveFencesTheHostTheVolumeLeft` | +| I7 | Bytes a guest controls are bounded (size, count, time) and made valid (UTF-8, paths) where they cross into the host. | the `CHECK`s; `TestWhatAGuestWritesIsBoundedBeforeItIsARow`, `TestAnAgentsThreadIndexIsBoundedAndReplacedWhole`, `TestAFloodOfNoticesIsAReadingAnInterval` | +| I8 | A host is trusted only for what is placed on it, and says only what a host may say - its guests' supervisors included, whose streams it carries under its own token. | `runnerMessageBinding` and its two tests; `TestAHostCarriesOnlyTheSupervisorsOfWorkspacesPlacedOnIt`, `TestWhatReachesTheControlPlaneIsTheSupervisorsCall`; `TestAHostsMintedCredentialWritesOnlyItsOwnSubtree`, against the store; `TestAHostsCredentialsLastAQuarterOfAnHour`, `TestAKeyForgottenIsAskedForAgainAndRefused`, `TestARevokedHostsVolumesArePendingRekey`, `TestAGroupsRunnerRemovedAsTakenHasItsDisksMarkedForRekeying`, `TestARekeyedVolumeOpensWithItsOwnKeyAlone`, `TestAHeadWrittenByAHostThatLeftIsPassedOverAndSaid`, the DST's `a-share-opens-only-its-snapshot` and `a-rekeyed-volume-depends-on-no-other-key`; `TestAMovedVolumeIsRestoredFromItsHoldersHistory`, `TestAMoveGrantsTheVolumeOverItsHistory`, the DST's `a-moved-volume-restores-its-new-holders-history`, the storage lane's `TestAMoveFencesTheHostTheVolumeLeft` | | I9 | Object-store bytes are checked against the database-anchored digest before use; a shared key is read at its published version. | `TestALayerWrittenOverIsStillReadAsPublished` | | I10 | An effect outside the database happens before the row that names it is forgotten. | *none* | | I11 | Every third-party action is pinned by commit. | `task lint:workflows` | @@ -30,7 +30,7 @@ The rules every entry point must keep, from spin's [`docs/security/README.md`](h | I15 | A program that parses a tenant's bytes on the host opens only the files of its operation. | `TestOnlyARootRunnerOnANewLandlockSaysItHoldsAProgramToItsFiles`, `TestAProductionInstallationPlacesOnlyOnIsolatedHosts`, `TestQemuImgDoesItsWorkWithOnlyItsFiles`, `TestAProgramReadsOnlyWhatItIsGiven`, `TestAProgramWritesOnlyWhatItIsGiven`, `TestAProgramMakesNoSocket`; the VM lane's `TestARootRunnersProgramHoldsNothingOfRoots`; the storage fakes refuse a file a run was not given, as the kernel does | | I16 | A store on the control plane's machine is reached by the installation's administrators only through the control plane, and by its processes only for what each is. | `TestOnlyTheControlPlaneSaysWhoTheAdministratorIs`, `TestGrafanaShowsTheStoreToTheAdministratorItIsTold`, `TestNothingWithoutTheStoresKeyTakesItsMetrics`, `TestTheStoresRunWhileTheirControlPlaneDoes` (each account to each port, against the kernel), `TestTheStoresGuardNamesEveryPortAndOnlyAccountsTheImageHas`; the dashboard lane's `Monitoring access` and `Admin Metrics` | | I17 | Only a workspace's owner and the guests they let in log in to it, each with a key that logs in as them - one they added, or a session's within its twelve hours - under the installation's certificate, never into a prebuild's build; a key, a passkey past the first and a guest are added only with an assertion of the person's passkey over a challenge naming that change, so their session alone adds none; the control plane holds no key that logs in and is never an SSH client of a guest (ADR-0031). | `TestATunnelCertifiesOnlyAKeyThatLogsInAsTheCaller`, `TestAKeyIsAddedOnlyWithThePasskeysAssertionForIt`, `TestLettingAGuestInTakesTheOwnersPasskey`, `TestAKeyLogsInWhileItIsLive`, `TestAPasskeyIsRegisteredOnlyAsItsRelyingPartysOverItsChallenge`, `TestAnAssertionHoldsOnlyAsItsPasskeysOverItsChallenge`, `TestAPreparedRootLetsInOnlyByTheInstallationsCertificate`, `TestOnlyTheListedProceduresAdmitAGuest`; the sshd lanes' `TestASessionKeyLogsInWithACertificateOverIt`, `TestTheTerminalLogsInToTheClaimedGuest`; the VM lane's `TestOnlyTheOwnerAndTheirGuestsLogInToAWorkspace`, `TestAGuestTakenOutStaysOutOfAWorkspaceRestoredToBeforeIt`, `TestTheOwnerLogsInToACloneOfTheirOwnSnapshot`; `TestAGuestIsConnectedToOnlyByAClaimThatHolds`, `TestASessionIsRefusedBeforeTheRelayIsDialled` | -| I19 | A workspace's identity is signed by the host that runs it, for the machine that asked, named as the control plane's set says it - its team while its owner is in it, its owner, image and parent - never for a prebuild's build, and given only for an audience the installation allows; the control plane holds no key that signs one. | `TestATokenIsTheAskingMachinesWorkspace`, `TestATokenIsForAnAudienceTheInstallationAllows`, `TestARunIsHeldToTheFirstKeyItPresents`, `TestAMachineIsNamedAsItsSetSays`, `TestAMachineNamedByNobodyIsGivenNoIdentity`, `TestACloneIsNamedAsMadeFromItsSnapshot`, `TestAStartNamesTheNewestSupervisorRelease`, `TestAHostOpensTheKeyThroughAnAttestedDecrypt`, `TestAHostWritesOnlyItsOwnIdentityRecords`; the VM lane's `TestAWorkspacesIdentityIsTheHostsSignatureOfItsSet` | +| I19 | A workspace's identity is signed by the host that runs it, for the machine that asked, named as the control plane's set says it - its team while its owner is in it, its owner, image and parent - never for a prebuild's build, and given only for an audience the installation allows; the control plane holds no key that signs one. | `TestATokenIsTheAskingMachinesWorkspace`, `TestAMachinesCIDIsUnnamedBeforeAnotherMachineIsGivenIt`, `TestAMachineIsNamedOnlyAtTheCIDTheRuntimeRunsItAt`, `TestTheSameCIDNamedAgainIsAnotherNaming`, `TestARestartedMachineIsNeverSignedForAsTheRunBefore`, `TestASessionReachesOnlyTheMachineItsWorkspaceWasNamedAt`, `TestAWorkspacesCIDIsItsRunningMachines`, `TestAMachinesCIDIsTakenBackBeforeAnotherMachineCanHaveIt`, `TestATokenIsForAnAudienceTheInstallationAllows`, `TestARunIsHeldToTheFirstKeyItPresents`, `TestAMachineIsNamedAsItsSetSays`, `TestAMachineNamedByNobodyIsGivenNoIdentity`, `TestACloneIsNamedAsMadeFromItsSnapshot`, `TestAStartNamesTheNewestSupervisorRelease`, `TestAHostOpensTheKeyThroughAnAttestedDecrypt`, `TestAHostWritesOnlyItsOwnIdentityRecords`; the VM lane's `TestAWorkspacesIdentityIsTheHostsSignatureOfItsSet`, `TestAMachineKilledUnderItsWorkspaceIsNoticedAndPutAway`, `TestAMachinesCIDIsHeardOfOnceHoweverItIsEnded`, `TestAnAdoptedMachinesCIDIsHeardOfOnceHoweverItEnds` | | I18 | What a workspace applies of its owner's - dotfiles, shell, environment, editor settings, Taskfile, the workspace's own environment - is what they saved, with no value that hides what it runs; and the owner's own go only where they alone are root: not to a workspace a guest was asked into, a copy of another person's snapshot, or a prebuild's build. A guest is given its own workspace's environment, never another's. | `TestTheGuestIsHandedTheSettingsItsOwnerSaved`, `TestTheOwnersNewlySavedSettingsReachARunningGuest`, `TestAPrebuildsBuildIsTheProjectsAndNobodysOwn`, `TestTheOwnersSettingsGoOnceAGuestIsLetIn`, `TestSettingsHandedToARunningGuestApplyAsTheyCome`, `TestABuildChecksOutItsCommit`, `TestAPrebuildsCheckoutIsHeldToItsCommit`, `TestSettingsThatHideWhatTheyRunAreRefused`, `TestSettingsThatHideWhatTheyRunAreNotSaved`, `TestAProjectOpensFromItsNewestPrebuild`; the e2e lane's `TestTheOwnersSettingsArriveInTheGuest` | | I20 | No commit holds a credential, in any file. | `task lint:secrets` | | I21 | A team's secret kept as a reference is read only as the team whose secret it is, so a team's admin cannot name another team's secret, or the installation's. | `TestASecretIsReadInASessionTaggedWithItsTeam`, `TestASecretSetAsAReferenceIsReadAsTheTeamBeforeItIsKept`, `TestASecretKeptAsAReferenceIsReadAsTheTeamThatKeepsIt`; spin-terraform-aws's posture run `a_teams_secret_is_read_only_as_the_team` | @@ -39,3 +39,4 @@ The rules every entry point must keep, from spin's [`docs/security/README.md`](h | I24 | A command run or a file read or written in a workspace through the API is the owner's, on a key made with their passkey that holds `workspace:exec`, and is recorded with who asked and the key it came on before it reaches the workspace. | `TestEveryProcedureHasAScope`, `TestOnlyTheListedProceduresAdmitAGuest`, `TestAStrangerGetsNothingOfSomebodyElses`; the e2e lane's `TestAKeyWithExecRunsACommandInAWorkspaceAndOneWithoutIsRefused` | | I25 | A key delegated from another holds no more than it - scopes, team, projects, end, the workspaces and cores its tree holds, and how far down the chain - reaches no workspace outside its team and projects, and goes when the key it came from does. | `TestADelegatedKeyHoldsNoMoreThanItsParent`, `TestAKeyDelegatesNoMoreThanItHolds`, `TestAKeyReachesOnlyItsTeamsAndProjectsWorkspaces`; the CLI lane's `TestE2E_AnAgentDrivesAWorkspaceThroughMCPOnADelegatedKey` | | I26 | A workload's identity buys a key only as the SPIFFE spec has it - a JWT-SVID go-spiffe validates against the trust domain's bundle, for the control plane's own audience - and only a child of the live key that made its workspace, within it (I25), for an hour at most, gone when the workspace goes to the trash. | `TestATokenForTheControlPlaneIsAJWTSVIDGoSpiffeValidates`, `TestAWorkloadExchangesItsIdentityForAChildOfTheKeyThatMadeItsWorkspace`; the e2e lane's `TestAnAgentInAWorkspaceDrivesAnotherOnTheIdentityOfItsWorkspace` | +| I27 | An installation's administrator acts on a workspace that is not theirs only through the procedures that say so, each from a session and audited with whose workspace it was: held in quarantine and released, its bandwidth bounded, its disk re-keyed, stopped, moved off a host that is gone - with a reason, which its owner reads on the workspace's history - and where it sends, read. Being an administrator opens no session or command in it, no snapshot of its disk, no start, and no say over who is let in: those are its owner's procedures, which answer an administrator as they answer a stranger. Nor does any of these acts read its env: each answers which workspace it acted on and what the act left, never the workspace itself. | `TestOnlyTheListedProceduresActOnAnybodysWorkspace`, `TestNoAdministratorsActOnAnybodysWorkspaceAnswersItsEnv`, `TestAnAdministratorsActsOnSomebodyElsesWorkspaceAnswerNoneOfItsEnv`, `TestAnAdministratorIsStillRefusedWhatIsTheOwnersAlone`, `TestAnAdministratorActsOnAWorkspaceThatIsNotTheirsAndItIsAudited`, `TestAnAdministratorsRecoverIsRefusedWithoutAReasonOrOfAHeldWorkspace`, `TestAStrangerGetsNothingOfSomebodyElses` | diff --git a/src/content/docs/reference/status/index.md b/src/content/docs/reference/status/index.md index 28e6bbe..50c37b8 100644 --- a/src/content/docs/reference/status/index.md +++ b/src/content/docs/reference/status/index.md @@ -9,7 +9,7 @@ sidebar: -Every row of this page is a line of `internal/features` in spin, and a test there resolves it against the tree. A row that says **built** names what shows the feature exists - a procedure the control plane serves, a command the CLI has, or a test - and, under **End to end**, the tests that drive a real runner and its guest and check what the feature did, or what no test checks yet. spin's build checks that each of those tests is there and not quarantined; whether it checks the whole feature is its review's. A row that says **not built** is an item of [`docs/ROADMAP.md`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/docs/ROADMAP.md). The page is written by `task reference` from `spin features` at spin `b7ba5206f`, and cannot say a feature the binary does not. spin is a private repository: a link to its code opens only for someone with access to it. +Every row of this page is a line of `internal/features` in spin, and a test there resolves it against the tree. A row that says **built** names what shows the feature exists - a procedure the control plane serves, a command the CLI has, or a test - and, under **End to end**, the tests that drive a real runner and its guest and check what the feature did, or what no test checks yet. spin's build checks that each of those tests is there and not quarantined; whether it checks the whole feature is its review's. A row that says **not built** is an item of [`docs/ROADMAP.md`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/docs/ROADMAP.md). The page is written by `task reference` from `spin features` at spin `911f516bc`, and cannot say a feature the binary does not. spin is a private repository: a link to its code opens only for someone with access to it. ## Built @@ -17,132 +17,137 @@ Every row of this page is a line of `internal/features` in spin, and a test ther | Feature | Exists | End to end | |---|---|---| -| A machine per workspace: KVM, its own kernel, root, a persistent disk, SSH | [`TestAWorkspaceBootsARealGuest`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/vm_test.go#L190), a test of `internal/e2e` | [`TestAWorkspaceBootsARealGuest`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/vm_test.go#L190) | -| Create, start, stop and delete | [`WorkspaceService/CreateWorkspace`](/reference/api/workspaceservice/) | [`TestE2E_WorkspaceCRUD`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/e2e_test.go#L424) | -| A trash: a deleted workspace stays whole, for its owner to undelete, until its days are up | [`TestAWorkspaceWhoseDaysInTheTrashAreUpIsErasedFromItsHost`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L389), a test of `internal/e2e` | [`TestATrashedWorkspaceIsWholeWhenItsOwnerUndeletesIt`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L421)
[`TestAWorkspaceWhoseDaysInTheTrashAreUpIsErasedFromItsHost`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L389) | -| Idle suspend, with a question before it that a keep answers | [`TestAWorkspaceIsAskedBeforeItsSuspensionAndAKeepAnswersIt`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L108), a test of `internal/e2e` | [`TestAWorkspaceIsAskedBeforeItsSuspensionAndAKeepAnswersIt`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L108) | -| A workspace that ran as long as the installation allows is suspended | [`TestAWorkspaceThatRanForAsLongAsAllowedIsSuspended`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L70), a test of `internal/e2e` | [`TestAWorkspaceThatRanForAsLongAsAllowedIsSuspended`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L70) | -| A process inside holds its workspace awake while it lives | [`TestAProcessHoldsItsWorkspaceAwakeWhileItLives`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L199), a test of `internal/e2e` | [`TestAProcessHoldsItsWorkspaceAwakeWhileItLives`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L199) | -| Suspend with the processes where they are; a start resumes them | [`TestAWorkspaceNobodyUsesIsSuspendedAndAStartResumesIt`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L36), a test of `internal/e2e` | [`TestE2E_ASuspendedWorkspaceResumesWhereItWas`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/journeys_e2e_test.go#L288)
[`TestAWorkspaceNobodyUsesIsSuspendedAndAStartResumesIt`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L36) | -| Cores and memory lent while the host has them, and taken back
*A loan refused while the host is full has no test against the stack: the budget is the host's own cores and half its memory, which no lane's workspaces fill.* | [`TestABusyWorkspaceIsLentCoresAndGivesThemBack`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L352), a test of `internal/e2e` | [`TestABusyWorkspaceIsLentCoresAndGivesThemBack`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L352)
[`TestABusyWorkspaceIsLentMemoryAndGivesItBack`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/memory_test.go#L109) | -| A grant of cores and memory of its own, for a while | [`TestAGrantWhoseTimeIsUpIsGivenBackToTheMachine`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L298), a test of `internal/e2e` | [`TestAGrantWhoseTimeIsUpIsGivenBackToTheMachine`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/background_test.go#L298)
[`TestAResumedWorkspaceIsGivenWhatItIsGrantedWhileItRuns`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/resume_grant_test.go#L20) | -| An administrator changes a running workspace's bandwidth, its connections open | [`TestAnAdministratorChangesARunningWorkspacesBandwidth`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/bandwidth_test.go#L118), a test of `internal/e2e` | [`TestAnAdministratorChangesARunningWorkspacesBandwidth`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/bandwidth_test.go#L118)
[`TestAWorkspacesBandwidthHoldsAcrossItsRunsAndItsRunner`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/bandwidth_test.go#L172) | -| Move a running workspace to another host, its processes as they are | [`TestHostsAMoveTakesARunningWorkspaceToAnotherHost`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/hosts_flows_test.go#L65), a test of `internal/e2e` | [`TestHostsAMoveTakesARunningWorkspaceToAnotherHost`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/hosts_flows_test.go#L65) | -| Clone a workspace: its disk, team, project, size, policies and environment, in one | [`TestACloneHoldsWhatItsSourceWroteAndItsShape`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/clone_test.go#L64), a test of `internal/e2e` | [`TestACloneHoldsWhatItsSourceWroteAndItsShape`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/clone_test.go#L64) | -| Recover a workspace whose host is gone, at a cost its owner accepts | [`TestHostsAWorkspaceWhoseHostIsGoneIsRecoveredOnAnother`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/hosts_flows_test.go#L100), a test of `internal/e2e` | [`TestHostsAWorkspaceWhoseHostIsGoneIsRecoveredOnAnother`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/hosts_flows_test.go#L100) | -| A workspace outlives its runner | [`TestAWorkspaceOutlivesItsRunner`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/vm_test.go#L341), a test of `internal/e2e` | [`TestAWorkspaceOutlivesItsRunner`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/vm_test.go#L341) | -| Quarantine, by an administrator | [`WorkspaceService/QuarantineWorkspace`](/reference/api/workspaceservice/) | [`TestE2E_AQuarantinedWorkspaceIsHeldUntilReleased`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/journeys_e2e_test.go#L337) | -| Why a workspace is not behaving: status, console, history | [`spin workspace status`](/reference/cli/workspace/) | [`TestE2E_AQuarantinedWorkspaceIsHeldUntilReleased`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/journeys_e2e_test.go#L337)
[`TestE2E_AWorkspacesConsoleIsWhatItsMachinePrinted`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/journeys_e2e_test.go#L370) | -| The owner's shell, environment, editor settings, Taskfile and dotfiles reach the guest as they save them | [`TestAWorkspacesOwnEnvironmentIsInItsOwnersLoginShell`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/env_test.go#L22), a test of `internal/e2e` | [`TestTheOwnersSettingsArriveInTheGuest`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/env_test.go#L74)
[`TestAWorkspacesOwnEnvironmentIsInItsOwnersLoginShell`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/env_test.go#L22) | -| Reset a disk to what it was created from | [`spin workspace reset`](/reference/cli/workspace/) | [`TestE2E_ResetPutsAWorkspaceBackToWhatItWasCreatedFrom`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/e2e_test.go#L1230) | -| Claude Code, Codex and T3 Code on every workspace's PATH, at the versions the release pins, with their own defaults
*Where an administrator accepted their terms (Admin → Extensions) or an operator publishes them: no image carries Claude Code, which only Anthropic may distribute.* | [`TestTheAgentCLIsAreOnPathWithThePinnedVersions`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/agentclis_test.go#L24), a test of `internal/e2e` | [`TestTheAgentCLIsAreOnPathWithThePinnedVersions`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/agentclis_test.go#L24) | -| An agent UI: T3 Code in a workspace as its agent user, over the owner's SSH session - from `spin agent` on the person's computer, or in the workspace's Agent tab in the dashboard, which frames the client and carries it over a passkey's session
*The lane has no provider credential, so no test has a model answer through the brokered egress: the server is reached, as the agent's user, and nothing is asked of it. The browser's test drives the page with a virtual authenticator, which no real passkey's maker vouches for.* | [`spin agent --port`](/reference/cli/agent/) | [`TestTheSupervisorRunsTheAgentForItsOwner`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/t3_test.go#L79)
[`TestE2E_TheAgentIsServedOnThisComputerWhileTheSessionIsOpen`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/journeys_e2e_test.go#L94)
[`agent.spec.ts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/dashboard/e2e/agent.spec.ts#L62): a passkey signs the person in, and the agent runs in their workspace from the dashboard | -| Claude Code and Codex signed in from the agent's page: each CLI's own login, run by the supervisor as the agent's user, its credentials kept in the agent's home and never passing through the page
*The lane has no provider account: it begins a login and sees the provider's page, and finishing one is the unit tests' on each CLI's own output.* | `AgentService/BeginLogin` | [`TestTheSupervisorRunsTheAgentForItsOwner`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/t3_test.go#L79) | -| A person signs Claude Code and Codex in once: every workspace of theirs, plain or a project's, is handed the same credentials and hands back each refresh and logout, and a workspace that names a guest holds none
*The lane has no provider account: its login is the file the CLI writes, written as the agent's user. Only a workspace its owner's alone through all it came from holds them: a project opened from its prebuild does, but not a prebuild's build, a copy of another person's snapshot, or one made before the release that keeps the mark.* | [`TestAPersonSignsInToTheAgentOnceForEveryWorkspaceOfTheirs`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/agentcredentials_test.go#L29), a test of `internal/e2e` | [`TestAPersonSignsInToTheAgentOnceForEveryWorkspaceOfTheirs`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/agentcredentials_test.go#L29) | -| The supervisor runs the agent for its owner while it is used: started, paired and listed over the owner's own session on a socket only root opens, and stopped once nobody has used it for half an hour and no chat is at work
*That it stops once idle is the sweep's unit test on a clock the test moves: no lane waits half an hour.* | `AgentService/Start` | [`TestTheSupervisorRunsTheAgentForItsOwner`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/t3_test.go#L79) | -| The agent's chats listed on the workspace - titles, paths and times, never a message - reported by its supervisor | [`WorkspaceService/ListAgentThreads`](/reference/api/workspaceservice/) | [`TestTheAgentsThreadsAreListed`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/t3_test.go#L184) | -| The agent's home is a volume of its own: the chats and sessions outlive the workspace, kept in the installation's store as every disk is, and a new workspace mounts them at its creation
*Sealed with the workspace's checkpoints, claimed with the launch beside the disk, and moved with the workspace.* | [`spin workspace create --agent-home`](/reference/cli/workspace/) | [`TestAnAgentsHomeOutlivesItsWorkspace`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/agenthome_test.go#L78) | +| A machine per workspace: KVM, its own kernel, root, a persistent disk, SSH | [`TestAWorkspaceBootsARealGuest`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/vm_test.go#L190), a test of `internal/e2e` | [`TestAWorkspaceBootsARealGuest`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/vm_test.go#L190) | +| Create, start, stop and delete | [`WorkspaceService/CreateWorkspace`](/reference/api/workspaceservice/) | [`TestE2E_WorkspaceCRUD`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/e2e_test.go#L426) | +| A trash: a deleted workspace stays whole, for its owner to undelete, until its days are up | [`TestAWorkspaceWhoseDaysInTheTrashAreUpIsErasedFromItsHost`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L507), a test of `internal/e2e` | [`TestATrashedWorkspaceIsWholeWhenItsOwnerUndeletesIt`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L539)
[`TestAWorkspaceWhoseDaysInTheTrashAreUpIsErasedFromItsHost`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L507) | +| Idle suspend, with a question before it that a keep answers | [`TestAWorkspaceNobodyUsesIsSuspendedUnlessKeptOrHeld`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L36), a test of `internal/e2e` | [`TestAWorkspaceNobodyUsesIsSuspendedUnlessKeptOrHeld`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L36) | +| A workspace that ran as long as the installation allows is suspended | [`TestAWorkspaceThatRanForAsLongAsAllowedIsSuspended`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L172), a test of `internal/e2e` | [`TestAWorkspaceThatRanForAsLongAsAllowedIsSuspended`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L172) | +| A process inside holds its workspace awake while it lives | [`TestAWorkspaceNobodyUsesIsSuspendedUnlessKeptOrHeld`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L36), a test of `internal/e2e` | [`TestAWorkspaceNobodyUsesIsSuspendedUnlessKeptOrHeld`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L36) | +| Suspend with the processes where they are; a start resumes them | [`TestAWorkspaceNobodyUsesIsSuspendedUnlessKeptOrHeld`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L36), a test of `internal/e2e` | [`TestE2E_ASuspendedWorkspaceResumesWhereItWas`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/journeys_e2e_test.go#L289)
[`TestAWorkspaceNobodyUsesIsSuspendedUnlessKeptOrHeld`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L36) | +| Cores and memory lent while the host has them, and taken back
*A loan refused while the host is full has no test against the stack: the budget is the host's own cores and half its memory, which no lane's workspaces fill.* | [`TestABusyWorkspaceIsLentCoresAndGivesThemBack`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L470), a test of `internal/e2e` | [`TestABusyWorkspaceIsLentCoresAndGivesThemBack`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L470)
[`TestABusyWorkspaceIsLentMemoryAndGivesItBack`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/memory_test.go#L110)
[`TestAnEditorAtTheFloorIsNotKilledForMemory`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/memory_test.go#L162) | +| A grant of cores and memory of its own, for a while | [`TestAGrantWhoseTimeIsUpIsGivenBackToTheMachine`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L416), a test of `internal/e2e` | [`TestAGrantWhoseTimeIsUpIsGivenBackToTheMachine`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/background_test.go#L416)
[`TestAResumedWorkspaceIsGivenWhatItIsGrantedWhileItRuns`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/resume_grant_test.go#L20) | +| An administrator changes a running workspace's bandwidth, its connections open | [`TestAnAdministratorChangesARunningWorkspacesBandwidth`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/bandwidth_test.go#L118), a test of `internal/e2e` | [`TestAnAdministratorChangesARunningWorkspacesBandwidth`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/bandwidth_test.go#L118)
[`TestAWorkspacesBandwidthHoldsAcrossItsRunsAndItsRunner`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/bandwidth_test.go#L172) | +| Move a running workspace to another host, its processes as they are | [`TestHostsAMoveTakesARunningWorkspaceToAnotherHost`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/hosts_flows_test.go#L65), a test of `internal/e2e` | [`TestHostsAMoveTakesARunningWorkspaceToAnotherHost`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/hosts_flows_test.go#L65) | +| Clone a workspace: its disk, team, project, size, policies and environment, in one | [`TestACloneHoldsWhatItsSourceWroteAndItsShape`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/clone_test.go#L64), a test of `internal/e2e` | [`TestACloneHoldsWhatItsSourceWroteAndItsShape`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/clone_test.go#L64) | +| Recover a workspace whose host is gone, at a cost its owner accepts | [`TestHostsAWorkspaceWhoseHostIsGoneIsRecoveredOnAnother`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/hosts_flows_test.go#L100), a test of `internal/e2e` | [`TestHostsAWorkspaceWhoseHostIsGoneIsRecoveredOnAnother`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/hosts_flows_test.go#L100) | +| A workspace outlives its runner | [`TestAWorkspaceOutlivesItsRunner`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/vm_test.go#L343), a test of `internal/e2e` | [`TestAWorkspaceOutlivesItsRunner`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/vm_test.go#L343) | +| Quarantine, by an administrator | [`WorkspaceService/QuarantineWorkspace`](/reference/api/workspaceservice/) | [`TestE2E_AQuarantinedWorkspaceIsHeldUntilReleased`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/journeys_e2e_test.go#L338) | +| Why a workspace is not behaving: status, console, history | [`spin workspace status`](/reference/cli/workspace/) | [`TestE2E_AQuarantinedWorkspaceIsHeldUntilReleased`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/journeys_e2e_test.go#L338)
[`TestE2E_AWorkspacesConsoleIsWhatItsMachinePrinted`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/journeys_e2e_test.go#L371) | +| The owner's shell, environment, editor settings, Taskfile and dotfiles reach the guest as they save them | [`TestAWorkspacesOwnEnvironmentIsInItsOwnersLoginShell`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/env_test.go#L22), a test of `internal/e2e` | [`TestTheOwnersSettingsArriveInTheGuest`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/env_test.go#L74)
[`TestAWorkspacesOwnEnvironmentIsInItsOwnersLoginShell`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/env_test.go#L22) | +| Reset a disk to what it was created from | [`spin workspace reset`](/reference/cli/workspace/) | [`TestE2E_ResetPutsAWorkspaceBackToWhatItWasCreatedFrom`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/e2e_test.go#L1352) | +| Claude Code, Codex and T3 Code on every workspace's PATH, at the versions the release pins, with their own defaults
*Where an administrator accepted their terms (Admin → Extensions) or an operator publishes them: no image carries Claude Code, which only Anthropic may distribute.* | [`TestTheAgentCLIsAreOnPathWithThePinnedVersions`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/agentclis_test.go#L24), a test of `internal/e2e` | [`TestTheAgentCLIsAreOnPathWithThePinnedVersions`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/agentclis_test.go#L24) | +| An agent UI: T3 Code in a workspace as its agent user, over the owner's SSH session - from `spin agent` on the person's computer, or in the workspace's Agent tab in the dashboard, which frames the client and carries it over a passkey's session
*The lane has no provider credential, so no test has a model answer through the brokered egress: the server is reached, as the agent's user, and nothing is asked of it. The browser's test drives the page with a virtual authenticator, which no real passkey's maker vouches for.* | [`spin agent --port`](/reference/cli/agent/) | [`TestTheSupervisorRunsTheAgentForItsOwner`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/t3_test.go#L79)
[`TestE2E_TheAgentIsServedOnThisComputerWhileTheSessionIsOpen`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/journeys_e2e_test.go#L95)
[`agent.spec.ts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/dashboard/e2e/agent.spec.ts#L62): a passkey signs the person in, and the agent runs in their workspace from the dashboard | +| Claude Code and Codex signed in from the agent's page: each CLI's own login, run by the supervisor as the agent's user, its credentials kept in the agent's home and never passing through the page
*The lane has no provider account: it begins a login and sees the provider's page, and finishing one is the unit tests' on each CLI's own output.* | `AgentService/BeginLogin` | [`TestTheSupervisorRunsTheAgentForItsOwner`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/t3_test.go#L79) | +| A person signs Claude Code and Codex in once: every workspace of theirs, plain or a project's, is handed the same credentials and hands back each refresh and logout, and a workspace that names a guest holds none
*The lane has no provider account: its login is the file the CLI writes, written as the agent's user. Only a workspace its owner's alone through all it came from holds them: a project opened from its prebuild does, but not a prebuild's build, a copy of another person's snapshot, or one made before the release that keeps the mark.* | [`TestAPersonSignsInToTheAgentOnceForEveryWorkspaceOfTheirs`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/agentcredentials_test.go#L29), a test of `internal/e2e` | [`TestAPersonSignsInToTheAgentOnceForEveryWorkspaceOfTheirs`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/agentcredentials_test.go#L29) | +| The supervisor runs the agent for its owner while it is used: started, paired and listed over the owner's own session on a socket only root opens, and stopped once nobody has used it for half an hour and no chat is at work
*That it stops once idle is the sweep's unit test on a clock the test moves: no lane waits half an hour.* | `AgentService/Start` | [`TestTheSupervisorRunsTheAgentForItsOwner`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/t3_test.go#L79) | +| The agent's chats listed on the workspace - titles, paths and times, never a message - reported by its supervisor | [`WorkspaceService/ListAgentThreads`](/reference/api/workspaceservice/) | [`TestTheAgentsThreadsAreListed`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/t3_test.go#L134) | +| Chat mode: the dashboard flips to the person's own chats across their workspaces, grouped by project, with the agent full height and a new chat that makes its workspace | [`WorkspaceService/ListOwnAgentThreads`](/reference/api/workspaceservice/) | not yet: The RPC is held to the caller's own chats by its unit test, the mode by the dashboard's; no lane opens chat mode in a browser against an agent that has reported. | +| The agent's home is a volume of its own: the chats and sessions outlive the workspace, kept in the installation's store as every disk is, and a new workspace mounts them at its creation
*Sealed with the workspace's checkpoints, claimed with the launch beside the disk, and moved with the workspace.* | [`spin workspace create --agent-home`](/reference/cli/workspace/) | [`TestAnAgentsHomeOutlivesItsWorkspace`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/agenthome_test.go#L78) | ### Teams and projects | Feature | Exists | End to end | |---|---|---| -| Open a repository, branch, commit or pull request from its URL, in the dashboard (/launch) and from the terminal
*From the terminal; the dashboard's /launch page makes the same create and has no test of its own against the stack.* | [`spin open --no-connect`](/reference/cli/open/) | [`TestE2E_AURLOpensTheWorkspaceItNames`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/journeys_e2e_test.go#L222) | -| A workspace opened at a commit or a pull request, checked out as pr-<n> | [`TestAProjectsWorkspaceOpensAtTheCommitItWasAskedFor`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/project_test.go#L153), a test of `internal/e2e` | [`TestAProjectsWorkspaceOpensAtTheCommitItWasAskedFor`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/project_test.go#L153)
[`TestE2E_AURLOpensTheWorkspaceItNames`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/journeys_e2e_test.go#L222) | -| Teams, with owner, admin and member | [`spin team member role`](/reference/cli/team/) | [`TestE2E_ATeamRoleIsWhatItsHolderMayDo`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/e2e_test.go#L502) | -| A team's own identity providers | [`TeamService/CreateIdentityProvider`](/reference/api/teamservice/) | [`TestE2E_ATeamsIdentityProviderIsItsAdminsAndSignsNobodyIn`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/e2e_test.go#L534) | +| Open a repository, branch, commit or pull request from its URL, in the dashboard (/launch) and from the terminal
*From the terminal; the dashboard's /launch page makes the same create and has no test of its own against the stack.* | [`spin open --no-connect`](/reference/cli/open/) | [`TestE2E_AURLOpensTheWorkspaceItNames`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/journeys_e2e_test.go#L223) | +| A workspace opened at a commit or a pull request, checked out as pr-<n> | [`TestAProjectsWorkspaceOpensAtTheCommitItWasAskedFor`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/project_test.go#L156), a test of `internal/e2e` | [`TestAProjectsWorkspaceOpensAtTheCommitItWasAskedFor`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/project_test.go#L156)
[`TestE2E_AURLOpensTheWorkspaceItNames`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/journeys_e2e_test.go#L223) | +| Teams, with owner, admin and member | [`spin team member role`](/reference/cli/team/) | [`TestE2E_ATeamRoleIsWhatItsHolderMayDo`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/e2e_test.go#L504) | +| A team's own identity providers | [`TeamService/CreateIdentityProvider`](/reference/api/teamservice/) | [`TestE2E_ATeamsIdentityProviderIsItsAdminsAndSignsNobodyIn`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/e2e_test.go#L536) | | Your GitHub account, connected once: private repositories cloned and pushed with nothing on the disk | [`ForgeService/CompleteConnect`](/reference/api/forgeservice/) | not yet: consent takes a person on GitHub's page, and revoking a grant would end the one authorization a lane could live on: checked by hand once per release | | Your GitHub account connected from the CLI, with a code entered on GitHub's page | [`spin git connect`](/reference/cli/git/) | not yet: the code is entered by a person on GitHub's page: checked by hand once per release | | A repository picked from the ones your account reaches | [`spin git repos`](/reference/cli/git/) | not yet: a real GitHub account the lane can search with | -| A team's own network policies, where the installation allows them | [`spin team policy set`](/reference/cli/team/) | [`TestATeamsOwnPolicyIsWhatItsWorkspacesReach`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/team_policy_test.go#L24) | -| Projects of the installation: a repository and the shape of the workspace that opens it, shared with everyone or some | [`TestAProjectsWorkspaceHasItsRepositoryCheckedOutAtTheRef`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/project_test.go#L27), a test of `internal/e2e` | [`TestAProjectsWorkspaceHasItsRepositoryCheckedOutAtTheRef`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/project_test.go#L27) | -| Prebuilds of a project's refs, as the floor of the workspaces that open them | [`TestAProjectOpensAsItsPrebuildMadeIt`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/prebuild_test.go#L24), a test of `internal/e2e` | [`TestAProjectOpensAsItsPrebuildMadeIt`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/prebuild_test.go#L24) | -| A team's workspaces run on the installation's hosts | [`TestATeamsWorkspaceRunsOnTheInstallationsHost`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/team_test.go#L20), a test of `internal/e2e` | [`TestATeamsWorkspaceRunsOnTheInstallationsHost`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/team_test.go#L20) | +| A team's own network policies, where the installation allows them | [`spin team policy set`](/reference/cli/team/) | [`TestATeamsOwnPolicyIsWhatItsWorkspacesReach`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/team_policy_test.go#L24) | +| Projects of the installation: a repository and the shape of the workspace that opens it, shared with everyone or some | [`TestAProjectsWorkspaceHasItsRepositoryCheckedOutAtTheRef`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/project_test.go#L27), a test of `internal/e2e` | [`TestAProjectsWorkspaceHasItsRepositoryCheckedOutAtTheRef`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/project_test.go#L27) | +| Prebuilds of a project's refs, as the floor of the workspaces that open them | [`TestAProjectOpensAsItsPrebuildMadeIt`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/prebuild_test.go#L24), a test of `internal/e2e` | [`TestAProjectOpensAsItsPrebuildMadeIt`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/prebuild_test.go#L24) | +| A team's workspaces run on the installation's hosts | [`TestATeamsWorkspaceRunsOnTheInstallationsHost`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/team_test.go#L20), a test of `internal/e2e` | [`TestATeamsWorkspaceRunsOnTheInstallationsHost`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/team_test.go#L20) | ### Snapshots | Feature | Exists | End to end | |---|---|---| -| Snapshots of a running workspace's disk | [`WorkspaceService/CreateSnapshot`](/reference/api/workspaceservice/) | [`TestACloneHoldsWhatItsSourceWroteAndItsShape`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/clone_test.go#L64)
[`TestADiskSnapshottedPastTheThresholdIsCompactedWhileItRuns`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/compaction_test.go#L19) | -| Snapshots with memory, resumed with their processes | [`TestARunningWorkspaceResumesFromASnapshotsMemory`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/restore_test.go#L175), a test of `internal/e2e` | [`TestARunningWorkspaceResumesFromASnapshotsMemory`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/restore_test.go#L175) | -| Restore a workspace to a snapshot | [`TestARestoredWorkspaceBootsOnTheSnapshotItWasRestoredTo`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/restore_test.go#L29), a test of `internal/e2e` | [`TestARestoredWorkspaceBootsOnTheSnapshotItWasRestoredTo`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/restore_test.go#L29)
[`TestE2E_TheQuickstartsDiffIsWhatTheSiteShows`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/site_e2e_test.go#L24) | -| A diff of the files that changed between two snapshots | [`TestADiffOfTwoSnapshotsIsWhatChangedBetweenThem`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/diff_test.go#L28), a test of `internal/e2e` | [`TestADiffOfTwoSnapshotsNamesWhatWasAddedChangedAndRemoved`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/diff_test.go#L95)
[`TestE2E_TheQuickstartsDiffIsWhatTheSiteShows`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/site_e2e_test.go#L24) | -| Share a snapshot with a person or make it public, and create a workspace from it | [`TestACloneOfASnapshotRegistersAsItself`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/clone_test.go#L23), a test of `internal/e2e` | [`TestASharedSnapshotIsCreatedFromByThePersonItIsSharedWith`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/share_test.go#L21) | -| What looks like a credential is found before a share, and the share refused unless acknowledged | [`ShareService/ShareSnapshot`](/reference/api/shareservice/) | [`TestE2E_ASharedSnapshotIsScannedForCredentials`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/journeys_e2e_test.go#L171) | -| A long chain is compacted while the workspace runs | [`TestADiskSnapshottedPastTheThresholdIsCompactedWhileItRuns`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/compaction_test.go#L19), a test of `internal/e2e` | [`TestADiskSnapshottedPastTheThresholdIsCompactedWhileItRuns`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/compaction_test.go#L19) | +| Snapshots of a running workspace's disk | [`WorkspaceService/CreateSnapshot`](/reference/api/workspaceservice/) | [`TestACloneHoldsWhatItsSourceWroteAndItsShape`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/clone_test.go#L64)
[`TestADiskSnapshottedPastTheThresholdIsCompactedWhileItRuns`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/compaction_test.go#L19) | +| Snapshots with memory, resumed with their processes | [`TestARunningWorkspaceResumesFromASnapshotsMemory`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/restore_test.go#L175), a test of `internal/e2e` | [`TestARunningWorkspaceResumesFromASnapshotsMemory`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/restore_test.go#L175) | +| Restore a workspace to a snapshot | [`TestARestoredWorkspaceBootsOnTheSnapshotItWasRestoredTo`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/restore_test.go#L29), a test of `internal/e2e` | [`TestARestoredWorkspaceBootsOnTheSnapshotItWasRestoredTo`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/restore_test.go#L29)
[`TestE2E_TheQuickstartsDiffIsWhatTheSiteShows`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/site_e2e_test.go#L24) | +| A diff of the files that changed between two snapshots | [`TestADiffOfTwoSnapshotsIsWhatChangedBetweenThem`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/diff_test.go#L28), a test of `internal/e2e` | [`TestADiffOfTwoSnapshotsNamesWhatWasAddedChangedAndRemoved`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/diff_test.go#L95)
[`TestE2E_TheQuickstartsDiffIsWhatTheSiteShows`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/site_e2e_test.go#L24) | +| Share a snapshot with a person or make it public, and create a workspace from it | [`TestACloneOfASnapshotRegistersAsItself`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/clone_test.go#L23), a test of `internal/e2e` | [`TestASharedSnapshotIsCreatedFromByThePersonItIsSharedWith`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/share_test.go#L21) | +| What looks like a credential is found before a share, and the share refused unless acknowledged | [`ShareService/ShareSnapshot`](/reference/api/shareservice/) | [`TestE2E_ASharedSnapshotIsScannedForCredentials`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/journeys_e2e_test.go#L172) | +| A long chain is compacted while the workspace runs | [`TestADiskSnapshottedPastTheThresholdIsCompactedWhileItRuns`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/compaction_test.go#L19), a test of `internal/e2e` | [`TestADiskSnapshottedPastTheThresholdIsCompactedWhileItRuns`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/compaction_test.go#L19) | ### Network | Feature | Exists | End to end | |---|---|---| -| Egress is closed by default; policies, by tag, name what a workspace may reach | [`TestAnOwnerMayOnlyChooseAPolicyTheInstallationDeclares`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/retag_test.go#L163), a test of `internal/e2e` | [`TestAWorkspaceNamedNoPolicyReachesNothing`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/retag_test.go#L71)
[`TestChangingAWorkspacesPoliciesReachesTheHostThatRunsIt`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/retag_test.go#L24) | -| A workspace's DNS goes upstream only for what its policy names, so a policy that closes egress closes the tunnel through names | [`TestAWorkspaceAsksItsResolverOnlyWhatItsPolicyNames`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/resolver_test.go#L76), a test of `internal/e2e` | [`TestAWorkspaceAsksItsResolverOnlyWhatItsPolicyNames`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/resolver_test.go#L76) | -| A policy changed reaches the host that runs the workspace | [`TestChangingAWorkspacesPoliciesReachesTheHostThatRunsIt`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/retag_test.go#L24), a test of `internal/e2e` | [`TestAnEditedPolicyChangesWhatARunningGuestReaches`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/retag_test.go#L100)
[`TestChangingAWorkspacesPoliciesReachesTheHostThatRunsIt`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/retag_test.go#L24) | -| Brokered names: the host's proxy stands in and adds what the workspace never holds - a team secret, a forge token, its identity, a cloud role
*The team secret's value is read at the origin; the forge token, identity and cloud role injections have no test against the stack.* | [`spin team secret set`](/reference/cli/team/) | [`TestAPersonsRuleAndAnAgentsOnOneNameEachArriveWithTheirOwnInjection`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/brokered_test.go#L99) | -| What a workspace reached, what it looked up and what it was refused | [`spin workspace egress`](/reference/cli/workspace/) | [`TestE2E_EgressIsAnsweredByTheHostTheWorkspaceRunsOn`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/e2e_test.go#L848) | -| Each request to a brokered name as the proxy read it, served or refused and why; and whether each injection's secret is the team's to give | [`TestABrokeredRequestIsSeenAsTheProxyReadIt`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/brokered_test.go#L27), a test of `internal/e2e` | [`TestABrokeredRequestIsSeenAsTheProxyReadIt`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/brokered_test.go#L27) | -| The egress proxy is a process of its own, holding no key of the host's, started again by the runner when it ends | [`TestTheEgressProxyIsAProcessOfItsOwnThatTheRunnerStartsAgain`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/egress_process_test.go#L21), a test of `internal/e2e` | [`TestTheEgressProxyIsAProcessOfItsOwnThatTheRunnerStartsAgain`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/egress_process_test.go#L21) | -| A brokered rule names whose it is, the agent's or the person's: one policy says what each may reach and with what | [`TestABrokeredNameForTheAgentIsTheAgentsAlone`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/brokered_test.go#L71), a test of `internal/e2e` | [`TestAPersonsRuleAndAnAgentsOnOneNameEachArriveWithTheirOwnInjection`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/brokered_test.go#L99)
[`TestABrokeredNameForTheAgentIsTheAgentsAlone`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/brokered_test.go#L71) | -| A WebSocket to a brokered name: its handshake under the rule's headers and scope, then bytes each way
*The rule's header on the handshake is not read at the origin: the lane's WebSocket echo answers frames, not headers.* | [`TestAWebSocketToABrokeredNameIsCarriedAfterItsHandshake`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/brokered_test.go#L167), a test of `internal/e2e` | [`TestAWebSocketToABrokeredNameCarriesTheGuestsBytesAndRefusesAPathOutOfScope`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/brokered_test.go#L195)
[`TestAWebSocketToABrokeredNameIsCarriedAfterItsHandshake`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/brokered_test.go#L167) | -| HTTP/2 to a brokered name, the proxy's ALPN the real host's: a rule's headers set stream by stream, gRPC's trailers both ways
*gRPC's trailers are egressproxy's h2 test against an origin of its own; the lane has no gRPC origin to reach.* | [`TestHTTP2ToABrokeredNameIsTheRealHosts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/brokered_test.go#L230), a test of `internal/e2e` | [`TestHTTP2ToABrokeredNameIsTheRealHosts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/brokered_test.go#L230)
[`TestEachStreamOfAnHTTP2ConnectionToABrokeredNameCarriesTheRulesHeader`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/brokered_test.go#L250) | -| Watch where a workspace connects, into its logs | [`spin workspace watch`](/reference/cli/workspace/) | [`TestE2E_AWatchedWorkspacesConnectionsAreInItsLogs`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/journeys_e2e_test.go#L388) | -| An agent the supervisor starts is marked, and reaches only brokered names | [`TestARealWorkspaceMarksTheAgentItsSupervisorStarts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/seal_test.go#L21), a test of `internal/e2e` | [`TestAnAgentReachesOnlyBrokeredNames`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/brokered_test.go#L137)
[`TestARealWorkspaceMarksTheAgentItsSupervisorStarts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/seal_test.go#L21) | -| Published ports at https://{port}-{workspace}.{domain}: private, whitelisted or public | [`spin port expose`](/reference/cli/port/) | [`TestAPublicPortIsReachedWithNoSessionAtAll`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/proxy/lane_test.go#L144)
[`workspace-sign-in.spec.ts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/dashboard/e2e/workspace-sign-in.spec.ts#L31): a visitor signed in to the dashboard reaches their private port | +| Egress is closed by default; policies, by tag, name what a workspace may reach | [`TestAnOwnerMayOnlyChooseAPolicyTheInstallationDeclares`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/retag_test.go#L163), a test of `internal/e2e` | [`TestAWorkspaceNamedNoPolicyReachesNothing`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/retag_test.go#L71)
[`TestChangingAWorkspacesPoliciesReachesTheHostThatRunsIt`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/retag_test.go#L24) | +| A workspace's DNS goes upstream only for what its policy names, so a policy that closes egress closes the tunnel through names | [`TestAWorkspaceAsksItsResolverOnlyWhatItsPolicyNames`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/resolver_test.go#L76), a test of `internal/e2e` | [`TestAWorkspaceAsksItsResolverOnlyWhatItsPolicyNames`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/resolver_test.go#L76) | +| A policy changed reaches the host that runs the workspace | [`TestChangingAWorkspacesPoliciesReachesTheHostThatRunsIt`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/retag_test.go#L24), a test of `internal/e2e` | [`TestAnEditedPolicyChangesWhatARunningGuestReaches`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/retag_test.go#L100)
[`TestChangingAWorkspacesPoliciesReachesTheHostThatRunsIt`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/retag_test.go#L24) | +| Brokered names: the host's proxy stands in and adds what the workspace never holds - a team secret, a forge token, its identity, a cloud role
*The team secret's value is read at the origin; the forge token, identity and cloud role injections have no test against the stack.* | [`spin team secret set`](/reference/cli/team/) | [`TestAPersonsRuleAndAnAgentsOnOneNameEachArriveWithTheirOwnInjection`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/brokered_test.go#L99) | +| What a workspace reached, what it looked up and what it was refused | [`spin workspace egress`](/reference/cli/workspace/) | [`TestE2E_EgressIsAnsweredByTheHostTheWorkspaceRunsOn`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/e2e_test.go#L970) | +| Each request to a brokered name as the proxy read it, served or refused and why; and whether each injection's secret is the team's to give | [`TestABrokeredRequestIsSeenAsTheProxyReadIt`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/brokered_test.go#L27), a test of `internal/e2e` | [`TestABrokeredRequestIsSeenAsTheProxyReadIt`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/brokered_test.go#L27) | +| The egress proxy is a process of its own, holding no key of the host's, started again by the runner when it ends | [`TestTheEgressProxyIsAProcessOfItsOwnThatTheRunnerStartsAgain`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/egress_process_test.go#L21), a test of `internal/e2e` | [`TestTheEgressProxyIsAProcessOfItsOwnThatTheRunnerStartsAgain`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/egress_process_test.go#L21) | +| A brokered rule names whose it is, the agent's or the person's: one policy says what each may reach and with what | [`TestABrokeredNameForTheAgentIsTheAgentsAlone`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/brokered_test.go#L71), a test of `internal/e2e` | [`TestAPersonsRuleAndAnAgentsOnOneNameEachArriveWithTheirOwnInjection`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/brokered_test.go#L99)
[`TestABrokeredNameForTheAgentIsTheAgentsAlone`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/brokered_test.go#L71) | +| A WebSocket to a brokered name: its handshake under the rule's headers and scope, then bytes each way
*The rule's header on the handshake is not read at the origin: the lane's WebSocket echo answers frames, not headers.* | [`TestAWebSocketToABrokeredNameIsCarriedAfterItsHandshake`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/brokered_test.go#L167), a test of `internal/e2e` | [`TestAWebSocketToABrokeredNameCarriesTheGuestsBytesAndRefusesAPathOutOfScope`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/brokered_test.go#L195)
[`TestAWebSocketToABrokeredNameIsCarriedAfterItsHandshake`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/brokered_test.go#L167) | +| HTTP/2 to a brokered name, the proxy's ALPN the real host's: a rule's headers set stream by stream, gRPC's trailers both ways
*gRPC's trailers are egressproxy's h2 test against an origin of its own; the lane has no gRPC origin to reach.* | [`TestHTTP2ToABrokeredNameIsTheRealHosts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/brokered_test.go#L230), a test of `internal/e2e` | [`TestHTTP2ToABrokeredNameIsTheRealHosts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/brokered_test.go#L230)
[`TestEachStreamOfAnHTTP2ConnectionToABrokeredNameCarriesTheRulesHeader`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/brokered_test.go#L250) | +| Watch where a workspace connects, into its logs | [`spin workspace watch`](/reference/cli/workspace/) | [`TestE2E_AWatchedWorkspacesConnectionsAreInItsLogs`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/journeys_e2e_test.go#L389) | +| An agent the supervisor starts is marked, and reaches only brokered names | [`TestARealWorkspaceMarksTheAgentItsSupervisorStarts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/seal_test.go#L21), a test of `internal/e2e` | [`TestAnAgentReachesOnlyBrokeredNames`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/brokered_test.go#L137)
[`TestARealWorkspaceMarksTheAgentItsSupervisorStarts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/seal_test.go#L21) | +| Published ports at https://{port}-{workspace}.{domain}: private, whitelisted or public | [`spin port expose`](/reference/cli/port/) | [`TestAPublicPortIsReachedWithNoSessionAtAll`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/proxy/lane_test.go#L144)
[`workspace-sign-in.spec.ts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/dashboard/e2e/workspace-sign-in.spec.ts#L31): a visitor signed in to the dashboard reaches their private port | ### Access | Feature | Exists | End to end | |---|---|---| | Sign in with GitHub or an OIDC provider | [`AuthService/StartLogin`](/reference/api/authservice/) | not yet: a GitHub provider: the sign-in through it and the verified email it gives | -| Device login for a terminal | [`AuthService/StartDeviceLogin`](/reference/api/authservice/) | [`TestE2E_Logout`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/e2e_test.go#L1217)
[`auth.spec.ts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/dashboard/e2e/auth.spec.ts#L18): the CLI's device page stands alone and keeps its code through a sign-in | -| API keys for scripts and agents | [`spin api-key create`](/reference/cli/api-key/) | [`TestE2E_APIKeyCRUD`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/e2e_test.go#L1172) | -| SSH keys, and plain ssh to spin.<workspace> | [`spin ssh-config`](/reference/cli/ssh-config/) | [`TestE2E_SSHConfigCarriesSSHToAWorkspace`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/e2e_test.go#L719) | -| A key logs in only once its person adds it with a passkey: their own for good, a browser's for twelve hours | [`PasskeyService/BeginPasskeyCeremony`](/reference/api/passkeyservice/) | [`TestOnlyTheOwnerAndTheirGuestsLogInToAWorkspace`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/login_test.go#L174) | -| Guests of a workspace, let in by its owner with a passkey | [`spin workspace guests`](/reference/cli/workspace/) | [`TestOnlyTheOwnerAndTheirGuestsLogInToAWorkspace`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/login_test.go#L174) | -| A workspace's identity, signed by its host, for the audiences its owner allows | [`TestAWorkspacesIdentityIsTheHostsSignatureOfItsSet`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/identity_test.go#L58), a test of `internal/e2e` | [`TestAWorkspacesIdentityIsTheHostsSignatureOfItsSet`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/identity_test.go#L58) | -| VS Code over SSH, with the server the installation publishes and nothing downloaded
*The server is Microsoft's, for Remote-SSH; spin code also opens an editor with Open Remote - SSH, which downloads its own. spin code itself is run by its unit tests only: it opens a desktop editor, which no lane has.* | [`TestAVSCodeServerOfAnotherCommitIsHandedToTheRunningMachine`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/vscodehotplug_test.go#L23), a test of `internal/e2e` | [`TestTheCarriedVSCodeServerRunsOfflineAndAnswersOverTheSSHTunnel`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/vscodeserver_test.go#L86)
[`TestAVSCodeServerOfAnotherCommitIsHandedToTheRunningMachine`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/vscodehotplug_test.go#L23) | -| Run a command in a workspace, copy files to and from it | [`spin exec`](/reference/cli/exec/) | [`TestE2E_ADetachedRunIsFollowedToItsEndAndFilesGoBothWays`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/journeys_e2e_test.go#L306) | -| A program runs a command and reads and writes files in a workspace through the API, with a key that holds workspace:exec, every call recorded with the key it came on | [`ExecService/Exec`](/reference/api/execservice/) | [`TestAKeyWithExecRunsACommandInAWorkspaceAndOneWithoutIsRefused`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/exec_test.go#L36) | -| An agent works in workspaces through `spin mcp` on a key delegated to it: never more than the key it came from - scopes, team, projects, end, how many workspaces and cores its tree holds - and revoked with it | [`spin mcp`](/reference/cli/mcp/) | [`TestE2E_AnAgentDrivesAWorkspaceThroughMCPOnADelegatedKey`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/mcp_e2e_test.go#L62) | -| An agent in a workspace drives others with spin, on a key it gets for the workspace's own SPIFFE identity - a child of the key that made the workspace, through its host, whatever the workspace's network
*No forge in the lane: a workspace reaches no private or host address, and no test repository has a credential in CI yet, so an agent opening a pull request is not run.* | [`AuthService/ExchangeWorkloadToken`](/reference/api/authservice/) | [`TestAnAgentInAWorkspaceDrivesAnotherOnTheIdentityOfItsWorkspace`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/inception_test.go#L97) | +| Device login for a terminal | [`AuthService/StartDeviceLogin`](/reference/api/authservice/) | [`TestE2E_Logout`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/e2e_test.go#L1339)
[`auth.spec.ts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/dashboard/e2e/auth.spec.ts#L18): the CLI's device page stands alone and keeps its code through a sign-in | +| API keys for scripts and agents | [`spin api-key create`](/reference/cli/api-key/) | [`TestE2E_APIKeyCRUD`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/e2e_test.go#L1294) | +| SSH keys, and plain ssh to spin.<workspace> | [`spin ssh-config`](/reference/cli/ssh-config/) | [`TestE2E_SSHConfigCarriesSSHToAWorkspace`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/e2e_test.go#L721) | +| A key logs in only once its person adds it with a passkey: their own for good, a browser's for twelve hours | [`PasskeyService/BeginPasskeyCeremony`](/reference/api/passkeyservice/) | [`TestOnlyTheOwnerAndTheirGuestsLogInToAWorkspace`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/login_test.go#L175) | +| Guests of a workspace, let in by its owner with a passkey | [`spin workspace guests`](/reference/cli/workspace/) | [`TestOnlyTheOwnerAndTheirGuestsLogInToAWorkspace`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/login_test.go#L175) | +| A workspace's identity, signed by its host, for the audiences its installation allows | [`TestAWorkspacesIdentityIsTheHostsSignatureOfItsSet`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/identity_test.go#L58), a test of `internal/e2e` | [`TestAWorkspacesIdentityIsTheHostsSignatureOfItsSet`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/identity_test.go#L58) | +| VS Code over SSH, with the server the installation publishes and nothing downloaded
*The server is Microsoft's, for Remote-SSH; spin code also opens an editor with Open Remote - SSH, which downloads its own. spin code itself is run by its unit tests only: it opens a desktop editor, which no lane has.* | [`TestAVSCodeServerOfAnotherCommitIsHandedToTheRunningMachine`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/vscodehotplug_test.go#L23), a test of `internal/e2e` | [`TestTheCarriedVSCodeServerRunsOfflineAndAnswersOverTheSSHTunnel`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/vscodeserver_test.go#L86)
[`TestAVSCodeServerOfAnotherCommitIsHandedToTheRunningMachine`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/vscodehotplug_test.go#L23) | +| Run a command in a workspace, copy files to and from it | [`spin exec`](/reference/cli/exec/) | [`TestE2E_ADetachedRunIsFollowedToItsEndAndFilesGoBothWays`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/journeys_e2e_test.go#L307) | +| A program runs a command and reads and writes files in a workspace through the API, with a key that holds workspace:exec, every call recorded with the key it came on | [`ExecService/Exec`](/reference/api/execservice/) | [`TestAKeyWithExecRunsACommandInAWorkspaceAndOneWithoutIsRefused`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/exec_test.go#L36) | +| An agent works in workspaces through `spin mcp` on a key delegated to it: never more than the key it came from - scopes, team, projects, end, how many workspaces and cores its tree holds - and revoked with it | [`spin mcp`](/reference/cli/mcp/) | [`TestE2E_AnAgentDrivesAWorkspaceThroughMCPOnADelegatedKey`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/mcp_e2e_test.go#L62) | +| An agent in a workspace drives others with spin, on a key it gets for the workspace's own SPIFFE identity - a child of the key that made the workspace, through its host, whatever the workspace's network
*No forge in the lane: a workspace reaches no private or host address, and no test repository has a credential in CI yet, so an agent opening a pull request is not run.* | [`AuthService/ExchangeWorkloadToken`](/reference/api/authservice/) | [`TestAnAgentInAWorkspaceDrivesAnotherOnTheIdentityOfItsWorkspace`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/inception_test.go#L97) | ### Administration | Feature | Exists | End to end | |---|---|---| -| Installation settings seeded from a file; a change in the file is a proposal to apply or dismiss | [`AdminService/DecideConfigChange`](/reference/api/adminservice/) | [`TestTheInstallationFileSeedsAndItsChangesAreAnAdministratorsToDecide`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/config_file_test.go#L92) | -| Resource presets | [`AdminService/CreateResourcePreset`](/reference/api/adminservice/) | [`admin.spec.ts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/dashboard/e2e/admin.spec.ts#L444): an admin's preset sizes a person's workspace, and is gone once deleted | -| Registration: open, by allowlist, or closed | [`AdminService/SetRegistrationMode`](/reference/api/adminservice/) | [`admin.spec.ts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/dashboard/e2e/admin.spec.ts#L240): closed, open and a domain on the allowlist decide who registers
[`admin.spec.ts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/dashboard/e2e/admin.spec.ts#L173): the allowlist lets in who it names, and nobody else | -| An audit log | [`AdminService/ListAuditLog`](/reference/api/adminservice/) | [`TestE2E_AnAdministratorsActionIsAuditedWithItsActorAndTarget`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/e2e_test.go#L609)
[`admin.spec.ts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/dashboard/e2e/admin.spec.ts#L972): admin reads the log and can narrow it to one kind of event | -| The control plane's jobs, and running one now | [`spin admin jobs`](/reference/cli/admin/) | [`TestE2E_Admin`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/e2e_test.go#L1075)
[`admin.spec.ts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/dashboard/e2e/admin.spec.ts#L740): admin runs a job by hand and sees how it ended | +| Installation settings seeded from a file; a change in the file is a proposal to apply or dismiss | [`AdminService/DecideConfigChange`](/reference/api/adminservice/) | [`TestTheInstallationFileSeedsAndItsChangesAreAnAdministratorsToDecide`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/config_file_test.go#L92) | +| Every installation setting read and changed from the terminal, by the definitions the dashboard and the file use | [`spin admin settings set`](/reference/cli/admin/) | not yet: the RPC's round trip of every definition is tested against a real database; no lane runs the command against a stack yet | +| Resource presets | [`AdminService/CreateResourcePreset`](/reference/api/adminservice/) | [`admin.spec.ts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/dashboard/e2e/admin.spec.ts#L438): an admin's preset sizes a person's workspace, and is gone once deleted | +| Registration: open, by allowlist, or closed | [`AdminService/SetSettings`](/reference/api/adminservice/) | [`admin.spec.ts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/dashboard/e2e/admin.spec.ts#L244): closed, open and a domain on the allowlist decide who registers
[`admin.spec.ts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/dashboard/e2e/admin.spec.ts#L177): the allowlist lets in who it names, and nobody else | +| An audit log | [`AdminService/ListAuditLog`](/reference/api/adminservice/) | [`TestE2E_AnAdministratorsActionIsAuditedWithItsActorAndTarget`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/e2e_test.go#L611)
[`admin.spec.ts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/dashboard/e2e/admin.spec.ts#L959): admin reads the log and can narrow it to one kind of event | +| A timeline: what happened to a workspace, a runner, a team, a project or the installation, by whom, in one read | [`AdminService/ListTimeline`](/reference/api/adminservice/) | not yet: no lane reads it yet: its reading is held against a real database by internal/controlplane/domain/timeline's tests, and a host's loss and return by hostserver's over a real stream | +| The control plane's jobs, and running one now | [`spin admin jobs`](/reference/cli/admin/) | [`TestE2E_Admin`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/e2e_test.go#L1197)
[`admin.spec.ts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/dashboard/e2e/admin.spec.ts#L728): admin runs a job by hand and sees how it ended | | The month's bill, its forecast, and what each workspace cost | [`spin admin costs`](/reference/cli/admin/) | not yet: the cloud's real bill read: no lane has an AWS account, so the bill a test gives the reader stands in for it | -| The store: every volume, whose it is, and taking out what nothing needs | [`spin admin storage list`](/reference/cli/admin/) | [`TestAVolumeNothingNeedsIsTakenOutOfTheStore`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/orphan_test.go#L26) | -| Re-key a workspace's disk | [`spin admin volume rekey`](/reference/cli/admin/) | [`TestARekeyedDiskBootsWithWhatItHeldUnderANewKey`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/rekey_test.go#L24) | -| Runners: registration tokens, drain, activate, revoke, and a policy per host | [`spin admin runner drain`](/reference/cli/admin/) | [`TestARunnerRegisteredWithATokenTheAPIMadeIsRevokedByTheAdmin`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/runner_token_test.go#L99)
[`TestARegistrationTokenExpiredOrRevokedRegistersNothing`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/runner_token_test.go#L148) | +| The store: every volume, whose it is, and taking out what nothing needs | [`spin admin storage list`](/reference/cli/admin/) | [`TestAVolumeNothingNeedsIsTakenOutOfTheStore`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/orphan_test.go#L26) | +| Re-key a workspace's disk | [`spin admin volume rekey`](/reference/cli/admin/) | [`TestARekeyedDiskBootsWithWhatItHeldUnderANewKey`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/rekey_test.go#L24) | +| An administrator stops a workspace that is not theirs, moves it off a lost host with a reason its owner reads on its history, reads where it sends, and lists the disks hosts refuse: each audited | [`spin admin workspace recover`](/reference/cli/admin/) | not yet: no lane asks these as an administrator of a real runner: each runs what its owner's stop, recover and egress run, which the lanes cover, and who may ask, the audit entry and what the owner's history says are tested at the RPC against the database (workspaceserver's adminacts tests) | +| Runners: registration tokens, drain, activate, revoke, and a policy per host | [`spin admin runner drain`](/reference/cli/admin/) | [`TestARunnerRegisteredWithATokenTheAPIMadeIsRevokedByTheAdmin`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/runner_token_test.go#L99)
[`TestARegistrationTokenExpiredOrRevokedRegistersNothing`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/runner_token_test.go#L148) | | Runners start when a workspace waits for one and stop when nothing runs | [`HostService/GetFleet`](/reference/api/hostservice/) | not yet: an autoscaling group to start and stop: the one group is AWS's, and no lane has an account | -| A root shell on a runner, for a while and with a reason: the runner emptied first, every session recorded under Object Lock, the runner retired after | [`spin admin shell open`](/reference/cli/admin/) | [`TestHostsARootShellOnAHostIsRecordedAndItsHostRetired`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/hosts_test.go#L420) | -| A host that reboots brings its workspaces back | [`TestAHostRebootBringsItsWorkspacesBack`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/restart_test.go#L38), a test of `internal/e2e` | [`TestAHostRebootBringsItsWorkspacesBack`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/restart_test.go#L38) | -| A cloud's reclaim warning empties the host before the machine goes | [`TestACloudsReclaimWarningEmptiesTheHostBeforeAnySignal`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/preemption_test.go#L26), a test of `internal/e2e` | [`TestACloudsReclaimWarningEmptiesTheHostBeforeAnySignal`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/preemption_test.go#L26) | -| A writeback bound per host, measured on that host before it is taken | [`TestCustomWritebackValuesAreMeasuredOnTheRunner`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/writeback_test.go#L28), a test of `internal/e2e` | [`TestCustomWritebackValuesAreMeasuredOnTheRunner`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/writeback_test.go#L28) | -| What is running where: the control plane, each runner and its machine | [`spin admin versions`](/reference/cli/admin/) | [`TestE2E_Admin`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/e2e_test.go#L1075) | +| A root shell on a runner, for a while and with a reason: the runner emptied first, every session recorded under Object Lock, the runner retired after | [`spin admin shell open`](/reference/cli/admin/) | [`TestHostsARootShellOnAHostIsRecordedAndItsHostRetired`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/hosts_test.go#L420) | +| A host that reboots brings its workspaces back | [`TestAHostRebootBringsItsWorkspacesBack`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/restart_test.go#L38), a test of `internal/e2e` | [`TestAHostRebootBringsItsWorkspacesBack`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/restart_test.go#L38) | +| A cloud's reclaim warning empties the host before the machine goes | [`TestACloudsReclaimWarningEmptiesTheHostBeforeAnySignal`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/preemption_test.go#L26), a test of `internal/e2e` | [`TestACloudsReclaimWarningEmptiesTheHostBeforeAnySignal`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/preemption_test.go#L26) | +| A writeback bound per host, measured on that host before it is taken | [`TestCustomWritebackValuesAreMeasuredOnTheRunner`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/writeback_test.go#L28), a test of `internal/e2e` | [`TestCustomWritebackValuesAreMeasuredOnTheRunner`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/writeback_test.go#L28) | +| What is running where: the control plane, each runner and its machine | [`spin admin versions`](/reference/cli/admin/) | [`TestE2E_Admin`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/e2e_test.go#L1197) | | A workspace whose host never comes back is moved when little would be lost, and its owner is told when it waits for them | [`WorkspaceService/RecoverWorkspace`](/reference/api/workspaceservice/) | not yet: the move without asking and the wait it records are tested against the database (workspaceserver's autorehome tests); the hosts lane recovers by hand, and no lane has an SMTP server to receive the owner's email | ### Observability | Feature | Exists | End to end | |---|---|---| +| A workspace's cost this month and its rate, as an estimate with its day, for its owner; a team's workspaces summed for its admins, and a project's with its prebuilds' storage for its admins
*A share of days already billed, never of this hour; nothing is said where the cloud sends no bill.* | [`WorkspaceService/GetWorkspaceCost`](/reference/api/workspaceservice/) | not yet: the cloud's real bill read: no lane has an AWS account, so the bill a test gives the reader stands in for it | | A workspace's owner is told by email when it waits for them or something happened to it, each event switchable
*Held after its host was lost, a stop that could not be taken, stopped for not responding, moved off a lost host. A disk almost full is not an event yet.* | [`SettingsService/UpdateNotificationPreferences`](/reference/api/settingsservice/) | not yet: no lane has an SMTP server: delivery is tested against a generated mail server, with every attempt and retry recorded (internal/controlplane/notify) | -| Platform logs, workspace logs and traces, searched in the product | [`LogService/SearchPlatformLogs`](/reference/api/logservice/) | [`TestAWorkspacesLinesAndTracesAreFoundBySearchingForIt`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/observe_test.go#L179)
[`TestE2E_TheInstallationsLogsAreSearchable`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/e2e_test.go#L1012) | -| Metrics, with Grafana on the control plane | [`AdminService/GetMonitoring`](/reference/api/adminservice/) | [`admin.spec.ts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/dashboard/e2e/admin.spec.ts#L1312): a series of the lane's host is in the metric store, read through Grafana
[`admin.spec.ts`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/dashboard/e2e/admin.spec.ts#L1281): admin reads the installation's dashboards without leaving the page | -| A workspace's journal and console are collected as the installation's policy says | [`spin workspace logs`](/reference/cli/workspace/) | [`TestE2E_AWorkspacesConsoleIsKeptAndSearchable`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/e2e_test.go#L1033) | -| A workspace's last hour of CPU, memory and network against what it holds, for its owner
*Kept on the host, so it starts again with a restart of it or a move; the disk's use is not sampled.* | [`WorkspaceService/GetWorkspaceUsage`](/reference/api/workspaceservice/) | [`TestAWorkspacesUsageIsWhatItsHostSampled`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/host_report_test.go#L98) | +| Platform logs, workspace logs and traces, searched in the product | [`LogService/SearchPlatformLogs`](/reference/api/logservice/) | [`TestAWorkspacesLinesAndTracesAreFoundBySearchingForIt`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/observe_test.go#L190)
[`TestE2E_TheInstallationsLogsAreSearchable`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/e2e_test.go#L1134) | +| Metrics, with Grafana on the control plane | [`AdminService/GetMonitoring`](/reference/api/adminservice/) | [`admin.spec.ts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/dashboard/e2e/admin.spec.ts#L1309): a series of the lane's host is in the metric store, read through Grafana
[`admin.spec.ts`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/dashboard/e2e/admin.spec.ts#L1278): admin reads the installation's dashboards without leaving the page | +| A workspace's journal and console are collected as the installation's policy says | [`spin workspace logs`](/reference/cli/workspace/) | [`TestE2E_AWorkspacesConsoleIsKeptAndSearchable`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/e2e_test.go#L1155) | +| A workspace's last hour of CPU, memory and network against what it holds, for its owner
*Kept on the host, so it starts again with a restart of it or a move; the disk's use is not sampled.* | [`WorkspaceService/GetWorkspaceUsage`](/reference/api/workspaceservice/) | [`TestAWorkspacesUsageIsWhatItsHostSampled`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/host_report_test.go#L99) | ### Platform | Feature | Exists | End to end | |---|---|---| -| A smoke test of what an installation's API promises, with a workspace of its own | [`spin smoke`](/reference/cli/smoke/) | [`TestE2E_SmokePassesAndLeavesNothingBehind`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/cmd/cli/journeys_e2e_test.go#L437) | -| A host serves only the releases it carries
*A resume whose recorded release was collected since has no test against the stack.* | [`TestAMachineAdoptedWithoutItsReleasesIsSuspendedWithItsDisk`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/suspend_test.go#L126), a test of `internal/e2e` | [`TestAMachineAdoptedWithoutItsReleasesIsSuspendedWithItsDisk`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/suspend_test.go#L126)
[`TestAVSCodeServerOfAnotherCommitIsHandedToTheRunningMachine`](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/internal/e2e/vscodehotplug_test.go#L23) | +| A smoke test of what an installation's API promises, with a workspace of its own | [`spin smoke`](/reference/cli/smoke/) | [`TestE2E_SmokePassesAndLeavesNothingBehind`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/cmd/cli/journeys_e2e_test.go#L438) | +| A host serves only the releases it carries
*A resume whose recorded release was collected since has no test against the stack.* | [`TestAMachineAdoptedWithoutItsReleasesIsSuspendedWithItsDisk`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/suspend_test.go#L126), a test of `internal/e2e` | [`TestAMachineAdoptedWithoutItsReleasesIsSuspendedWithItsDisk`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/suspend_test.go#L126)
[`TestAVSCodeServerOfAnotherCommitIsHandedToTheRunningMachine`](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/internal/e2e/vscodehotplug_test.go#L23) | ## Partly there @@ -161,9 +166,9 @@ Not planned: a limit of the platform or of where it runs today. [Limitations](/o - **AWS only** (Platform): The Terraform module is the one supported install; nothing else is packaged or tested. - **x86-64 only** (Platform): Runners are x86-64 machines with nested virtualization. -- **The CLI runs on Linux x86-64 and macOS Apple silicon** (Platform) +- **The CLI runs on Linux and macOS** (Platform): x86-64 and Arm of each; there is no Windows build. - **One region, one control plane** (Platform): A machine that fails is replaced in minutes, not seconds. -- **No GPUs** (Workspaces): There is no way to ask for a runner of a particular kind. +- **No GPUs** (Workspaces): A preset names the class of runner its workspaces run on, and no class hands a workspace a GPU. - **Linux guests only** (Workspaces): Booted with the kernel spin provides. - **No IPv6 inside a workspace** (Network) - **TCP only for published ports** (Network) diff --git a/src/content/docs/use/access.md b/src/content/docs/use/access.md index 9f3faee..c712d1f 100644 --- a/src/content/docs/use/access.md +++ b/src/content/docs/use/access.md @@ -16,7 +16,7 @@ the audit log. Give it `keys:delegate` and it makes keys of its own for the agen (`spin mcp` serves them the API): each holds no more than it does - its scopes, team, projects, end, and how many workspaces and cores all of them hold - and goes when you revoke it. Why, and what it trades, is -[ADR-0031](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/docs/decisions/ADR-0031-a-passkey-buys-a-key-the-control-plane-certifies.md). +[ADR-0031](https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/docs/decisions/ADR-0031-a-passkey-buys-a-key-the-control-plane-certifies.md). The control plane decides who logs in, at every session: it certifies a key of yours, for five minutes, into a workspace you own or are a guest of. It also holds what it needs to serve you: your diff --git a/src/content/docs/use/dashboard.md b/src/content/docs/use/dashboard.md index 7d4943e..b887ea1 100644 --- a/src/content/docs/use/dashboard.md +++ b/src/content/docs/use/dashboard.md @@ -7,7 +7,7 @@ editUrl: false -The dashboard is at `https://app.`. These screenshots are of spin v20261110.01, taken by spin's dashboard suite on its end-to-end stack - real workspaces on a real runner - each by a test that first checks the screen shows what its title says. Everything here is also in the [CLI](/reference/cli/) and the [API](/reference/api/). +The dashboard is at `https://app.`. These screenshots are of spin v20261113.01, taken by spin's dashboard suite on its end-to-end stack - real workspaces on a real runner - each by a test that first checks the screen shows what its title says. Everything here is also in the [CLI](/reference/cli/) and the [API](/reference/api/). ## A person's workspaces diff --git a/src/data/features.json b/src/data/features.json index 32fab04..1c17a72 100644 --- a/src/data/features.json +++ b/src/data/features.json @@ -34,10 +34,10 @@ "area": "Workspaces", "name": "Idle suspend, with a question before it that a keep answers", "state": "built", - "proof": "e2e:TestAWorkspaceIsAskedBeforeItsSuspensionAndAKeepAnswersIt", + "proof": "e2e:TestAWorkspaceNobodyUsesIsSuspendedUnlessKeptOrHeld", "note": "", "endToEnd": [ - "go:internal/e2e.TestAWorkspaceIsAskedBeforeItsSuspensionAndAKeepAnswersIt" + "go:internal/e2e.TestAWorkspaceNobodyUsesIsSuspendedUnlessKeptOrHeld" ] }, { @@ -54,21 +54,21 @@ "area": "Workspaces", "name": "A process inside holds its workspace awake while it lives", "state": "built", - "proof": "e2e:TestAProcessHoldsItsWorkspaceAwakeWhileItLives", + "proof": "e2e:TestAWorkspaceNobodyUsesIsSuspendedUnlessKeptOrHeld", "note": "", "endToEnd": [ - "go:internal/e2e.TestAProcessHoldsItsWorkspaceAwakeWhileItLives" + "go:internal/e2e.TestAWorkspaceNobodyUsesIsSuspendedUnlessKeptOrHeld" ] }, { "area": "Workspaces", "name": "Suspend with the processes where they are; a start resumes them", "state": "built", - "proof": "e2e:TestAWorkspaceNobodyUsesIsSuspendedAndAStartResumesIt", + "proof": "e2e:TestAWorkspaceNobodyUsesIsSuspendedUnlessKeptOrHeld", "note": "", "endToEnd": [ "go:cmd/cli.TestE2E_ASuspendedWorkspaceResumesWhereItWas", - "go:internal/e2e.TestAWorkspaceNobodyUsesIsSuspendedAndAStartResumesIt" + "go:internal/e2e.TestAWorkspaceNobodyUsesIsSuspendedUnlessKeptOrHeld" ] }, { @@ -79,7 +79,8 @@ "note": "A loan refused while the host is full has no test against the stack: the budget is the host's own cores and half its memory, which no lane's workspaces fill.", "endToEnd": [ "go:internal/e2e.TestABusyWorkspaceIsLentCoresAndGivesThemBack", - "go:internal/e2e.TestABusyWorkspaceIsLentMemoryAndGivesItBack" + "go:internal/e2e.TestABusyWorkspaceIsLentMemoryAndGivesItBack", + "go:internal/e2e.TestAnEditorAtTheFloorIsNotKilledForMemory" ] }, { @@ -492,7 +493,7 @@ }, { "area": "Access", - "name": "A workspace's identity, signed by its host, for the audiences its owner allows", + "name": "A workspace's identity, signed by its host, for the audiences its installation allows", "state": "built", "proof": "e2e:TestAWorkspacesIdentityIsTheHostsSignatureOfItsSet", "note": "", @@ -573,6 +574,14 @@ "go:internal/e2e.TestTheAgentsThreadsAreListed" ] }, + { + "area": "Workspaces", + "name": "Chat mode: the dashboard flips to the person's own chats across their workspaces, grouped by project, with the agent full height and a new chat that makes its workspace", + "state": "built", + "proof": "rpc:spin.v1.WorkspaceService/ListOwnAgentThreads", + "note": "", + "endToEndGap": "The RPC is held to the caller's own chats by its unit test, the mode by the dashboard's; no lane opens chat mode in a browser against an agent that has reported." + }, { "area": "Workspaces", "name": "The agent's home is a volume of its own: the chats and sessions outlive the workspace, kept in the installation's store as every disk is, and a new workspace mounts them at its creation", @@ -717,6 +726,14 @@ "go:internal/e2e.TestTheInstallationFileSeedsAndItsChangesAreAnAdministratorsToDecide" ] }, + { + "area": "Administration", + "name": "Every installation setting read and changed from the terminal, by the definitions the dashboard and the file use", + "state": "built", + "proof": "cli:admin settings set", + "note": "", + "endToEndGap": "the RPC's round trip of every definition is tested against a real database; no lane runs the command against a stack yet" + }, { "area": "Administration", "name": "Resource presets", @@ -731,7 +748,7 @@ "area": "Administration", "name": "Registration: open, by allowlist, or closed", "state": "built", - "proof": "rpc:spin.v1.AdminService/SetRegistrationMode", + "proof": "rpc:spin.v1.AdminService/SetSettings", "note": "", "endToEnd": [ "pw:admin.spec.ts:closed, open and a domain on the allowlist decide who registers", @@ -749,6 +766,14 @@ "pw:admin.spec.ts:admin reads the log and can narrow it to one kind of event" ] }, + { + "area": "Administration", + "name": "A timeline: what happened to a workspace, a runner, a team, a project or the installation, by whom, in one read", + "state": "built", + "proof": "rpc:spin.v1.AdminService/ListTimeline", + "note": "", + "endToEndGap": "no lane reads it yet: its reading is held against a real database by internal/controlplane/domain/timeline's tests, and a host's loss and return by hostserver's over a real stream" + }, { "area": "Administration", "name": "The control plane's jobs, and running one now", @@ -768,6 +793,14 @@ "note": "", "endToEndGap": "the cloud's real bill read: no lane has an AWS account, so the bill a test gives the reader stands in for it" }, + { + "area": "Observability", + "name": "A workspace's cost this month and its rate, as an estimate with its day, for its owner; a team's workspaces summed for its admins, and a project's with its prebuilds' storage for its admins", + "state": "built", + "proof": "rpc:spin.v1.WorkspaceService/GetWorkspaceCost", + "note": "A share of days already billed, never of this hour; nothing is said where the cloud sends no bill.", + "endToEndGap": "the cloud's real bill read: no lane has an AWS account, so the bill a test gives the reader stands in for it" + }, { "area": "Administration", "name": "The store: every volume, whose it is, and taking out what nothing needs", @@ -788,6 +821,14 @@ "go:internal/e2e.TestARekeyedDiskBootsWithWhatItHeldUnderANewKey" ] }, + { + "area": "Administration", + "name": "An administrator stops a workspace that is not theirs, moves it off a lost host with a reason its owner reads on its history, reads where it sends, and lists the disks hosts refuse: each audited", + "state": "built", + "proof": "cli:admin workspace recover", + "note": "", + "endToEndGap": "no lane asks these as an administrator of a real runner: each runs what its owner's stop, recover and egress run, which the lanes cover, and who may ask, the audit entry and what the owner's history says are tested at the RPC against the database (workspaceserver's adminacts tests)" + }, { "area": "Administration", "name": "Runners: registration tokens, drain, activate, revoke, and a policy per host", @@ -952,10 +993,10 @@ }, { "area": "Platform", - "name": "The CLI runs on Linux x86-64 and macOS Apple silicon", + "name": "The CLI runs on Linux and macOS", "state": "limit", "proof": "", - "note": "" + "note": "x86-64 and Arm of each; there is no Windows build." }, { "area": "Platform", @@ -969,7 +1010,7 @@ "name": "No GPUs", "state": "limit", "proof": "", - "note": "There is no way to ask for a runner of a particular kind." + "note": "A preset names the class of runner its workspaces run on, and no class hands a workspace a GPU." }, { "area": "Workspaces", diff --git a/src/data/figures.json b/src/data/figures.json index 627c827..600d034 100644 --- a/src/data/figures.json +++ b/src/data/figures.json @@ -1,6 +1,6 @@ { "datapath": { - "source": "https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/docs/network/datapath", + "source": "https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/docs/network/datapath", "width": 552, "words": [ "How a packet leaves a workspace", @@ -56,7 +56,7 @@ ] }, "egress-policy": { - "source": "https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/docs/network/egress-policy", + "source": "https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/docs/network/egress-policy", "width": 923, "words": [ "What the forward chain decides, in order", @@ -173,7 +173,7 @@ ] }, "isolation": { - "source": "https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/docs/network/isolation", + "source": "https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/docs/network/isolation", "width": 499, "words": [ "Same address, different segment", @@ -220,7 +220,7 @@ ] }, "traffic": { - "source": "https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/docs/security/traffic", + "source": "https://github.com/spin-stack/spin/blob/911f516bc89ae266c013681247d72c40990fe62c/docs/security/traffic", "width": 1889, "words": [ "Traffic: every arrow is a connection opened in its direction, and nothing else is let in", diff --git a/src/data/pricing.json b/src/data/pricing.json index 196e10f..856f3d7 100644 --- a/src/data/pricing.json +++ b/src/data/pricing.json @@ -1,6 +1,6 @@ { - "generated": "2026-11-13", - "published": "2026-11-10T17:38:52Z", + "generated": "2026-11-14", + "published": "2026-11-14T01:29:26Z", "source": "https://b0.p.awsstatic.com/pricing/2.0/meteredUnitMaps/ec2/USD/current/ec2-ondemand-without-sec-sel/\u003cregion\u003e/Linux/index.json", "machines": { "controlPlane": "t8i.medium", diff --git a/src/data/reference.json b/src/data/reference.json index 993e8f7..4a7053f 100644 --- a/src/data/reference.json +++ b/src/data/reference.json @@ -1,8 +1,8 @@ { "spin": { "installs": "v20261027.01", - "commit": "b7ba5206f12ba93a829a48e354be7fce6bc65db4", - "tag": "v20261110.01", + "commit": "911f516bc89ae266c013681247d72c40990fe62c", + "tag": "v20261113.01", "machine": "v20261026.01" }, "terraform": { @@ -13,12 +13,12 @@ "commit": "e5d547cff92ba84137e7d3af0eae5eee04c63cd8" }, "counts": { - "built": 91, + "built": 96, "partial": 0, "notBuilt": 2, "limits": 17, "endToEnd": 83, - "gap": 8 + "gap": 13 }, - "openapiSha256": "df426012d8424746aed6a141797c96a4e0495082d4dad613dac78bad6b738929" + "openapiSha256": "bb8efbad5b1f1de3ae3301b78c9c50d62d65a987dd05dc12594bc1e7ad2cf0a9" } diff --git a/src/data/shots.json b/src/data/shots.json index 61a6918..e919a0b 100644 --- a/src/data/shots.json +++ b/src/data/shots.json @@ -1,6 +1,6 @@ { - "release": "v20261110.01", - "commit": "b7ba5206f12ba93a829a48e354be7fce6bc65db4", + "release": "v20261113.01", + "commit": "911f516bc89ae266c013681247d72c40990fe62c", "shots": [ { "name": "workspaces", diff --git a/versions.yaml b/versions.yaml index 9c4ca6e..0413d60 100644 --- a/versions.yaml +++ b/versions.yaml @@ -7,8 +7,8 @@ - name: spin kind: git source: https://github.com/spin-stack/spin - version: v20261110.01 - pin: b7ba5206f12ba93a829a48e354be7fce6bc65db4 + version: v20261113.01 + pin: 911f516bc89ae266c013681247d72c40990fe62c track: github-release note: >- The release the site documents (D2: the newest, exactly). The daily sync moves it to the next