diff --git a/public/openapi.json b/public/openapi.json index bbf1da6..39bf23d 100644 --- a/public/openapi.json +++ b/public/openapi.json @@ -6,6 +6,68 @@ "version": "v1" }, "paths": { + "/spin.v1.AdminService/AcceptThirdPartyTerms": { + "post": { + "tags": [ + "AdminService" + ], + "summary": "AcceptThirdPartyTerms", + "description": "Accept the terms, as the version shown, for the items named: this installation then\n downloads them - the releases this control plane pins at once, and the newest daily.", + "operationId": "spin.v1.AdminService.AcceptThirdPartyTerms", + "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.AcceptThirdPartyTermsRequest" + } + } + }, + "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.AcceptThirdPartyTermsResponse" + } + } + } + } + } + } + }, "/spin.v1.AdminService/AddAllowedEmail": { "post": { "tags": [ @@ -747,6 +809,68 @@ } } }, + "/spin.v1.AdminService/GetEmailSettings": { + "post": { + "tags": [ + "AdminService" + ], + "summary": "GetEmailSettings", + "description": "The SMTP server the installation tells people through. The password is never read back.", + "operationId": "spin.v1.AdminService.GetEmailSettings", + "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.GetEmailSettingsRequest" + } + } + }, + "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.GetEmailSettingsResponse" + } + } + } + } + } + } + }, "/spin.v1.AdminService/GetFleetVersions": { "post": { "tags": [ @@ -1119,14 +1243,14 @@ } } }, - "/spin.v1.AdminService/GetSecuritySettings": { + "/spin.v1.AdminService/GetRunbook": { "post": { "tags": [ "AdminService" ], - "summary": "GetSecuritySettings", - "description": "Get security settings", - "operationId": "spin.v1.AdminService.GetSecuritySettings", + "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 +1275,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetSecuritySettingsRequest" + "$ref": "#/components/schemas/spin.v1.GetRunbookRequest" } } }, @@ -1173,7 +1297,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetSecuritySettingsResponse" + "$ref": "#/components/schemas/spin.v1.GetRunbookResponse" } } } @@ -1181,14 +1305,14 @@ } } }, - "/spin.v1.AdminService/GetStorageSettings": { + "/spin.v1.AdminService/GetSecuritySettings": { "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": "GetSecuritySettings", + "description": "Get security settings", + "operationId": "spin.v1.AdminService.GetSecuritySettings", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1213,7 +1337,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetStorageSettingsRequest" + "$ref": "#/components/schemas/spin.v1.GetSecuritySettingsRequest" } } }, @@ -1235,7 +1359,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetStorageSettingsResponse" + "$ref": "#/components/schemas/spin.v1.GetSecuritySettingsResponse" } } } @@ -1243,14 +1367,14 @@ } } }, - "/spin.v1.AdminService/GetStorageUsage": { + "/spin.v1.AdminService/GetStorageSettings": { "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": "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 +1399,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetStorageUsageRequest" + "$ref": "#/components/schemas/spin.v1.GetStorageSettingsRequest" } } }, @@ -1297,7 +1421,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetStorageUsageResponse" + "$ref": "#/components/schemas/spin.v1.GetStorageSettingsResponse" } } } @@ -1305,14 +1429,14 @@ } } }, - "/spin.v1.AdminService/GetTelemetryStatus": { + "/spin.v1.AdminService/GetStorageUsage": { "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": "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 +1461,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetTelemetryStatusRequest" + "$ref": "#/components/schemas/spin.v1.GetStorageUsageRequest" } } }, @@ -1359,7 +1483,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetTelemetryStatusResponse" + "$ref": "#/components/schemas/spin.v1.GetStorageUsageResponse" } } } @@ -1367,14 +1491,14 @@ } } }, - "/spin.v1.AdminService/GetVSCodeServers": { + "/spin.v1.AdminService/GetTelemetryStatus": { "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": "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 +1523,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetVSCodeServersRequest" + "$ref": "#/components/schemas/spin.v1.GetTelemetryStatusRequest" } } }, @@ -1421,7 +1545,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetVSCodeServersResponse" + "$ref": "#/components/schemas/spin.v1.GetTelemetryStatusResponse" } } } @@ -1429,14 +1553,14 @@ } } }, - "/spin.v1.AdminService/ListAllowedEmails": { + "/spin.v1.AdminService/GetThirdPartyTerms": { "post": { "tags": [ "AdminService" ], - "summary": "ListAllowedEmails", - "description": "List allowed emails/domains", - "operationId": "spin.v1.AdminService.ListAllowedEmails", + "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 +1585,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListAllowedEmailsRequest" + "$ref": "#/components/schemas/spin.v1.GetThirdPartyTermsRequest" } } }, @@ -1483,7 +1607,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListAllowedEmailsResponse" + "$ref": "#/components/schemas/spin.v1.GetThirdPartyTermsResponse" } } } @@ -1491,14 +1615,14 @@ } } }, - "/spin.v1.AdminService/ListAuditLog": { + "/spin.v1.AdminService/GetVSCodeServers": { "post": { "tags": [ "AdminService" ], - "summary": "ListAuditLog", - "description": "Read the audit log, newest first. There is no RPC that writes one: an entry is written\n by the operation it records, so a log an API could add to would be one an API could\n forge.", - "operationId": "spin.v1.AdminService.ListAuditLog", + "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", @@ -1523,7 +1647,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListAuditLogRequest" + "$ref": "#/components/schemas/spin.v1.GetVSCodeServersRequest" } } }, @@ -1545,7 +1669,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListAuditLogResponse" + "$ref": "#/components/schemas/spin.v1.GetVSCodeServersResponse" } } } @@ -1553,14 +1677,14 @@ } } }, - "/spin.v1.AdminService/ListConfigChanges": { + "/spin.v1.AdminService/GetWorkspaceNames": { "post": { "tags": [ "AdminService" ], - "summary": "ListConfigChanges", - "description": "What the config file says now and the installation does not, for an administrator to\n decide: the file seeds an installation once, and after that its changes are proposals.", - "operationId": "spin.v1.AdminService.ListConfigChanges", + "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", @@ -1585,7 +1709,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListConfigChangesRequest" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceNamesRequest" } } }, @@ -1607,7 +1731,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListConfigChangesResponse" + "$ref": "#/components/schemas/spin.v1.GetWorkspaceNamesResponse" } } } @@ -1615,13 +1739,14 @@ } } }, - "/spin.v1.AdminService/ListHostClasses": { + "/spin.v1.AdminService/ListAllowedEmails": { "post": { "tags": [ "AdminService" ], - "summary": "ListHostClasses", - "operationId": "spin.v1.AdminService.ListHostClasses", + "summary": "ListAllowedEmails", + "description": "List allowed emails/domains", + "operationId": "spin.v1.AdminService.ListAllowedEmails", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1646,7 +1771,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListHostClassesRequest" + "$ref": "#/components/schemas/spin.v1.ListAllowedEmailsRequest" } } }, @@ -1668,7 +1793,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListHostClassesResponse" + "$ref": "#/components/schemas/spin.v1.ListAllowedEmailsResponse" } } } @@ -1676,14 +1801,14 @@ } } }, - "/spin.v1.AdminService/ListJobRuns": { + "/spin.v1.AdminService/ListAuditLog": { "post": { "tags": [ "AdminService" ], - "summary": "ListJobRuns", - "description": "One job's runs, newest first.", - "operationId": "spin.v1.AdminService.ListJobRuns", + "summary": "ListAuditLog", + "description": "Read the audit log, newest first. There is no RPC that writes one: an entry is written\n by the operation it records, so a log an API could add to would be one an API could\n forge.", + "operationId": "spin.v1.AdminService.ListAuditLog", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1708,7 +1833,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListJobRunsRequest" + "$ref": "#/components/schemas/spin.v1.ListAuditLogRequest" } } }, @@ -1730,7 +1855,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListJobRunsResponse" + "$ref": "#/components/schemas/spin.v1.ListAuditLogResponse" } } } @@ -1738,14 +1863,14 @@ } } }, - "/spin.v1.AdminService/ListJobs": { + "/spin.v1.AdminService/ListConfigChanges": { "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": "ListConfigChanges", + "description": "What the config file says now and the installation does not, for an administrator to\n decide: the file seeds an installation once, and after that its changes are proposals.", + "operationId": "spin.v1.AdminService.ListConfigChanges", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1770,7 +1895,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListJobsRequest" + "$ref": "#/components/schemas/spin.v1.ListConfigChangesRequest" } } }, @@ -1792,7 +1917,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListJobsResponse" + "$ref": "#/components/schemas/spin.v1.ListConfigChangesResponse" } } } @@ -1800,14 +1925,13 @@ } } }, - "/spin.v1.AdminService/ListRekeys": { + "/spin.v1.AdminService/ListHostClasses": { "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": "ListHostClasses", + "operationId": "spin.v1.AdminService.ListHostClasses", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1832,7 +1956,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListRekeysRequest" + "$ref": "#/components/schemas/spin.v1.ListHostClassesRequest" } } }, @@ -1854,7 +1978,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListRekeysResponse" + "$ref": "#/components/schemas/spin.v1.ListHostClassesResponse" } } } @@ -1862,14 +1986,14 @@ } } }, - "/spin.v1.AdminService/ListResourcePresets": { + "/spin.v1.AdminService/ListJobRuns": { "post": { "tags": [ "AdminService" ], - "summary": "ListResourcePresets", - "description": "List resource presets", - "operationId": "spin.v1.AdminService.ListResourcePresets", + "summary": "ListJobRuns", + "description": "One job's runs, newest first.", + "operationId": "spin.v1.AdminService.ListJobRuns", "parameters": [ { "name": "Connect-Protocol-Version", @@ -1894,7 +2018,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListResourcePresetsRequest" + "$ref": "#/components/schemas/spin.v1.ListJobRunsRequest" } } }, @@ -1916,7 +2040,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListResourcePresetsResponse" + "$ref": "#/components/schemas/spin.v1.ListJobRunsResponse" } } } @@ -1924,14 +2048,14 @@ } } }, - "/spin.v1.AdminService/ListUserAPIKeys": { + "/spin.v1.AdminService/ListJobs": { "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": "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", @@ -1956,7 +2080,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListUserAPIKeysRequest" + "$ref": "#/components/schemas/spin.v1.ListJobsRequest" } } }, @@ -1978,7 +2102,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListUserAPIKeysResponse" + "$ref": "#/components/schemas/spin.v1.ListJobsResponse" } } } @@ -1986,14 +2110,14 @@ } } }, - "/spin.v1.AdminService/ListUsers": { + "/spin.v1.AdminService/ListRekeys": { "post": { "tags": [ "AdminService" ], - "summary": "ListUsers", - "description": "List all users", - "operationId": "spin.v1.AdminService.ListUsers", + "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", @@ -2018,7 +2142,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListUsersRequest" + "$ref": "#/components/schemas/spin.v1.ListRekeysRequest" } } }, @@ -2040,7 +2164,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListUsersResponse" + "$ref": "#/components/schemas/spin.v1.ListRekeysResponse" } } } @@ -2048,14 +2172,14 @@ } } }, - "/spin.v1.AdminService/PublishVSCodeServers": { + "/spin.v1.AdminService/ListResourcePresets": { "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": "ListResourcePresets", + "description": "List resource presets", + "operationId": "spin.v1.AdminService.ListResourcePresets", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2080,7 +2204,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.PublishVSCodeServersRequest" + "$ref": "#/components/schemas/spin.v1.ListResourcePresetsRequest" } } }, @@ -2102,7 +2226,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.PublishVSCodeServersResponse" + "$ref": "#/components/schemas/spin.v1.ListResourcePresetsResponse" } } } @@ -2110,14 +2234,14 @@ } } }, - "/spin.v1.AdminService/RekeyVolume": { + "/spin.v1.AdminService/ListRunbooks": { "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": "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", @@ -2142,7 +2266,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RekeyVolumeRequest" + "$ref": "#/components/schemas/spin.v1.ListRunbooksRequest" } } }, @@ -2164,7 +2288,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RekeyVolumeResponse" + "$ref": "#/components/schemas/spin.v1.ListRunbooksResponse" } } } @@ -2172,14 +2296,14 @@ } } }, - "/spin.v1.AdminService/RemoveAllowedEmail": { + "/spin.v1.AdminService/ListUserAPIKeys": { "post": { "tags": [ "AdminService" ], - "summary": "RemoveAllowedEmail", - "description": "Remove allowed email/domain", - "operationId": "spin.v1.AdminService.RemoveAllowedEmail", + "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", @@ -2204,7 +2328,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RemoveAllowedEmailRequest" + "$ref": "#/components/schemas/spin.v1.ListUserAPIKeysRequest" } } }, @@ -2226,7 +2350,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RemoveAllowedEmailResponse" + "$ref": "#/components/schemas/spin.v1.ListUserAPIKeysResponse" } } } @@ -2234,14 +2358,14 @@ } } }, - "/spin.v1.AdminService/RemoveStoredVolume": { + "/spin.v1.AdminService/ListUsers": { "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": "ListUsers", + "description": "List all users", + "operationId": "spin.v1.AdminService.ListUsers", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2266,7 +2390,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RemoveStoredVolumeRequest" + "$ref": "#/components/schemas/spin.v1.ListUsersRequest" } } }, @@ -2288,7 +2412,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RemoveStoredVolumeResponse" + "$ref": "#/components/schemas/spin.v1.ListUsersResponse" } } } @@ -2296,14 +2420,14 @@ } } }, - "/spin.v1.AdminService/RetryPlatformImages": { + "/spin.v1.AdminService/PublishVSCodeServers": { "post": { "tags": [ "AdminService" ], - "summary": "RetryPlatformImages", - "description": "Look again now rather than when the next retry is due.", - "operationId": "spin.v1.AdminService.RetryPlatformImages", + "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", @@ -2328,7 +2452,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RetryPlatformImagesRequest" + "$ref": "#/components/schemas/spin.v1.PublishVSCodeServersRequest" } } }, @@ -2350,7 +2474,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RetryPlatformImagesResponse" + "$ref": "#/components/schemas/spin.v1.PublishVSCodeServersResponse" } } } @@ -2358,14 +2482,14 @@ } } }, - "/spin.v1.AdminService/RevokeUserAPIKey": { + "/spin.v1.AdminService/RekeyVolume": { "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": "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", @@ -2390,7 +2514,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeUserAPIKeyRequest" + "$ref": "#/components/schemas/spin.v1.RekeyVolumeRequest" } } }, @@ -2412,7 +2536,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeUserAPIKeyResponse" + "$ref": "#/components/schemas/spin.v1.RekeyVolumeResponse" } } } @@ -2420,14 +2544,14 @@ } } }, - "/spin.v1.AdminService/RunJobNow": { + "/spin.v1.AdminService/RemoveAllowedEmail": { "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": "RemoveAllowedEmail", + "description": "Remove allowed email/domain", + "operationId": "spin.v1.AdminService.RemoveAllowedEmail", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2452,7 +2576,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RunJobNowRequest" + "$ref": "#/components/schemas/spin.v1.RemoveAllowedEmailRequest" } } }, @@ -2474,7 +2598,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RunJobNowResponse" + "$ref": "#/components/schemas/spin.v1.RemoveAllowedEmailResponse" } } } @@ -2482,14 +2606,14 @@ } } }, - "/spin.v1.AdminService/SetRegistrationMode": { + "/spin.v1.AdminService/RemoveStoredVolume": { "post": { "tags": [ "AdminService" ], - "summary": "SetRegistrationMode", - "description": "Set registration mode", - "operationId": "spin.v1.AdminService.SetRegistrationMode", + "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", @@ -2514,7 +2638,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SetRegistrationModeRequest" + "$ref": "#/components/schemas/spin.v1.RemoveStoredVolumeRequest" } } }, @@ -2536,7 +2660,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SetRegistrationModeResponse" + "$ref": "#/components/schemas/spin.v1.RemoveStoredVolumeResponse" } } } @@ -2544,14 +2668,14 @@ } } }, - "/spin.v1.AdminService/UntagImage": { + "/spin.v1.AdminService/RetryPlatformImages": { "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": "RetryPlatformImages", + "description": "Look again now rather than when the next retry is due.", + "operationId": "spin.v1.AdminService.RetryPlatformImages", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2576,7 +2700,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UntagImageRequest" + "$ref": "#/components/schemas/spin.v1.RetryPlatformImagesRequest" } } }, @@ -2598,7 +2722,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UntagImageResponse" + "$ref": "#/components/schemas/spin.v1.RetryPlatformImagesResponse" } } } @@ -2606,13 +2730,14 @@ } } }, - "/spin.v1.AdminService/UpdateHostClass": { + "/spin.v1.AdminService/RevokeThirdPartyTerms": { "post": { "tags": [ "AdminService" ], - "summary": "UpdateHostClass", - "operationId": "spin.v1.AdminService.UpdateHostClass", + "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", @@ -2637,7 +2762,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateHostClassRequest" + "$ref": "#/components/schemas/spin.v1.RevokeThirdPartyTermsRequest" } } }, @@ -2659,7 +2784,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateHostClassResponse" + "$ref": "#/components/schemas/spin.v1.RevokeThirdPartyTermsResponse" } } } @@ -2667,14 +2792,14 @@ } } }, - "/spin.v1.AdminService/UpdateInstallationSettings": { + "/spin.v1.AdminService/RevokeUserAPIKey": { "post": { "tags": [ "AdminService" ], - "summary": "UpdateInstallationSettings", - "description": "Update installation settings", - "operationId": "spin.v1.AdminService.UpdateInstallationSettings", + "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", @@ -2699,7 +2824,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateInstallationSettingsRequest" + "$ref": "#/components/schemas/spin.v1.RevokeUserAPIKeyRequest" } } }, @@ -2721,7 +2846,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateInstallationSettingsResponse" + "$ref": "#/components/schemas/spin.v1.RevokeUserAPIKeyResponse" } } } @@ -2729,13 +2854,14 @@ } } }, - "/spin.v1.AdminService/UpdateNetworkPolicy": { + "/spin.v1.AdminService/RunJobNow": { "post": { "tags": [ "AdminService" ], - "summary": "UpdateNetworkPolicy", - "operationId": "spin.v1.AdminService.UpdateNetworkPolicy", + "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", @@ -2760,7 +2886,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateNetworkPolicyRequest" + "$ref": "#/components/schemas/spin.v1.RunJobNowRequest" } } }, @@ -2782,7 +2908,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateNetworkPolicyResponse" + "$ref": "#/components/schemas/spin.v1.RunJobNowResponse" } } } @@ -2790,14 +2916,14 @@ } } }, - "/spin.v1.AdminService/UpdateResourcePreset": { + "/spin.v1.AdminService/SetRegistrationMode": { "post": { "tags": [ "AdminService" ], - "summary": "UpdateResourcePreset", - "description": "Update a resource preset", - "operationId": "spin.v1.AdminService.UpdateResourcePreset", + "summary": "SetRegistrationMode", + "description": "Set registration mode", + "operationId": "spin.v1.AdminService.SetRegistrationMode", "parameters": [ { "name": "Connect-Protocol-Version", @@ -2822,7 +2948,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateResourcePresetRequest" + "$ref": "#/components/schemas/spin.v1.SetRegistrationModeRequest" } } }, @@ -2844,7 +2970,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateResourcePresetResponse" + "$ref": "#/components/schemas/spin.v1.SetRegistrationModeResponse" } } } @@ -2852,14 +2978,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", @@ -2884,7 +3010,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateSecuritySettingsRequest" + "$ref": "#/components/schemas/spin.v1.UntagImageRequest" } } }, @@ -2906,7 +3032,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateSecuritySettingsResponse" + "$ref": "#/components/schemas/spin.v1.UntagImageResponse" } } } @@ -2914,14 +3040,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", @@ -2946,7 +3072,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateStorageSettingsRequest" + "$ref": "#/components/schemas/spin.v1.UpdateEmailSettingsRequest" } } }, @@ -2968,7 +3094,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateStorageSettingsResponse" + "$ref": "#/components/schemas/spin.v1.UpdateEmailSettingsResponse" } } } @@ -2976,14 +3102,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", @@ -3008,7 +3133,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateUserRequest" + "$ref": "#/components/schemas/spin.v1.UpdateHostClassRequest" } } }, @@ -3030,7 +3155,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateUserResponse" + "$ref": "#/components/schemas/spin.v1.UpdateHostClassResponse" } } } @@ -3038,13 +3163,14 @@ } } }, - "/spin.v1.AuthService/ApproveWorkspaceSignIn": { + "/spin.v1.AdminService/UpdateInstallationSettings": { "post": { "tags": [ - "AuthService" + "AdminService" ], - "summary": "ApproveWorkspaceSignIn", - "operationId": "spin.v1.AuthService.ApproveWorkspaceSignIn", + "summary": "UpdateInstallationSettings", + "description": "Update installation settings", + "operationId": "spin.v1.AdminService.UpdateInstallationSettings", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3069,7 +3195,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ApproveWorkspaceSignInRequest" + "$ref": "#/components/schemas/spin.v1.UpdateInstallationSettingsRequest" } } }, @@ -3091,7 +3217,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ApproveWorkspaceSignInResponse" + "$ref": "#/components/schemas/spin.v1.UpdateInstallationSettingsResponse" } } } @@ -3099,14 +3225,13 @@ } } }, - "/spin.v1.AuthService/BeginWorkspaceSignIn": { + "/spin.v1.AdminService/UpdateNetworkPolicy": { "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": "UpdateNetworkPolicy", + "operationId": "spin.v1.AdminService.UpdateNetworkPolicy", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3131,7 +3256,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.BeginWorkspaceSignInRequest" + "$ref": "#/components/schemas/spin.v1.UpdateNetworkPolicyRequest" } } }, @@ -3153,7 +3278,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.BeginWorkspaceSignInResponse" + "$ref": "#/components/schemas/spin.v1.UpdateNetworkPolicyResponse" } } } @@ -3161,14 +3286,14 @@ } } }, - "/spin.v1.AuthService/CheckDeviceLogin": { + "/spin.v1.AdminService/UpdateResourcePreset": { "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": "UpdateResourcePreset", + "description": "Update a resource preset", + "operationId": "spin.v1.AdminService.UpdateResourcePreset", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3193,7 +3318,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CheckDeviceLoginRequest" + "$ref": "#/components/schemas/spin.v1.UpdateResourcePresetRequest" } } }, @@ -3215,7 +3340,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CheckDeviceLoginResponse" + "$ref": "#/components/schemas/spin.v1.UpdateResourcePresetResponse" } } } @@ -3223,14 +3348,14 @@ } } }, - "/spin.v1.AuthService/CompleteLogin": { + "/spin.v1.AdminService/UpdateSecuritySettings": { "post": { "tags": [ - "AuthService" + "AdminService" ], - "summary": "CompleteLogin", - "description": "Complete login (callback from IdP)", - "operationId": "spin.v1.AuthService.CompleteLogin", + "summary": "UpdateSecuritySettings", + "description": "Update security settings", + "operationId": "spin.v1.AdminService.UpdateSecuritySettings", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3255,7 +3380,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CompleteLoginRequest" + "$ref": "#/components/schemas/spin.v1.UpdateSecuritySettingsRequest" } } }, @@ -3277,7 +3402,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CompleteLoginResponse" + "$ref": "#/components/schemas/spin.v1.UpdateSecuritySettingsResponse" } } } @@ -3285,13 +3410,14 @@ } } }, - "/spin.v1.AuthService/CompleteWorkspaceSignIn": { + "/spin.v1.AdminService/UpdateStorageSettings": { "post": { "tags": [ - "AuthService" + "AdminService" ], - "summary": "CompleteWorkspaceSignIn", - "operationId": "spin.v1.AuthService.CompleteWorkspaceSignIn", + "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", @@ -3316,7 +3442,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CompleteWorkspaceSignInRequest" + "$ref": "#/components/schemas/spin.v1.UpdateStorageSettingsRequest" } } }, @@ -3338,7 +3464,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CompleteWorkspaceSignInResponse" + "$ref": "#/components/schemas/spin.v1.UpdateStorageSettingsResponse" } } } @@ -3346,14 +3472,14 @@ } } }, - "/spin.v1.AuthService/ConfirmDeviceLogin": { + "/spin.v1.AdminService/UpdateUser": { "post": { "tags": [ - "AuthService" + "AdminService" ], - "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": "UpdateUser", + "description": "Update user (can toggle is_instance_admin, disable user)", + "operationId": "spin.v1.AdminService.UpdateUser", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3378,7 +3504,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ConfirmDeviceLoginRequest" + "$ref": "#/components/schemas/spin.v1.UpdateUserRequest" } } }, @@ -3400,7 +3526,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ConfirmDeviceLoginResponse" + "$ref": "#/components/schemas/spin.v1.UpdateUserResponse" } } } @@ -3408,14 +3534,13 @@ } } }, - "/spin.v1.AuthService/CreateAPIKey": { + "/spin.v1.AuthService/ApproveWorkspaceSignIn": { "post": { "tags": [ "AuthService" ], - "summary": "CreateAPIKey", - "description": "Create API key", - "operationId": "spin.v1.AuthService.CreateAPIKey", + "summary": "ApproveWorkspaceSignIn", + "operationId": "spin.v1.AuthService.ApproveWorkspaceSignIn", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3440,7 +3565,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CreateAPIKeyRequest" + "$ref": "#/components/schemas/spin.v1.ApproveWorkspaceSignInRequest" } } }, @@ -3462,7 +3587,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CreateAPIKeyResponse" + "$ref": "#/components/schemas/spin.v1.ApproveWorkspaceSignInResponse" } } } @@ -3470,14 +3595,14 @@ } } }, - "/spin.v1.AuthService/ExchangeWorkloadToken": { + "/spin.v1.AuthService/BeginWorkspaceSignIn": { "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": "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", @@ -3502,7 +3627,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ExchangeWorkloadTokenRequest" + "$ref": "#/components/schemas/spin.v1.BeginWorkspaceSignInRequest" } } }, @@ -3524,7 +3649,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ExchangeWorkloadTokenResponse" + "$ref": "#/components/schemas/spin.v1.BeginWorkspaceSignInResponse" } } } @@ -3532,14 +3657,14 @@ } } }, - "/spin.v1.AuthService/GetCurrentUser": { + "/spin.v1.AuthService/CheckDeviceLogin": { "post": { "tags": [ "AuthService" ], - "summary": "GetCurrentUser", - "description": "Get current user info", - "operationId": "spin.v1.AuthService.GetCurrentUser", + "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", @@ -3564,7 +3689,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetCurrentUserRequest" + "$ref": "#/components/schemas/spin.v1.CheckDeviceLoginRequest" } } }, @@ -3586,7 +3711,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetCurrentUserResponse" + "$ref": "#/components/schemas/spin.v1.CheckDeviceLoginResponse" } } } @@ -3594,14 +3719,14 @@ } } }, - "/spin.v1.AuthService/ListAPIKeys": { + "/spin.v1.AuthService/CompleteLogin": { "post": { "tags": [ "AuthService" ], - "summary": "ListAPIKeys", - "description": "List API keys", - "operationId": "spin.v1.AuthService.ListAPIKeys", + "summary": "CompleteLogin", + "description": "Complete login (callback from IdP)", + "operationId": "spin.v1.AuthService.CompleteLogin", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3626,7 +3751,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListAPIKeysRequest" + "$ref": "#/components/schemas/spin.v1.CompleteLoginRequest" } } }, @@ -3648,7 +3773,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListAPIKeysResponse" + "$ref": "#/components/schemas/spin.v1.CompleteLoginResponse" } } } @@ -3656,14 +3781,13 @@ } } }, - "/spin.v1.AuthService/ListIdentityProviders": { + "/spin.v1.AuthService/CompleteWorkspaceSignIn": { "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": "CompleteWorkspaceSignIn", + "operationId": "spin.v1.AuthService.CompleteWorkspaceSignIn", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3688,7 +3812,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListIdentityProvidersRequest" + "$ref": "#/components/schemas/spin.v1.CompleteWorkspaceSignInRequest" } } }, @@ -3710,7 +3834,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListIdentityProvidersResponse" + "$ref": "#/components/schemas/spin.v1.CompleteWorkspaceSignInResponse" } } } @@ -3718,14 +3842,14 @@ } } }, - "/spin.v1.AuthService/Logout": { + "/spin.v1.AuthService/ConfirmDeviceLogin": { "post": { "tags": [ "AuthService" ], - "summary": "Logout", - "description": "Logout (invalidate session)", - "operationId": "spin.v1.AuthService.Logout", + "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", @@ -3750,7 +3874,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.LogoutRequest" + "$ref": "#/components/schemas/spin.v1.ConfirmDeviceLoginRequest" } } }, @@ -3772,7 +3896,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.LogoutResponse" + "$ref": "#/components/schemas/spin.v1.ConfirmDeviceLoginResponse" } } } @@ -3780,14 +3904,14 @@ } } }, - "/spin.v1.AuthService/RevokeAPIKey": { + "/spin.v1.AuthService/CreateAPIKey": { "post": { "tags": [ "AuthService" ], - "summary": "RevokeAPIKey", - "description": "Revoke API key", - "operationId": "spin.v1.AuthService.RevokeAPIKey", + "summary": "CreateAPIKey", + "description": "Create API key", + "operationId": "spin.v1.AuthService.CreateAPIKey", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3812,7 +3936,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeAPIKeyRequest" + "$ref": "#/components/schemas/spin.v1.CreateAPIKeyRequest" } } }, @@ -3834,7 +3958,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeAPIKeyResponse" + "$ref": "#/components/schemas/spin.v1.CreateAPIKeyResponse" } } } @@ -3842,14 +3966,14 @@ } } }, - "/spin.v1.AuthService/SearchUsers": { + "/spin.v1.AuthService/ExchangeWorkloadToken": { "post": { "tags": [ "AuthService" ], - "summary": "SearchUsers", - "description": "Search users by name or email (for team member selection, workspace sharing)", - "operationId": "spin.v1.AuthService.SearchUsers", + "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", @@ -3874,7 +3998,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SearchUsersRequest" + "$ref": "#/components/schemas/spin.v1.ExchangeWorkloadTokenRequest" } } }, @@ -3896,7 +4020,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SearchUsersResponse" + "$ref": "#/components/schemas/spin.v1.ExchangeWorkloadTokenResponse" } } } @@ -3904,14 +4028,14 @@ } } }, - "/spin.v1.AuthService/StartDeviceLogin": { + "/spin.v1.AuthService/GetCurrentUser": { "post": { "tags": [ "AuthService" ], - "summary": "StartDeviceLogin", - "description": "Start device login flow (for CLI when OAuth redirect is not available)\n Returns a user code and verification URL. User visits URL and enters code.", - "operationId": "spin.v1.AuthService.StartDeviceLogin", + "summary": "GetCurrentUser", + "description": "Get current user info", + "operationId": "spin.v1.AuthService.GetCurrentUser", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3936,7 +4060,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.StartDeviceLoginRequest" + "$ref": "#/components/schemas/spin.v1.GetCurrentUserRequest" } } }, @@ -3958,7 +4082,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.StartDeviceLoginResponse" + "$ref": "#/components/schemas/spin.v1.GetCurrentUserResponse" } } } @@ -3966,14 +4090,14 @@ } } }, - "/spin.v1.AuthService/StartLogin": { + "/spin.v1.AuthService/ListAPIKeys": { "post": { "tags": [ "AuthService" ], - "summary": "StartLogin", - "description": "Start login flow with a specific identity provider\n Use \"github\" for built-in GitHub auth, or IdP ID for dynamic providers", - "operationId": "spin.v1.AuthService.StartLogin", + "summary": "ListAPIKeys", + "description": "List API keys", + "operationId": "spin.v1.AuthService.ListAPIKeys", "parameters": [ { "name": "Connect-Protocol-Version", @@ -3998,7 +4122,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.StartLoginRequest" + "$ref": "#/components/schemas/spin.v1.ListAPIKeysRequest" } } }, @@ -4020,7 +4144,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.StartLoginResponse" + "$ref": "#/components/schemas/spin.v1.ListAPIKeysResponse" } } } @@ -4028,14 +4152,14 @@ } } }, - "/spin.v1.ExecService/Exec": { + "/spin.v1.AuthService/ListIdentityProviders": { "post": { "tags": [ - "ExecService" + "AuthService" ], - "summary": "Exec", - "description": "Runs command in the workspace's login shell and answers once it has exited, or once timeout\n has passed: stdin is all of it, given at once, and stdout and stderr are kept up to a bound\n each.", - "operationId": "spin.v1.ExecService.Exec", + "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", @@ -4060,7 +4184,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ExecRequest" + "$ref": "#/components/schemas/spin.v1.ListIdentityProvidersRequest" } } }, @@ -4082,7 +4206,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ExecResponse" + "$ref": "#/components/schemas/spin.v1.ListIdentityProvidersResponse" } } } @@ -4090,14 +4214,14 @@ } } }, - "/spin.v1.ExecService/ReadFile": { + "/spin.v1.AuthService/Logout": { "post": { "tags": [ - "ExecService" + "AuthService" ], - "summary": "ReadFile", - "description": "Reads a file of the workspace's, whole, up to a bound.", - "operationId": "spin.v1.ExecService.ReadFile", + "summary": "Logout", + "description": "Logout (invalidate session)", + "operationId": "spin.v1.AuthService.Logout", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4122,7 +4246,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ReadFileRequest" + "$ref": "#/components/schemas/spin.v1.LogoutRequest" } } }, @@ -4144,7 +4268,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ReadFileResponse" + "$ref": "#/components/schemas/spin.v1.LogoutResponse" } } } @@ -4152,14 +4276,14 @@ } } }, - "/spin.v1.ExecService/WriteFile": { + "/spin.v1.AuthService/RevokeAPIKey": { "post": { "tags": [ - "ExecService" + "AuthService" ], - "summary": "WriteFile", - "description": "Writes a file of the workspace's, whole, making the directories it is in.", - "operationId": "spin.v1.ExecService.WriteFile", + "summary": "RevokeAPIKey", + "description": "Revoke API key", + "operationId": "spin.v1.AuthService.RevokeAPIKey", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4184,7 +4308,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.WriteFileRequest" + "$ref": "#/components/schemas/spin.v1.RevokeAPIKeyRequest" } } }, @@ -4206,7 +4330,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.WriteFileResponse" + "$ref": "#/components/schemas/spin.v1.RevokeAPIKeyResponse" } } } @@ -4214,13 +4338,14 @@ } } }, - "/spin.v1.ForgeService/CompleteAppCreation": { + "/spin.v1.AuthService/SearchUsers": { "post": { "tags": [ - "ForgeService" + "AuthService" ], - "summary": "CompleteAppCreation", - "operationId": "spin.v1.ForgeService.CompleteAppCreation", + "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", @@ -4245,7 +4370,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CompleteAppCreationRequest" + "$ref": "#/components/schemas/spin.v1.SearchUsersRequest" } } }, @@ -4267,7 +4392,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CompleteAppCreationResponse" + "$ref": "#/components/schemas/spin.v1.SearchUsersResponse" } } } @@ -4275,13 +4400,14 @@ } } }, - "/spin.v1.ForgeService/CompleteConnect": { + "/spin.v1.AuthService/StartDeviceLogin": { "post": { "tags": [ - "ForgeService" + "AuthService" ], - "summary": "CompleteConnect", - "operationId": "spin.v1.ForgeService.CompleteConnect", + "summary": "StartDeviceLogin", + "description": "Start device login flow (for CLI when OAuth redirect is not available)\n Returns a user code and verification URL. User visits URL and enters code.", + "operationId": "spin.v1.AuthService.StartDeviceLogin", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4306,7 +4432,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CompleteConnectRequest" + "$ref": "#/components/schemas/spin.v1.StartDeviceLoginRequest" } } }, @@ -4328,7 +4454,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CompleteConnectResponse" + "$ref": "#/components/schemas/spin.v1.StartDeviceLoginResponse" } } } @@ -4336,14 +4462,14 @@ } } }, - "/spin.v1.ForgeService/DeleteForgeApp": { + "/spin.v1.AuthService/StartLogin": { "post": { "tags": [ - "ForgeService" + "AuthService" ], - "summary": "DeleteForgeApp", - "description": "Takes the app out of use at once. Every connection through it is revoked at the forge, and the\n app is gone when that is done.", - "operationId": "spin.v1.ForgeService.DeleteForgeApp", + "summary": "StartLogin", + "description": "Start login flow with a specific identity provider\n Use \"github\" for built-in GitHub auth, or IdP ID for dynamic providers", + "operationId": "spin.v1.AuthService.StartLogin", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4368,7 +4494,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.DeleteForgeAppRequest" + "$ref": "#/components/schemas/spin.v1.StartLoginRequest" } } }, @@ -4390,7 +4516,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.DeleteForgeAppResponse" + "$ref": "#/components/schemas/spin.v1.StartLoginResponse" } } } @@ -4398,14 +4524,14 @@ } } }, - "/spin.v1.ForgeService/Disconnect": { + "/spin.v1.ExecService/Exec": { "post": { "tags": [ - "ForgeService" + "ExecService" ], - "summary": "Disconnect", - "description": "Forgets the token and revokes it at the forge.", - "operationId": "spin.v1.ForgeService.Disconnect", + "summary": "Exec", + "description": "Runs command in the workspace's login shell and answers once it has exited, or once timeout\n has passed: stdin is all of it, given at once, and stdout and stderr are kept up to a bound\n each.", + "operationId": "spin.v1.ExecService.Exec", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4430,7 +4556,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.DisconnectRequest" + "$ref": "#/components/schemas/spin.v1.ExecRequest" } } }, @@ -4452,7 +4578,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.DisconnectResponse" + "$ref": "#/components/schemas/spin.v1.ExecResponse" } } } @@ -4460,13 +4586,14 @@ } } }, - "/spin.v1.ForgeService/ListConnections": { + "/spin.v1.ExecService/ReadFile": { "post": { "tags": [ - "ForgeService" + "ExecService" ], - "summary": "ListConnections", - "operationId": "spin.v1.ForgeService.ListConnections", + "summary": "ReadFile", + "description": "Reads a file of the workspace's, whole, up to a bound.", + "operationId": "spin.v1.ExecService.ReadFile", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4491,7 +4618,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListConnectionsRequest" + "$ref": "#/components/schemas/spin.v1.ReadFileRequest" } } }, @@ -4513,7 +4640,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListConnectionsResponse" + "$ref": "#/components/schemas/spin.v1.ReadFileResponse" } } } @@ -4521,14 +4648,14 @@ } } }, - "/spin.v1.ForgeService/ListForgeApps": { + "/spin.v1.ExecService/WriteFile": { "post": { "tags": [ - "ForgeService" + "ExecService" ], - "summary": "ListForgeApps", - "description": "The installation's app on each forge: whether a person can connect, and where. Its secrets are\n never answered with.", - "operationId": "spin.v1.ForgeService.ListForgeApps", + "summary": "WriteFile", + "description": "Writes a file of the workspace's, whole, making the directories it is in.", + "operationId": "spin.v1.ExecService.WriteFile", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4553,7 +4680,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListForgeAppsRequest" + "$ref": "#/components/schemas/spin.v1.WriteFileRequest" } } }, @@ -4575,7 +4702,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListForgeAppsResponse" + "$ref": "#/components/schemas/spin.v1.WriteFileResponse" } } } @@ -4583,13 +4710,13 @@ } } }, - "/spin.v1.ForgeService/PollDeviceConnect": { + "/spin.v1.ForgeService/CompleteAppCreation": { "post": { "tags": [ "ForgeService" ], - "summary": "PollDeviceConnect", - "operationId": "spin.v1.ForgeService.PollDeviceConnect", + "summary": "CompleteAppCreation", + "operationId": "spin.v1.ForgeService.CompleteAppCreation", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4614,7 +4741,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.PollDeviceConnectRequest" + "$ref": "#/components/schemas/spin.v1.CompleteAppCreationRequest" } } }, @@ -4636,7 +4763,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.PollDeviceConnectResponse" + "$ref": "#/components/schemas/spin.v1.CompleteAppCreationResponse" } } } @@ -4644,14 +4771,13 @@ } } }, - "/spin.v1.ForgeService/SearchRepositories": { + "/spin.v1.ForgeService/CompleteConnect": { "post": { "tags": [ "ForgeService" ], - "summary": "SearchRepositories", - "description": "The repositories the person's account reaches that match query, as the forge searches them\n with the person's token: what they can see there is what they can pick here.", - "operationId": "spin.v1.ForgeService.SearchRepositories", + "summary": "CompleteConnect", + "operationId": "spin.v1.ForgeService.CompleteConnect", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4676,7 +4802,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SearchRepositoriesRequest" + "$ref": "#/components/schemas/spin.v1.CompleteConnectRequest" } } }, @@ -4698,7 +4824,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SearchRepositoriesResponse" + "$ref": "#/components/schemas/spin.v1.CompleteConnectResponse" } } } @@ -4706,14 +4832,14 @@ } } }, - "/spin.v1.ForgeService/SetForgeApp": { + "/spin.v1.ForgeService/DeleteForgeApp": { "post": { "tags": [ "ForgeService" ], - "summary": "SetForgeApp", - "description": "Keeping an app that was made elsewhere. Refused while the forge has one: an app is never\n edited, because another client id could not revoke what this one granted.", - "operationId": "spin.v1.ForgeService.SetForgeApp", + "summary": "DeleteForgeApp", + "description": "Takes the app out of use at once. Every connection through it is revoked at the forge, and the\n app is gone when that is done.", + "operationId": "spin.v1.ForgeService.DeleteForgeApp", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4738,7 +4864,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SetForgeAppRequest" + "$ref": "#/components/schemas/spin.v1.DeleteForgeAppRequest" } } }, @@ -4760,7 +4886,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SetForgeAppResponse" + "$ref": "#/components/schemas/spin.v1.DeleteForgeAppResponse" } } } @@ -4768,14 +4894,14 @@ } } }, - "/spin.v1.ForgeService/StartAppCreation": { + "/spin.v1.ForgeService/Disconnect": { "post": { "tags": [ "ForgeService" ], - "summary": "StartAppCreation", - "description": "Making the app, by an instance admin, through the forge's manifest flow: StartAppCreation\n answers the form the browser posts to the forge, which makes the app and sends the admin back\n with a code; CompleteAppCreation exchanges it for the app's credentials. Nobody copies a key.", - "operationId": "spin.v1.ForgeService.StartAppCreation", + "summary": "Disconnect", + "description": "Forgets the token and revokes it at the forge.", + "operationId": "spin.v1.ForgeService.Disconnect", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4800,7 +4926,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.StartAppCreationRequest" + "$ref": "#/components/schemas/spin.v1.DisconnectRequest" } } }, @@ -4822,7 +4948,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.StartAppCreationResponse" + "$ref": "#/components/schemas/spin.v1.DisconnectResponse" } } } @@ -4830,14 +4956,13 @@ } } }, - "/spin.v1.ForgeService/StartConnect": { + "/spin.v1.ForgeService/ListConnections": { "post": { "tags": [ "ForgeService" ], - "summary": "StartConnect", - "description": "Connecting: StartConnect answers where the person authorizes the app and a binding only this\n client keeps; the forge sends the browser back to redirect_uri with a code and the state, and\n CompleteConnect exchanges them, with the binding, for the person's token.", - "operationId": "spin.v1.ForgeService.StartConnect", + "summary": "ListConnections", + "operationId": "spin.v1.ForgeService.ListConnections", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4862,7 +4987,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.StartConnectRequest" + "$ref": "#/components/schemas/spin.v1.ListConnectionsRequest" } } }, @@ -4884,7 +5009,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.StartConnectResponse" + "$ref": "#/components/schemas/spin.v1.ListConnectionsResponse" } } } @@ -4892,14 +5017,14 @@ } } }, - "/spin.v1.ForgeService/StartDeviceConnect": { + "/spin.v1.ForgeService/ListForgeApps": { "post": { "tags": [ "ForgeService" ], - "summary": "StartDeviceConnect", - "description": "Connecting from somewhere with no browser to send back to, the CLI: the control plane asks the\n forge for a device code (RFC 8628) and keeps it, and answers with the code the person types on\n the forge's page and a handle only the caller can poll with. PollDeviceConnect asks the forge,\n at most once an interval, and on the person's approval keeps their token as CompleteConnect\n does: once, for the person who began it.", - "operationId": "spin.v1.ForgeService.StartDeviceConnect", + "summary": "ListForgeApps", + "description": "The installation's app on each forge: whether a person can connect, and where. Its secrets are\n never answered with.", + "operationId": "spin.v1.ForgeService.ListForgeApps", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4924,7 +5049,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.StartDeviceConnectRequest" + "$ref": "#/components/schemas/spin.v1.ListForgeAppsRequest" } } }, @@ -4946,7 +5071,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.StartDeviceConnectResponse" + "$ref": "#/components/schemas/spin.v1.ListForgeAppsResponse" } } } @@ -4954,14 +5079,13 @@ } } }, - "/spin.v1.HostService/ActivateHost": { + "/spin.v1.ForgeService/PollDeviceConnect": { "post": { "tags": [ - "HostService" + "ForgeService" ], - "summary": "ActivateHost", - "description": "Activate a drained host (set to healthy, admin only)", - "operationId": "spin.v1.HostService.ActivateHost", + "summary": "PollDeviceConnect", + "operationId": "spin.v1.ForgeService.PollDeviceConnect", "parameters": [ { "name": "Connect-Protocol-Version", @@ -4986,7 +5110,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ActivateHostRequest" + "$ref": "#/components/schemas/spin.v1.PollDeviceConnectRequest" } } }, @@ -5008,7 +5132,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ActivateHostResponse" + "$ref": "#/components/schemas/spin.v1.PollDeviceConnectResponse" } } } @@ -5016,14 +5140,14 @@ } } }, - "/spin.v1.HostService/DrainHost": { + "/spin.v1.ForgeService/SearchRepositories": { "post": { "tags": [ - "HostService" + "ForgeService" ], - "summary": "DrainHost", - "description": "Set host to draining (admin only)", - "operationId": "spin.v1.HostService.DrainHost", + "summary": "SearchRepositories", + "description": "The repositories the person's account reaches that match query, as the forge searches them\n with the person's token: what they can see there is what they can pick here.", + "operationId": "spin.v1.ForgeService.SearchRepositories", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5048,7 +5172,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.DrainHostRequest" + "$ref": "#/components/schemas/spin.v1.SearchRepositoriesRequest" } } }, @@ -5070,7 +5194,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.DrainHostResponse" + "$ref": "#/components/schemas/spin.v1.SearchRepositoriesResponse" } } } @@ -5078,14 +5202,14 @@ } } }, - "/spin.v1.HostService/GetFleet": { + "/spin.v1.ForgeService/SetForgeApp": { "post": { "tags": [ - "HostService" + "ForgeService" ], - "summary": "GetFleet", - "description": "The fleet as a whole (admin only): how many hosts there are against how many the\n installation has asked its cloud for, and what it is waiting for. A fleet that scales from\n none looks broken without this - no hosts, no explanation, and a workspace that waits\n minutes for a machine to boot with nothing saying so.", - "operationId": "spin.v1.HostService.GetFleet", + "summary": "SetForgeApp", + "description": "Keeping an app that was made elsewhere. Refused while the forge has one: an app is never\n edited, because another client id could not revoke what this one granted.", + "operationId": "spin.v1.ForgeService.SetForgeApp", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5110,7 +5234,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetFleetRequest" + "$ref": "#/components/schemas/spin.v1.SetForgeAppRequest" } } }, @@ -5132,7 +5256,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetFleetResponse" + "$ref": "#/components/schemas/spin.v1.SetForgeAppResponse" } } } @@ -5140,14 +5264,14 @@ } } }, - "/spin.v1.HostService/GetHost": { + "/spin.v1.ForgeService/StartAppCreation": { "post": { "tags": [ - "HostService" + "ForgeService" ], - "summary": "GetHost", - "description": "Get host details (admin only)", - "operationId": "spin.v1.HostService.GetHost", + "summary": "StartAppCreation", + "description": "Making the app, by an instance admin, through the forge's manifest flow: StartAppCreation\n answers the form the browser posts to the forge, which makes the app and sends the admin back\n with a code; CompleteAppCreation exchanges it for the app's credentials. Nobody copies a key.", + "operationId": "spin.v1.ForgeService.StartAppCreation", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5172,7 +5296,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetHostRequest" + "$ref": "#/components/schemas/spin.v1.StartAppCreationRequest" } } }, @@ -5194,7 +5318,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetHostResponse" + "$ref": "#/components/schemas/spin.v1.StartAppCreationResponse" } } } @@ -5202,14 +5326,14 @@ } } }, - "/spin.v1.HostService/GetHostPolicy": { + "/spin.v1.ForgeService/StartConnect": { "post": { "tags": [ - "HostService" + "ForgeService" ], - "summary": "GetHostPolicy", - "description": "What a host may do, as against what it is (admin only). A host reads what it *is* from\n its own environment, before it can reach this; everything else it is told, on its\n heartbeat, and it reports back the revision it is running under.", - "operationId": "spin.v1.HostService.GetHostPolicy", + "summary": "StartConnect", + "description": "Connecting: StartConnect answers where the person authorizes the app and a binding only this\n client keeps; the forge sends the browser back to redirect_uri with a code and the state, and\n CompleteConnect exchanges them, with the binding, for the person's token.", + "operationId": "spin.v1.ForgeService.StartConnect", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5234,7 +5358,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetHostPolicyRequest" + "$ref": "#/components/schemas/spin.v1.StartConnectRequest" } } }, @@ -5256,7 +5380,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetHostPolicyResponse" + "$ref": "#/components/schemas/spin.v1.StartConnectResponse" } } } @@ -5264,14 +5388,14 @@ } } }, - "/spin.v1.HostService/ListHosts": { + "/spin.v1.ForgeService/StartDeviceConnect": { "post": { "tags": [ - "HostService" + "ForgeService" ], - "summary": "ListHosts", - "description": "List all hosts (admin only)", - "operationId": "spin.v1.HostService.ListHosts", + "summary": "StartDeviceConnect", + "description": "Connecting from somewhere with no browser to send back to, the CLI: the control plane asks the\n forge for a device code (RFC 8628) and keeps it, and answers with the code the person types on\n the forge's page and a handle only the caller can poll with. PollDeviceConnect asks the forge,\n at most once an interval, and on the person's approval keeps their token as CompleteConnect\n does: once, for the person who began it.", + "operationId": "spin.v1.ForgeService.StartDeviceConnect", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5296,7 +5420,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListHostsRequest" + "$ref": "#/components/schemas/spin.v1.StartDeviceConnectRequest" } } }, @@ -5318,7 +5442,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListHostsResponse" + "$ref": "#/components/schemas/spin.v1.StartDeviceConnectResponse" } } } @@ -5326,13 +5450,14 @@ } } }, - "/spin.v1.HostService/SetHostPolicy": { + "/spin.v1.HostService/ActivateHost": { "post": { "tags": [ "HostService" ], - "summary": "SetHostPolicy", - "operationId": "spin.v1.HostService.SetHostPolicy", + "summary": "ActivateHost", + "description": "Activate a drained host (set to healthy, admin only)", + "operationId": "spin.v1.HostService.ActivateHost", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5357,7 +5482,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SetHostPolicyRequest" + "$ref": "#/components/schemas/spin.v1.ActivateHostRequest" } } }, @@ -5379,7 +5504,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SetHostPolicyResponse" + "$ref": "#/components/schemas/spin.v1.ActivateHostResponse" } } } @@ -5387,14 +5512,14 @@ } } }, - "/spin.v1.HostService/TestHostWriteback": { + "/spin.v1.HostService/DrainHost": { "post": { "tags": [ "HostService" ], - "summary": "TestHostWriteback", - "description": "Measures a host's disk under writeback thresholds no preset names, against the ones it holds\n (admin only). SetHostPolicy refuses such thresholds for a host until it has been tested with\n them; the test loads that host's disk for about forty seconds.", - "operationId": "spin.v1.HostService.TestHostWriteback", + "summary": "DrainHost", + "description": "Set host to draining (admin only)", + "operationId": "spin.v1.HostService.DrainHost", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5419,7 +5544,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.TestHostWritebackRequest" + "$ref": "#/components/schemas/spin.v1.DrainHostRequest" } } }, @@ -5441,7 +5566,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.TestHostWritebackResponse" + "$ref": "#/components/schemas/spin.v1.DrainHostResponse" } } } @@ -5449,14 +5574,14 @@ } } }, - "/spin.v1.HostShellService/ApproveHostShell": { + "/spin.v1.HostService/GetFleet": { "post": { "tags": [ - "HostShellService" + "HostService" ], - "summary": "ApproveHostShell", - "description": "Approves a shell another administrator asked for.", - "operationId": "spin.v1.HostShellService.ApproveHostShell", + "summary": "GetFleet", + "description": "The fleet as a whole (admin only): how many hosts there are against how many the\n installation has asked its cloud for, and what it is waiting for. A fleet that scales from\n none looks broken without this - no hosts, no explanation, and a workspace that waits\n minutes for a machine to boot with nothing saying so.", + "operationId": "spin.v1.HostService.GetFleet", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5481,7 +5606,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ApproveHostShellRequest" + "$ref": "#/components/schemas/spin.v1.GetFleetRequest" } } }, @@ -5503,7 +5628,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ApproveHostShellResponse" + "$ref": "#/components/schemas/spin.v1.GetFleetResponse" } } } @@ -5511,14 +5636,14 @@ } } }, - "/spin.v1.HostShellService/CloseHostShell": { + "/spin.v1.HostService/GetHost": { "post": { "tags": [ - "HostShellService" + "HostService" ], - "summary": "CloseHostShell", - "description": "Ends a shell: one not yet approved is refused, any other is ended and its host retired.", - "operationId": "spin.v1.HostShellService.CloseHostShell", + "summary": "GetHost", + "description": "Get host details (admin only)", + "operationId": "spin.v1.HostService.GetHost", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5543,7 +5668,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CloseHostShellRequest" + "$ref": "#/components/schemas/spin.v1.GetHostRequest" } } }, @@ -5565,7 +5690,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CloseHostShellResponse" + "$ref": "#/components/schemas/spin.v1.GetHostResponse" } } } @@ -5573,14 +5698,14 @@ } } }, - "/spin.v1.HostShellService/GetHostShellRecording": { + "/spin.v1.HostService/GetHostPolicy": { "post": { "tags": [ - "HostShellService" + "HostService" ], - "summary": "GetHostShellRecording", - "description": "What a shell's sessions recorded, asciicast v2, each session's in turn.", - "operationId": "spin.v1.HostShellService.GetHostShellRecording", + "summary": "GetHostPolicy", + "description": "What a host may do, as against what it is (admin only). A host reads what it *is* from\n its own environment, before it can reach this; everything else it is told, on its\n heartbeat, and it reports back the revision it is running under.", + "operationId": "spin.v1.HostService.GetHostPolicy", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5605,7 +5730,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetHostShellRecordingRequest" + "$ref": "#/components/schemas/spin.v1.GetHostPolicyRequest" } } }, @@ -5627,7 +5752,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetHostShellRecordingResponse" + "$ref": "#/components/schemas/spin.v1.GetHostPolicyResponse" } } } @@ -5635,14 +5760,14 @@ } } }, - "/spin.v1.HostShellService/ListHostShells": { + "/spin.v1.HostService/ListHosts": { "post": { "tags": [ - "HostShellService" + "HostService" ], - "summary": "ListHostShells", - "description": "The installation's host shells, newest first: all of them, or one host's.", - "operationId": "spin.v1.HostShellService.ListHostShells", + "summary": "ListHosts", + "description": "List all hosts (admin only)", + "operationId": "spin.v1.HostService.ListHosts", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5667,7 +5792,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListHostShellsRequest" + "$ref": "#/components/schemas/spin.v1.ListHostsRequest" } } }, @@ -5689,7 +5814,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListHostShellsResponse" + "$ref": "#/components/schemas/spin.v1.ListHostsResponse" } } } @@ -5697,14 +5822,14 @@ } } }, - "/spin.v1.HostShellService/RequestHostShell": { + "/spin.v1.HostService/RemoveHost": { "post": { "tags": [ - "HostShellService" + "HostService" ], - "summary": "RequestHostShell", - "description": "Asks for a shell on a host. Where the installation has a second administrator approve\n (host_shell_needs_approval), it waits for one; otherwise the host is emptied at once.", - "operationId": "spin.v1.HostShellService.RequestHostShell", + "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.", + "operationId": "spin.v1.HostService.RemoveHost", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5729,7 +5854,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RequestHostShellRequest" + "$ref": "#/components/schemas/spin.v1.RemoveHostRequest" } } }, @@ -5751,7 +5876,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RequestHostShellResponse" + "$ref": "#/components/schemas/spin.v1.RemoveHostResponse" } } } @@ -5759,14 +5884,13 @@ } } }, - "/spin.v1.LogService/GetTrace": { + "/spin.v1.HostService/SetHostPolicy": { "post": { "tags": [ - "LogService" + "HostService" ], - "summary": "GetTrace", - "description": "GetTrace is every span of one trace, in the order they began.", - "operationId": "spin.v1.LogService.GetTrace", + "summary": "SetHostPolicy", + "operationId": "spin.v1.HostService.SetHostPolicy", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5791,7 +5915,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetTraceRequest" + "$ref": "#/components/schemas/spin.v1.SetHostPolicyRequest" } } }, @@ -5813,7 +5937,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetTraceResponse" + "$ref": "#/components/schemas/spin.v1.SetHostPolicyResponse" } } } @@ -5821,15 +5945,635 @@ } } }, - "/spin.v1.LogService/GetWorkspaceTrace": { + "/spin.v1.HostService/TestHostWriteback": { "post": { "tags": [ - "LogService" + "HostService" ], - "summary": "GetWorkspaceTrace", - "description": "GetWorkspaceTrace is the spans of one trace marked as about one workspace, in the order they\n began, for its owner: the rest of the trace is left out, as SearchWorkspaceTraces leaves it.", - "operationId": "spin.v1.LogService.GetWorkspaceTrace", - "parameters": [ + "summary": "TestHostWriteback", + "description": "Measures a host's disk under writeback thresholds no preset names, against the ones it holds\n (admin only). SetHostPolicy refuses such thresholds for a host until it has been tested with\n them; the test loads that host's disk for about forty seconds.", + "operationId": "spin.v1.HostService.TestHostWriteback", + "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.TestHostWritebackRequest" + } + } + }, + "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.TestHostWritebackResponse" + } + } + } + } + } + } + }, + "/spin.v1.HostShellService/ApproveHostShell": { + "post": { + "tags": [ + "HostShellService" + ], + "summary": "ApproveHostShell", + "description": "Approves a shell another administrator asked for.", + "operationId": "spin.v1.HostShellService.ApproveHostShell", + "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.ApproveHostShellRequest" + } + } + }, + "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.ApproveHostShellResponse" + } + } + } + } + } + } + }, + "/spin.v1.HostShellService/CloseHostShell": { + "post": { + "tags": [ + "HostShellService" + ], + "summary": "CloseHostShell", + "description": "Ends a shell: one not yet approved is refused, any other is ended and its host retired.", + "operationId": "spin.v1.HostShellService.CloseHostShell", + "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.CloseHostShellRequest" + } + } + }, + "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.CloseHostShellResponse" + } + } + } + } + } + } + }, + "/spin.v1.HostShellService/GetHostShellRecording": { + "post": { + "tags": [ + "HostShellService" + ], + "summary": "GetHostShellRecording", + "description": "What a shell's sessions recorded, asciicast v2, each session's in turn.", + "operationId": "spin.v1.HostShellService.GetHostShellRecording", + "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.GetHostShellRecordingRequest" + } + } + }, + "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.GetHostShellRecordingResponse" + } + } + } + } + } + } + }, + "/spin.v1.HostShellService/ListHostShells": { + "post": { + "tags": [ + "HostShellService" + ], + "summary": "ListHostShells", + "description": "The installation's host shells, newest first: all of them, or one host's.", + "operationId": "spin.v1.HostShellService.ListHostShells", + "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.ListHostShellsRequest" + } + } + }, + "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.ListHostShellsResponse" + } + } + } + } + } + } + }, + "/spin.v1.HostShellService/RequestHostShell": { + "post": { + "tags": [ + "HostShellService" + ], + "summary": "RequestHostShell", + "description": "Asks for a shell on a host. Where the installation has a second administrator approve\n (host_shell_needs_approval), it waits for one; otherwise the host is emptied at once.", + "operationId": "spin.v1.HostShellService.RequestHostShell", + "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.RequestHostShellRequest" + } + } + }, + "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.RequestHostShellResponse" + } + } + } + } + } + } + }, + "/spin.v1.LogService/GetTrace": { + "post": { + "tags": [ + "LogService" + ], + "summary": "GetTrace", + "description": "GetTrace is every span of one trace, in the order they began.", + "operationId": "spin.v1.LogService.GetTrace", + "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.GetTraceRequest" + } + } + }, + "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.GetTraceResponse" + } + } + } + } + } + } + }, + "/spin.v1.LogService/GetWorkspaceTrace": { + "post": { + "tags": [ + "LogService" + ], + "summary": "GetWorkspaceTrace", + "description": "GetWorkspaceTrace is the spans of one trace marked as about one workspace, in the order they\n began, for its owner: the rest of the trace is left out, as SearchWorkspaceTraces leaves it.", + "operationId": "spin.v1.LogService.GetWorkspaceTrace", + "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.GetWorkspaceTraceRequest" + } + } + }, + "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.GetWorkspaceTraceResponse" + } + } + } + } + } + } + }, + "/spin.v1.LogService/HistogramPlatformLogs": { + "post": { + "tags": [ + "LogService" + ], + "summary": "HistogramPlatformLogs", + "description": "HistogramPlatformLogs is how many of those records each interval of the window holds, by\n severity: the chart above them.", + "operationId": "spin.v1.LogService.HistogramPlatformLogs", + "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.HistogramPlatformLogsRequest" + } + } + }, + "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.HistogramLogsResponse" + } + } + } + } + } + } + }, + "/spin.v1.LogService/HistogramWorkspaceLogs": { + "post": { + "tags": [ + "LogService" + ], + "summary": "HistogramWorkspaceLogs", + "description": "HistogramWorkspaceLogs is how many of those records each interval of the window holds.", + "operationId": "spin.v1.LogService.HistogramWorkspaceLogs", + "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.HistogramWorkspaceLogsRequest" + } + } + }, + "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.HistogramWorkspaceLogsResponse" + } + } + } + } + } + } + }, + "/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", @@ -5853,7 +6597,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceTraceRequest" + "$ref": "#/components/schemas/spin.v1.ListLogIndexesRequest" } } }, @@ -5875,7 +6619,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetWorkspaceTraceResponse" + "$ref": "#/components/schemas/spin.v1.ListLogIndexesResponse" } } } @@ -5883,14 +6627,14 @@ } } }, - "/spin.v1.LogService/HistogramPlatformLogs": { + "/spin.v1.LogService/PlatformLogFieldValues": { "post": { "tags": [ "LogService" ], - "summary": "HistogramPlatformLogs", - "description": "HistogramPlatformLogs is how many of those records each interval of the window holds, by\n severity: the chart above them.", - "operationId": "spin.v1.LogService.HistogramPlatformLogs", + "summary": "PlatformLogFieldValues", + "description": "PlatformLogFieldValues is what one field most often is in the records a search of the\n platform's logs finds: service_name, severity_text, attributes.* or resource_attributes.*.", + "operationId": "spin.v1.LogService.PlatformLogFieldValues", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5915,7 +6659,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.HistogramPlatformLogsRequest" + "$ref": "#/components/schemas/spin.v1.PlatformLogFieldValuesRequest" } } }, @@ -5937,7 +6681,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.HistogramLogsResponse" + "$ref": "#/components/schemas/spin.v1.PlatformLogFieldValuesResponse" } } } @@ -5945,14 +6689,14 @@ } } }, - "/spin.v1.LogService/HistogramWorkspaceLogs": { + "/spin.v1.LogService/SearchPlatformLogs": { "post": { "tags": [ "LogService" ], - "summary": "HistogramWorkspaceLogs", - "description": "HistogramWorkspaceLogs is how many of those records each interval of the window holds.", - "operationId": "spin.v1.LogService.HistogramWorkspaceLogs", + "summary": "SearchPlatformLogs", + "description": "SearchPlatformLogs is what the installation's own processes logged - the control plane, the\n proxy, the runners. An administrator's: a platform's log names every workspace it touched.", + "operationId": "spin.v1.LogService.SearchPlatformLogs", "parameters": [ { "name": "Connect-Protocol-Version", @@ -5977,7 +6721,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.HistogramWorkspaceLogsRequest" + "$ref": "#/components/schemas/spin.v1.SearchPlatformLogsRequest" } } }, @@ -5999,7 +6743,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.HistogramWorkspaceLogsResponse" + "$ref": "#/components/schemas/spin.v1.SearchLogsResponse" } } } @@ -6007,14 +6751,14 @@ } } }, - "/spin.v1.LogService/ListLogIndexes": { + "/spin.v1.LogService/SearchTraces": { "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": "SearchTraces", + "description": "SearchTraces is the installation's traces whose first span matches, newest first. An\n administrator's, as the platform's logs are.", + "operationId": "spin.v1.LogService.SearchTraces", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6039,7 +6783,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListLogIndexesRequest" + "$ref": "#/components/schemas/spin.v1.SearchTracesRequest" } } }, @@ -6061,7 +6805,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListLogIndexesResponse" + "$ref": "#/components/schemas/spin.v1.SearchTracesResponse" } } } @@ -6069,14 +6813,14 @@ } } }, - "/spin.v1.LogService/PlatformLogFieldValues": { + "/spin.v1.LogService/SearchWorkspaceLogs": { "post": { "tags": [ "LogService" ], - "summary": "PlatformLogFieldValues", - "description": "PlatformLogFieldValues is what one field most often is in the records a search of the\n platform's logs finds: service_name, severity_text, attributes.* or resource_attributes.*.", - "operationId": "spin.v1.LogService.PlatformLogFieldValues", + "summary": "SearchWorkspaceLogs", + "description": "SearchWorkspaceLogs is what one workspace's machine wrote to its console, where the\n installation collects it: whoever may read the workspace's console may search it.", + "operationId": "spin.v1.LogService.SearchWorkspaceLogs", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6101,7 +6845,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.PlatformLogFieldValuesRequest" + "$ref": "#/components/schemas/spin.v1.SearchWorkspaceLogsRequest" } } }, @@ -6123,7 +6867,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.PlatformLogFieldValuesResponse" + "$ref": "#/components/schemas/spin.v1.SearchWorkspaceLogsResponse" } } } @@ -6131,14 +6875,14 @@ } } }, - "/spin.v1.LogService/SearchPlatformLogs": { + "/spin.v1.LogService/SearchWorkspaceTraces": { "post": { "tags": [ "LogService" ], - "summary": "SearchPlatformLogs", - "description": "SearchPlatformLogs is what the installation's own processes logged - the control plane, the\n proxy, the runners. An administrator's: a platform's log names every workspace it touched.", - "operationId": "spin.v1.LogService.SearchPlatformLogs", + "summary": "SearchWorkspaceTraces", + "description": "SearchWorkspaceTraces is the spans marked as about one workspace - its creation, its starts\n and stops, what its host did for it - newest first, for its owner. A trace names every\n workspace it touched, so a span not marked as this one's is never answered, whichever trace\n it is in.", + "operationId": "spin.v1.LogService.SearchWorkspaceTraces", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6163,7 +6907,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SearchPlatformLogsRequest" + "$ref": "#/components/schemas/spin.v1.SearchWorkspaceTracesRequest" } } }, @@ -6185,7 +6929,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SearchLogsResponse" + "$ref": "#/components/schemas/spin.v1.SearchWorkspaceTracesResponse" } } } @@ -6193,14 +6937,14 @@ } } }, - "/spin.v1.LogService/SearchTraces": { + "/spin.v1.LogService/ServiceHealth": { "post": { "tags": [ "LogService" ], - "summary": "SearchTraces", - "description": "SearchTraces is the installation's traces whose first span matches, newest first. An\n administrator's, as the platform's logs are.", - "operationId": "spin.v1.LogService.SearchTraces", + "summary": "ServiceHealth", + "description": "ServiceHealth is how each of the installation's services did over a window, as its traces\n and logs say it. An administrator's, as the traces are.", + "operationId": "spin.v1.LogService.ServiceHealth", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6225,7 +6969,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SearchTracesRequest" + "$ref": "#/components/schemas/spin.v1.ServiceHealthRequest" } } }, @@ -6247,7 +6991,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SearchTracesResponse" + "$ref": "#/components/schemas/spin.v1.ServiceHealthResponse" } } } @@ -6255,14 +6999,138 @@ } } }, - "/spin.v1.LogService/SearchWorkspaceLogs": { + "/spin.v1.LogService/WorkspaceLogFieldValues": { "post": { "tags": [ "LogService" ], - "summary": "SearchWorkspaceLogs", - "description": "SearchWorkspaceLogs is what one workspace's machine wrote to its console, where the\n installation collects it: whoever may read the workspace's console may search it.", - "operationId": "spin.v1.LogService.SearchWorkspaceLogs", + "summary": "WorkspaceLogFieldValues", + "description": "WorkspaceLogFieldValues is the same of one workspace's, for whoever may read it.", + "operationId": "spin.v1.LogService.WorkspaceLogFieldValues", + "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.WorkspaceLogFieldValuesRequest" + } + } + }, + "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.WorkspaceLogFieldValuesResponse" + } + } + } + } + } + } + }, + "/spin.v1.PasskeyService/BeginPasskeyCeremony": { + "post": { + "tags": [ + "PasskeyService" + ], + "summary": "BeginPasskeyCeremony", + "description": "A challenge for one ceremony of the caller's, bound to what it is for: a passkey registered, a\n key added, a passkey deleted. Taken once, by the call it is answered in, within minutes.", + "operationId": "spin.v1.PasskeyService.BeginPasskeyCeremony", + "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.BeginPasskeyCeremonyRequest" + } + } + }, + "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.BeginPasskeyCeremonyResponse" + } + } + } + } + } + } + }, + "/spin.v1.PasskeyService/DeletePasskey": { + "post": { + "tags": [ + "PasskeyService" + ], + "summary": "DeletePasskey", + "description": "Deletes a passkey of the caller's, with an assertion of one of theirs.", + "operationId": "spin.v1.PasskeyService.DeletePasskey", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6287,7 +7155,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SearchWorkspaceLogsRequest" + "$ref": "#/components/schemas/spin.v1.DeletePasskeyRequest" } } }, @@ -6309,7 +7177,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SearchWorkspaceLogsResponse" + "$ref": "#/components/schemas/spin.v1.DeletePasskeyResponse" } } } @@ -6317,14 +7185,13 @@ } } }, - "/spin.v1.LogService/SearchWorkspaceTraces": { + "/spin.v1.PasskeyService/ListPasskeys": { "post": { "tags": [ - "LogService" + "PasskeyService" ], - "summary": "SearchWorkspaceTraces", - "description": "SearchWorkspaceTraces is the spans marked as about one workspace - its creation, its starts\n and stops, what its host did for it - newest first, for its owner. A trace names every\n workspace it touched, so a span not marked as this one's is never answered, whichever trace\n it is in.", - "operationId": "spin.v1.LogService.SearchWorkspaceTraces", + "summary": "ListPasskeys", + "operationId": "spin.v1.PasskeyService.ListPasskeys", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6349,7 +7216,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SearchWorkspaceTracesRequest" + "$ref": "#/components/schemas/spin.v1.ListPasskeysRequest" } } }, @@ -6371,7 +7238,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.SearchWorkspaceTracesResponse" + "$ref": "#/components/schemas/spin.v1.ListPasskeysResponse" } } } @@ -6379,14 +7246,14 @@ } } }, - "/spin.v1.LogService/ServiceHealth": { + "/spin.v1.PasskeyService/RegisterPasskey": { "post": { "tags": [ - "LogService" + "PasskeyService" ], - "summary": "ServiceHealth", - "description": "ServiceHealth is how each of the installation's services did over a window, as its traces\n and logs say it. An administrator's, as the traces are.", - "operationId": "spin.v1.LogService.ServiceHealth", + "summary": "RegisterPasskey", + "description": "Registers a passkey to the caller's account. The first is registered on their session alone;\n another takes an assertion of one they have, so a session cannot add a passkey of its own.", + "operationId": "spin.v1.PasskeyService.RegisterPasskey", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6411,7 +7278,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ServiceHealthRequest" + "$ref": "#/components/schemas/spin.v1.RegisterPasskeyRequest" } } }, @@ -6433,7 +7300,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ServiceHealthResponse" + "$ref": "#/components/schemas/spin.v1.RegisterPasskeyResponse" } } } @@ -6441,14 +7308,13 @@ } } }, - "/spin.v1.LogService/WorkspaceLogFieldValues": { + "/spin.v1.ProjectService/CreateProject": { "post": { "tags": [ - "LogService" + "ProjectService" ], - "summary": "WorkspaceLogFieldValues", - "description": "WorkspaceLogFieldValues is the same of one workspace's, for whoever may read it.", - "operationId": "spin.v1.LogService.WorkspaceLogFieldValues", + "summary": "CreateProject", + "operationId": "spin.v1.ProjectService.CreateProject", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6473,7 +7339,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.WorkspaceLogFieldValuesRequest" + "$ref": "#/components/schemas/spin.v1.CreateProjectRequest" } } }, @@ -6495,7 +7361,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.WorkspaceLogFieldValuesResponse" + "$ref": "#/components/schemas/spin.v1.CreateProjectResponse" } } } @@ -6503,14 +7369,13 @@ } } }, - "/spin.v1.PasskeyService/BeginPasskeyCeremony": { + "/spin.v1.ProjectService/DeleteProject": { "post": { "tags": [ - "PasskeyService" + "ProjectService" ], - "summary": "BeginPasskeyCeremony", - "description": "A challenge for one ceremony of the caller's, bound to what it is for: a passkey registered, a\n key added, a passkey deleted. Taken once, by the call it is answered in, within minutes.", - "operationId": "spin.v1.PasskeyService.BeginPasskeyCeremony", + "summary": "DeleteProject", + "operationId": "spin.v1.ProjectService.DeleteProject", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6535,7 +7400,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.BeginPasskeyCeremonyRequest" + "$ref": "#/components/schemas/spin.v1.DeleteProjectRequest" } } }, @@ -6557,7 +7422,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.BeginPasskeyCeremonyResponse" + "$ref": "#/components/schemas/spin.v1.DeleteProjectResponse" } } } @@ -6565,14 +7430,14 @@ } } }, - "/spin.v1.PasskeyService/DeletePasskey": { + "/spin.v1.ProjectService/GetPrebuild": { "post": { "tags": [ - "PasskeyService" + "ProjectService" ], - "summary": "DeletePasskey", - "description": "Deletes a passkey of the caller's, with an assertion of one of theirs.", - "operationId": "spin.v1.PasskeyService.DeletePasskey", + "summary": "GetPrebuild", + "description": "One of them whole, with what its build's create tasks wrote, to whoever sees the project.", + "operationId": "spin.v1.ProjectService.GetPrebuild", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6597,7 +7462,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.DeletePasskeyRequest" + "$ref": "#/components/schemas/spin.v1.GetPrebuildRequest" } } }, @@ -6619,7 +7484,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.DeletePasskeyResponse" + "$ref": "#/components/schemas/spin.v1.GetPrebuildResponse" } } } @@ -6627,13 +7492,13 @@ } } }, - "/spin.v1.PasskeyService/ListPasskeys": { + "/spin.v1.ProjectService/GetProject": { "post": { "tags": [ - "PasskeyService" + "ProjectService" ], - "summary": "ListPasskeys", - "operationId": "spin.v1.PasskeyService.ListPasskeys", + "summary": "GetProject", + "operationId": "spin.v1.ProjectService.GetProject", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6658,7 +7523,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListPasskeysRequest" + "$ref": "#/components/schemas/spin.v1.GetProjectRequest" } } }, @@ -6680,7 +7545,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListPasskeysResponse" + "$ref": "#/components/schemas/spin.v1.GetProjectResponse" } } } @@ -6688,14 +7553,14 @@ } } }, - "/spin.v1.PasskeyService/RegisterPasskey": { + "/spin.v1.ProjectService/ListPrebuilds": { "post": { "tags": [ - "PasskeyService" + "ProjectService" ], - "summary": "RegisterPasskey", - "description": "Registers a passkey to the caller's account. The first is registered on their session alone;\n another takes an assertion of one they have, so a session cannot add a passkey of its own.", - "operationId": "spin.v1.PasskeyService.RegisterPasskey", + "summary": "ListPrebuilds", + "description": "A project's prebuilds, to whoever sees it; and a build of one of its refs now, by its admins,\n rather than at the next look.", + "operationId": "spin.v1.ProjectService.ListPrebuilds", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6720,7 +7585,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RegisterPasskeyRequest" + "$ref": "#/components/schemas/spin.v1.ListPrebuildsRequest" } } }, @@ -6742,7 +7607,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RegisterPasskeyResponse" + "$ref": "#/components/schemas/spin.v1.ListPrebuildsResponse" } } } @@ -6750,13 +7615,14 @@ } } }, - "/spin.v1.ProjectService/CreateProject": { + "/spin.v1.ProjectService/ListProjectWorkspaces": { "post": { "tags": [ "ProjectService" ], - "summary": "CreateProject", - "operationId": "spin.v1.ProjectService.CreateProject", + "summary": "ListProjectWorkspaces", + "description": "Everybody's workspaces open on a project, to its admins and nobody else: a person it is only\n shared with is refused, and reads their own with ListWorkspaces.", + "operationId": "spin.v1.ProjectService.ListProjectWorkspaces", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6781,7 +7647,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CreateProjectRequest" + "$ref": "#/components/schemas/spin.v1.ListProjectWorkspacesRequest" } } }, @@ -6803,7 +7669,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CreateProjectResponse" + "$ref": "#/components/schemas/spin.v1.ListProjectWorkspacesResponse" } } } @@ -6811,13 +7677,13 @@ } } }, - "/spin.v1.ProjectService/DeleteProject": { + "/spin.v1.ProjectService/ListProjects": { "post": { "tags": [ "ProjectService" ], - "summary": "DeleteProject", - "operationId": "spin.v1.ProjectService.DeleteProject", + "summary": "ListProjects", + "operationId": "spin.v1.ProjectService.ListProjects", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6842,7 +7708,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.DeleteProjectRequest" + "$ref": "#/components/schemas/spin.v1.ListProjectsRequest" } } }, @@ -6864,7 +7730,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.DeleteProjectResponse" + "$ref": "#/components/schemas/spin.v1.ListProjectsResponse" } } } @@ -6872,13 +7738,13 @@ } } }, - "/spin.v1.ProjectService/GetProject": { + "/spin.v1.ProjectService/RunPrebuild": { "post": { "tags": [ "ProjectService" ], - "summary": "GetProject", - "operationId": "spin.v1.ProjectService.GetProject", + "summary": "RunPrebuild", + "operationId": "spin.v1.ProjectService.RunPrebuild", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6903,7 +7769,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetProjectRequest" + "$ref": "#/components/schemas/spin.v1.RunPrebuildRequest" } } }, @@ -6925,7 +7791,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetProjectResponse" + "$ref": "#/components/schemas/spin.v1.RunPrebuildResponse" } } } @@ -6933,14 +7799,13 @@ } } }, - "/spin.v1.ProjectService/ListPrebuilds": { + "/spin.v1.ProjectService/ShareProject": { "post": { "tags": [ "ProjectService" ], - "summary": "ListPrebuilds", - "description": "A project's prebuilds, to whoever sees it; and a build of one of its refs now, by its admins,\n rather than at the next look.", - "operationId": "spin.v1.ProjectService.ListPrebuilds", + "summary": "ShareProject", + "operationId": "spin.v1.ProjectService.ShareProject", "parameters": [ { "name": "Connect-Protocol-Version", @@ -6965,7 +7830,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListPrebuildsRequest" + "$ref": "#/components/schemas/spin.v1.ShareProjectRequest" } } }, @@ -6987,7 +7852,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListPrebuildsResponse" + "$ref": "#/components/schemas/spin.v1.ShareProjectResponse" } } } @@ -6995,13 +7860,14 @@ } } }, - "/spin.v1.ProjectService/ListProjects": { + "/spin.v1.ProjectService/UpdateProject": { "post": { "tags": [ "ProjectService" ], - "summary": "ListProjects", - "operationId": "spin.v1.ProjectService.ListProjects", + "summary": "UpdateProject", + "description": "Changed, shared and deleted by its admins. A project with a workspace open on it is not\n deleted.", + "operationId": "spin.v1.ProjectService.UpdateProject", "parameters": [ { "name": "Connect-Protocol-Version", @@ -7026,7 +7892,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListProjectsRequest" + "$ref": "#/components/schemas/spin.v1.UpdateProjectRequest" } } }, @@ -7048,7 +7914,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListProjectsResponse" + "$ref": "#/components/schemas/spin.v1.UpdateProjectResponse" } } } @@ -7056,13 +7922,14 @@ } } }, - "/spin.v1.ProjectService/RunPrebuild": { + "/spin.v1.RunnerTokenService/CreateRegistrationToken": { "post": { "tags": [ - "ProjectService" + "RunnerTokenService" ], - "summary": "RunPrebuild", - "operationId": "spin.v1.ProjectService.RunPrebuild", + "summary": "CreateRegistrationToken", + "description": "Generate a one-time registration token (admin only)", + "operationId": "spin.v1.RunnerTokenService.CreateRegistrationToken", "parameters": [ { "name": "Connect-Protocol-Version", @@ -7087,7 +7954,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RunPrebuildRequest" + "$ref": "#/components/schemas/spin.v1.CreateRegistrationTokenRequest" } } }, @@ -7109,7 +7976,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RunPrebuildResponse" + "$ref": "#/components/schemas/spin.v1.CreateRegistrationTokenResponse" } } } @@ -7117,13 +7984,14 @@ } } }, - "/spin.v1.ProjectService/ShareProject": { + "/spin.v1.RunnerTokenService/ListRegistrationTokens": { "post": { "tags": [ - "ProjectService" + "RunnerTokenService" ], - "summary": "ShareProject", - "operationId": "spin.v1.ProjectService.ShareProject", + "summary": "ListRegistrationTokens", + "description": "List active registration tokens (admin only)", + "operationId": "spin.v1.RunnerTokenService.ListRegistrationTokens", "parameters": [ { "name": "Connect-Protocol-Version", @@ -7148,7 +8016,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ShareProjectRequest" + "$ref": "#/components/schemas/spin.v1.ListRegistrationTokensRequest" } } }, @@ -7170,7 +8038,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ShareProjectResponse" + "$ref": "#/components/schemas/spin.v1.ListRegistrationTokensResponse" } } } @@ -7178,14 +8046,14 @@ } } }, - "/spin.v1.ProjectService/UpdateProject": { + "/spin.v1.RunnerTokenService/RevokeRegistrationToken": { "post": { "tags": [ - "ProjectService" + "RunnerTokenService" ], - "summary": "UpdateProject", - "description": "Changed, shared and deleted by its admins. A project with a workspace open on it is not\n deleted.", - "operationId": "spin.v1.ProjectService.UpdateProject", + "summary": "RevokeRegistrationToken", + "description": "Revoke a registration token (admin only)", + "operationId": "spin.v1.RunnerTokenService.RevokeRegistrationToken", "parameters": [ { "name": "Connect-Protocol-Version", @@ -7210,7 +8078,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateProjectRequest" + "$ref": "#/components/schemas/spin.v1.RevokeRegistrationTokenRequest" } } }, @@ -7232,7 +8100,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.UpdateProjectResponse" + "$ref": "#/components/schemas/spin.v1.RevokeRegistrationTokenResponse" } } } @@ -7240,14 +8108,14 @@ } } }, - "/spin.v1.RunnerTokenService/CreateRegistrationToken": { + "/spin.v1.RunnerTokenService/RevokeRunner": { "post": { "tags": [ "RunnerTokenService" ], - "summary": "CreateRegistrationToken", - "description": "Generate a one-time registration token (admin only)", - "operationId": "spin.v1.RunnerTokenService.CreateRegistrationToken", + "summary": "RevokeRunner", + "description": "Revoke a runner (admin only)", + "operationId": "spin.v1.RunnerTokenService.RevokeRunner", "parameters": [ { "name": "Connect-Protocol-Version", @@ -7272,7 +8140,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CreateRegistrationTokenRequest" + "$ref": "#/components/schemas/spin.v1.RevokeRunnerRequest" } } }, @@ -7294,7 +8162,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.CreateRegistrationTokenResponse" + "$ref": "#/components/schemas/spin.v1.RevokeRunnerResponse" } } } @@ -7302,14 +8170,14 @@ } } }, - "/spin.v1.RunnerTokenService/ListRegistrationTokens": { + "/spin.v1.SSHKeyService/AddSSHKey": { "post": { "tags": [ - "RunnerTokenService" + "SSHKeyService" ], - "summary": "ListRegistrationTokens", - "description": "List active registration tokens (admin only)", - "operationId": "spin.v1.RunnerTokenService.ListRegistrationTokens", + "summary": "AddSSHKey", + "description": "Adds a key, with an assertion of a passkey of the caller's over a PASSKEY_PURPOSE_ADD_SSH_KEY\n challenge naming it.", + "operationId": "spin.v1.SSHKeyService.AddSSHKey", "parameters": [ { "name": "Connect-Protocol-Version", @@ -7334,7 +8202,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListRegistrationTokensRequest" + "$ref": "#/components/schemas/spin.v1.AddSSHKeyRequest" } } }, @@ -7356,7 +8224,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListRegistrationTokensResponse" + "$ref": "#/components/schemas/spin.v1.AddSSHKeyResponse" } } } @@ -7364,14 +8232,14 @@ } } }, - "/spin.v1.RunnerTokenService/RevokeRegistrationToken": { + "/spin.v1.SSHKeyService/DeleteSSHKey": { "post": { "tags": [ - "RunnerTokenService" + "SSHKeyService" ], - "summary": "RevokeRegistrationToken", - "description": "Revoke a registration token (admin only)", - "operationId": "spin.v1.RunnerTokenService.RevokeRegistrationToken", + "summary": "DeleteSSHKey", + "description": "Delete an SSH key from user's account", + "operationId": "spin.v1.SSHKeyService.DeleteSSHKey", "parameters": [ { "name": "Connect-Protocol-Version", @@ -7396,7 +8264,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeRegistrationTokenRequest" + "$ref": "#/components/schemas/spin.v1.DeleteSSHKeyRequest" } } }, @@ -7418,7 +8286,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeRegistrationTokenResponse" + "$ref": "#/components/schemas/spin.v1.DeleteSSHKeyResponse" } } } @@ -7426,14 +8294,14 @@ } } }, - "/spin.v1.RunnerTokenService/RevokeRunner": { + "/spin.v1.SSHKeyService/ListSSHKeys": { "post": { "tags": [ - "RunnerTokenService" + "SSHKeyService" ], - "summary": "RevokeRunner", - "description": "Revoke a runner (admin only)", - "operationId": "spin.v1.RunnerTokenService.RevokeRunner", + "summary": "ListSSHKeys", + "description": "List user's SSH public keys", + "operationId": "spin.v1.SSHKeyService.ListSSHKeys", "parameters": [ { "name": "Connect-Protocol-Version", @@ -7458,7 +8326,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeRunnerRequest" + "$ref": "#/components/schemas/spin.v1.ListSSHKeysRequest" } } }, @@ -7480,7 +8348,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.RevokeRunnerResponse" + "$ref": "#/components/schemas/spin.v1.ListSSHKeysResponse" } } } @@ -7488,14 +8356,14 @@ } } }, - "/spin.v1.SSHKeyService/AddSSHKey": { + "/spin.v1.SettingsService/GetNotificationPreferences": { "post": { "tags": [ - "SSHKeyService" + "SettingsService" ], - "summary": "AddSSHKey", - "description": "Adds a key, with an assertion of a passkey of the caller's over a PASSKEY_PURPOSE_ADD_SSH_KEY\n challenge naming it.", - "operationId": "spin.v1.SSHKeyService.AddSSHKey", + "summary": "GetNotificationPreferences", + "description": "Which of those the caller is emailed about.", + "operationId": "spin.v1.SettingsService.GetNotificationPreferences", "parameters": [ { "name": "Connect-Protocol-Version", @@ -7520,7 +8388,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.AddSSHKeyRequest" + "$ref": "#/components/schemas/spin.v1.GetNotificationPreferencesRequest" } } }, @@ -7542,7 +8410,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.AddSSHKeyResponse" + "$ref": "#/components/schemas/spin.v1.GetNotificationPreferencesResponse" } } } @@ -7550,14 +8418,14 @@ } } }, - "/spin.v1.SSHKeyService/DeleteSSHKey": { + "/spin.v1.SettingsService/GetUserSettings": { "post": { "tags": [ - "SSHKeyService" + "SettingsService" ], - "summary": "DeleteSSHKey", - "description": "Delete an SSH key from user's account", - "operationId": "spin.v1.SSHKeyService.DeleteSSHKey", + "summary": "GetUserSettings", + "description": "User settings", + "operationId": "spin.v1.SettingsService.GetUserSettings", "parameters": [ { "name": "Connect-Protocol-Version", @@ -7582,7 +8450,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.DeleteSSHKeyRequest" + "$ref": "#/components/schemas/spin.v1.GetUserSettingsRequest" } } }, @@ -7604,7 +8472,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.DeleteSSHKeyResponse" + "$ref": "#/components/schemas/spin.v1.GetUserSettingsResponse" } } } @@ -7612,14 +8480,14 @@ } } }, - "/spin.v1.SSHKeyService/ListSSHKeys": { + "/spin.v1.SettingsService/ListNotifications": { "post": { "tags": [ - "SSHKeyService" + "SettingsService" ], - "summary": "ListSSHKeys", - "description": "List user's SSH public keys", - "operationId": "spin.v1.SSHKeyService.ListSSHKeys", + "summary": "ListNotifications", + "description": "What happened to the caller's workspaces that they are told of, newest first, with whether\n each was sent and how. Recorded whether or not the installation can send email.", + "operationId": "spin.v1.SettingsService.ListNotifications", "parameters": [ { "name": "Connect-Protocol-Version", @@ -7644,7 +8512,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListSSHKeysRequest" + "$ref": "#/components/schemas/spin.v1.ListNotificationsRequest" } } }, @@ -7666,7 +8534,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.ListSSHKeysResponse" + "$ref": "#/components/schemas/spin.v1.ListNotificationsResponse" } } } @@ -7674,14 +8542,13 @@ } } }, - "/spin.v1.SettingsService/GetUserSettings": { + "/spin.v1.SettingsService/UpdateNotificationPreferences": { "post": { "tags": [ "SettingsService" ], - "summary": "GetUserSettings", - "description": "User settings", - "operationId": "spin.v1.SettingsService.GetUserSettings", + "summary": "UpdateNotificationPreferences", + "operationId": "spin.v1.SettingsService.UpdateNotificationPreferences", "parameters": [ { "name": "Connect-Protocol-Version", @@ -7706,7 +8573,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetUserSettingsRequest" + "$ref": "#/components/schemas/spin.v1.UpdateNotificationPreferencesRequest" } } }, @@ -7728,7 +8595,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/spin.v1.GetUserSettingsResponse" + "$ref": "#/components/schemas/spin.v1.UpdateNotificationPreferencesResponse" } } } @@ -9778,7 +10645,7 @@ "WorkspaceService" ], "summary": "AttachVSCodeServer", - "description": "Give a running workspace the VS Code server of a client's commit, while it runs: published\n first when this installation has not got it and fetches servers on its own\n (InstallationSettings.vscode_fetch), refused as FAILED_PRECONDITION when it does not. Asked\n again until it answers attached.", + "description": "Give a running workspace the VS Code server of a client's commit, while it runs: published\n first when this installation has not got it and an administrator accepted the VS Code\n server's terms (AdminService.AcceptThirdPartyTerms), refused as FAILED_PRECONDITION, saying\n so, when nobody did. Asked again until it answers attached.", "operationId": "spin.v1.WorkspaceService.AttachVSCodeServer", "parameters": [ { @@ -13235,6 +14102,30 @@ "title": "APIKey", "additionalProperties": false }, + "spin.v1.AcceptThirdPartyTermsRequest": { + "type": "object", + "properties": { + "termsVersion": { + "type": "string", + "title": "terms_version", + "description": "The version of the text the administrator was shown: one that is not the current one is\n refused, so nobody accepts a text they did not read." + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.ThirdPartyItem" + }, + "title": "items" + } + }, + "title": "AcceptThirdPartyTermsRequest", + "additionalProperties": false + }, + "spin.v1.AcceptThirdPartyTermsResponse": { + "type": "object", + "title": "AcceptThirdPartyTermsResponse", + "additionalProperties": false + }, "spin.v1.ActivateHostRequest": { "type": "object", "properties": { @@ -13737,6 +14628,11 @@ "type": "boolean", "title": "removable", "description": "No disk was cloned from it and it is not the one given: RemoveStoredVolume untags it on the\n way and removes it." + }, + "keptBecause": { + "type": "string", + "title": "kept_because", + "description": "Why it stays, in words, where it may not go." } }, "title": "BaseImage", @@ -14697,6 +15593,12 @@ "title": "prebuild_rebase_every", "format": "int32", "description": "Zero is the installation's default" + }, + "prebuildKeep": { + "type": "integer", + "title": "prebuild_keep", + "format": "int32", + "description": "Zero is one: the newest of each ref" } }, "title": "CreateProjectRequest", @@ -15053,7 +15955,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 installation's default preset, or with none marked\n 1 core, 512 MB and 10 GB free. A 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, 512 MB and 10 GB free. A\n disabled preset is refused." }, "env": { "type": "object", @@ -15080,7 +15982,7 @@ "projectId": { "type": "string", "title": "project_id", - "description": "A project the caller sees: the workspace is the project's - its image, preset and tags, which\n the request then names none of - in team_id, the caller's personal team when empty, and its\n guest clones the project's repository at ref, the project's own when empty. Refused while the\n repository is on a forge the installation connects to (ForgeService) and the caller has not\n connected their account there." + "description": "A project the caller sees: the workspace is the project's - its image and tags, which the\n request then names neither of, and its preset unless preset names another - in team_id, the\n caller's personal team when empty, and its\n guest clones the project's repository at ref, the project's own when empty. Refused while the\n repository is on a forge the installation connects to (ForgeService) and the caller has not\n connected their account there." }, "ref": { "type": "string", @@ -15623,6 +16525,37 @@ "title": "DrainHostResponse", "additionalProperties": false }, + "spin.v1.EmailSettings": { + "type": "object", + "properties": { + "host": { + "type": "string", + "title": "host" + }, + "port": { + "type": "integer", + "title": "port", + "format": "int32", + "description": "465 is TLS from the first byte; any other port is upgraded with STARTTLS where the server\n offers it, and a username is refused over a connection that is not encrypted." + }, + "username": { + "type": "string", + "title": "username" + }, + "passwordSet": { + "type": "boolean", + "title": "password_set" + }, + "from": { + "type": "string", + "title": "from", + "description": "The address mail is sent from, as the server allows this account to send." + } + }, + "title": "EmailSettings", + "additionalProperties": false, + "description": "EmailSettings is the SMTP server the installation sends its notifications through. No host is\n email off: what would have been sent is still recorded, and shown on each person's page." + }, "spin.v1.EnableDevModeRequest": { "type": "object", "title": "EnableDevModeRequest", @@ -15893,6 +16826,21 @@ "type": "boolean", "title": "newest", "description": "Whether a start is given this one." + }, + "volumeId": { + "type": "string", + "title": "volume_id", + "description": "Its volume in the store, which RemoveStoredVolume takes when removable." + }, + "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." + }, + "keptBecause": { + "type": "string", + "title": "kept_because", + "description": "Why it stays, in words, where it may not go." } }, "title": "ExtensionRelease", @@ -16118,7 +17066,7 @@ "type": "integer", "title": "busy", "format": "int32", - "description": "Workspaces of the class keeping its group up." + "description": "Workspaces of the class, and hosts a root shell holds, keeping its group up." }, "launchFailure": { "type": "string", @@ -16132,6 +17080,19 @@ } ], "title": "launch_failed_at" + }, + "giveBackRefused": { + "type": "string", + "title": "give_back_refused", + "description": "A machine of the group the cloud would not take back, in its own words - a role or a policy\n somebody has to change - and when; it is asked again every quarter hour until it is taken.\n Empty while none is refused." + }, + "giveBackRefusedAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "give_back_refused_at" } }, "title": "FleetClass", @@ -16489,6 +17450,26 @@ "title": "GetCurrentUserResponse", "additionalProperties": false }, + "spin.v1.GetEmailSettingsRequest": { + "type": "object", + "title": "GetEmailSettingsRequest", + "additionalProperties": false + }, + "spin.v1.GetEmailSettingsResponse": { + "type": "object", + "properties": { + "settings": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.EmailSettings" + } + ], + "title": "settings" + } + }, + "title": "GetEmailSettingsResponse", + "additionalProperties": false + }, "spin.v1.GetFleetRequest": { "type": "object", "title": "GetFleetRequest", @@ -16721,6 +17702,34 @@ } ], "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", @@ -16747,6 +17756,30 @@ "title": "GetMonitoringResponse", "additionalProperties": false }, + "spin.v1.GetNotificationPreferencesRequest": { + "type": "object", + "title": "GetNotificationPreferencesRequest", + "additionalProperties": false + }, + "spin.v1.GetNotificationPreferencesResponse": { + "type": "object", + "properties": { + "preferences": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.NotificationPreference" + }, + "title": "preferences", + "description": "One per event a person may be told of, in the order they are shown." + }, + "emailConfigured": { + "type": "boolean", + "title": "email_configured" + } + }, + "title": "GetNotificationPreferencesResponse", + "additionalProperties": false + }, "spin.v1.GetPlatformImagesRequest": { "type": "object", "title": "GetPlatformImagesRequest", @@ -16791,6 +17824,37 @@ "title": "GetPlatformImagesResponse", "additionalProperties": false }, + "spin.v1.GetPrebuildRequest": { + "type": "object", + "properties": { + "projectId": { + "type": "string", + "title": "project_id" + }, + "prebuildId": { + "type": "string", + "title": "prebuild_id" + } + }, + "title": "GetPrebuildRequest", + "additionalProperties": false, + "description": "A prebuild by its id, of the project it names: one of another project is not found." + }, + "spin.v1.GetPrebuildResponse": { + "type": "object", + "properties": { + "prebuild": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.Prebuild" + } + ], + "title": "prebuild" + } + }, + "title": "GetPrebuildResponse", + "additionalProperties": false + }, "spin.v1.GetProjectRequest": { "type": "object", "properties": { @@ -16842,6 +17906,42 @@ "title": "GetRegistrationModeResponse", "additionalProperties": false }, + "spin.v1.GetRunbookRequest": { + "type": "object", + "properties": { + "id": { + "type": "string", + "title": "id" + } + }, + "title": "GetRunbookRequest", + "additionalProperties": false + }, + "spin.v1.GetRunbookResponse": { + "type": "object", + "properties": { + "runbook": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.Runbook" + } + ], + "title": "runbook" + }, + "markdown": { + "type": "string", + "title": "markdown", + "description": "Its body, markdown without the front matter: the app renders it and nothing else (no raw HTML)." + }, + "sourceUrl": { + "type": "string", + "title": "source_url", + "description": "The file at the commit this release pins, to propose a change from." + } + }, + "title": "GetRunbookResponse", + "additionalProperties": false + }, "spin.v1.GetSecuritySettingsRequest": { "type": "object", "title": "GetSecuritySettingsRequest", @@ -16923,6 +18023,11 @@ "type": "boolean", "title": "development", "description": "True for a development installation, where the mock identity provider may be enabled." + }, + "thirdPartyAccepted": { + "type": "boolean", + "title": "third_party_accepted", + "description": "True where an administrator accepted the terms of any third-party software, as the current\n text: the wizard asks until one has, or until it is told to go on without." } }, "title": "GetSetupStatusResponse", @@ -17080,6 +18185,38 @@ "title": "GetTelemetryStatusResponse", "additionalProperties": false }, + "spin.v1.GetThirdPartyTermsRequest": { + "type": "object", + "title": "GetThirdPartyTermsRequest", + "additionalProperties": false + }, + "spin.v1.GetThirdPartyTermsResponse": { + "type": "object", + "properties": { + "termsVersion": { + "type": "string", + "title": "terms_version", + "description": "The version of the text below, which an acceptance names." + }, + "text": { + "type": "array", + "items": { + "type": "string" + }, + "title": "text", + "description": "The terms, a paragraph each." + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.ThirdPartyTermsItem" + }, + "title": "items" + } + }, + "title": "GetThirdPartyTermsResponse", + "additionalProperties": false + }, "spin.v1.GetTraceRequest": { "type": "object", "properties": { @@ -17335,6 +18472,37 @@ "title": "GetWorkspaceIdentityResponse", "additionalProperties": false }, + "spin.v1.GetWorkspaceNamesRequest": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "string" + }, + "title": "ids", + "description": "At most 500: the ids a page of records names." + } + }, + "title": "GetWorkspaceNamesRequest", + "additionalProperties": false + }, + "spin.v1.GetWorkspaceNamesResponse": { + "type": "object", + "properties": { + "names": { + "type": "object", + "title": "names", + "additionalProperties": { + "type": "string", + "title": "value" + }, + "description": "Each id asked for that the installation holds a row for, to its workspace's name." + } + }, + "title": "GetWorkspaceNamesResponse", + "additionalProperties": false + }, "spin.v1.GetWorkspaceRequest": { "type": "object", "properties": { @@ -18099,6 +19267,20 @@ "type": "string", "title": "hostname", "description": "hostname is the name the host's machine goes by, as it last registered it: how a person tells\n one host from another where its id says nothing. Empty for a host that has not registered\n since it was made." + }, + "removal": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.HostRemoval" + } + ], + "title": "removal", + "description": "removal is how this host leaves the fleet, decided by where it came from: the only removal\n the API takes for it, so the dashboard offers that one and no other." + }, + "removalRefused": { + "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." } }, "title": "Host", @@ -18339,6 +19521,23 @@ "additionalProperties": false, "description": "HostPolicy is what an installation decides about one host. An unset field is the\n installation saying nothing about that setting, which leaves the host on its own default -\n not the same as setting it to nothing." }, + "spin.v1.HostRemoval": { + "type": "string", + "title": "HostRemoval", + "enum": [ + "HOST_REMOVAL_UNSPECIFIED", + "HOST_REMOVAL_REVOKE", + "HOST_REMOVAL_GIVE_BACK", + "HOST_REMOVAL_FORGET" + ], + "description": "HostRemoval is how a host leaves the fleet.\n\n- `HOST_REMOVAL_REVOKE`: A host registered with a token, or a machine of a cloud no group of this installation sizes:\n RevokeRunner. Nothing else can take its machine away.\n- `HOST_REMOVAL_GIVE_BACK`: A machine of an autoscaling group, connected: RemoveHost gives it back to its group, which\n terminates it and is asked for one less. Revoking it would leave the machine running and\n paid for, in a group that counts it.\n- `HOST_REMOVAL_FORGET`: A machine of an autoscaling group, not connected: RemoveHost gives back a machine the group\n still has, and forgets the host now rather than once it has been silent for\n host_forget_after_hours.", + "x-enum-descriptions": [ + "", + "A host registered with a token, or a machine of a cloud no group of this installation sizes:\n RevokeRunner. Nothing else can take its machine away.", + "A machine of an autoscaling group, connected: RemoveHost gives it back to its group, which\n terminates it and is asked for one less. Revoking it would leave the machine running and\n paid for, in a group that counts it.", + "A machine of an autoscaling group, not connected: RemoveHost gives back a machine the group\n still has, and forgets the host now rather than once it has been silent for\n host_forget_after_hours." + ] + }, "spin.v1.HostShell": { "type": "object", "properties": { @@ -18662,11 +19861,6 @@ "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." }, - "vscodeFetch": { - "type": "boolean", - "title": "vscode_fetch", - "description": "Whether the control plane fetches VS Code servers from Microsoft on its own: the release it\n pins, at start, the newest stable release, looked for daily, and the server of a client's\n commit the installation has not released. False, it fetches none, and a workspace is given\n a server an administrator published; no image carries one." - }, "workspaceTrashDays": { "type": "integer", "title": "workspace_trash_days", @@ -18721,11 +19915,6 @@ "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." }, - "agentsFetch": { - "type": "boolean", - "title": "agents_fetch", - "description": "Whether the control plane fetches the agents' programs - Claude Code, Codex and T3 Code -\n from their publishers on its own: the triple it pins, at start, and the newest release of\n each, looked for daily. False, it fetches none, and a workspace is given a triple an operator\n published; no image carries one." - }, "projectCreation": { "type": "string", "title": "project_creation", @@ -18813,6 +20002,24 @@ } ], "title": "last_succeeded_at" + }, + "title": { + "type": "string", + "title": "title", + "description": "The job as a person names it: \"Storage collection\" for storage-gc." + }, + "purpose": { + "type": "string", + "title": "purpose", + "description": "One sentence of what it does and what stays undone while it fails." + }, + "recentRuns": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.JobRun" + }, + "title": "recent_runs", + "description": "Its newest runs, newest first, at most twenty: what a list of jobs shows each one's recent\n outcomes and durations from, without asking for every job's runs. Each has its id, start,\n end and outcome only; ListJobRuns has the rest." } }, "title": "Job", @@ -19499,7 +20706,31 @@ "format": "int32" } }, - "title": "ListNetworkPoliciesResponse", + "title": "ListNetworkPoliciesResponse", + "additionalProperties": false + }, + "spin.v1.ListNotificationsRequest": { + "type": "object", + "title": "ListNotificationsRequest", + "additionalProperties": false + }, + "spin.v1.ListNotificationsResponse": { + "type": "object", + "properties": { + "notifications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.Notification" + }, + "title": "notifications" + }, + "emailConfigured": { + "type": "boolean", + "title": "email_configured", + "description": "Whether the installation can send email at all." + } + }, + "title": "ListNotificationsResponse", "additionalProperties": false }, "spin.v1.ListPasskeysRequest": { @@ -19542,11 +20773,60 @@ }, "title": "prebuilds", "description": "Newest first." + }, + "storageMeasuredAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "storage_measured_at", + "description": "When storage-gc last read the store, which each stored_bytes is as of; unset before it has." + }, + "retireUnusedDays": { + "type": "integer", + "title": "retire_unused_days", + "format": "int32", + "description": "The installation's prebuild_retire_unused_days: a ready prebuild nobody opened a workspace\n from in this many days is retired, its ref's newest included. Zero retires none for that." + }, + "refsNotFound": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.PrebuildRefNotFound" + }, + "title": "refs_not_found", + "description": "The refs the project prebuilds that its forge says the repository has not - a branch deleted\n since it was named - as the prebuilds job last found them: nothing is built of one until the\n forge has it again or the project names it no longer." } }, "title": "ListPrebuildsResponse", "additionalProperties": false }, + "spin.v1.ListProjectWorkspacesRequest": { + "type": "object", + "properties": { + "projectId": { + "type": "string", + "title": "project_id" + } + }, + "title": "ListProjectWorkspacesRequest", + "additionalProperties": false + }, + "spin.v1.ListProjectWorkspacesResponse": { + "type": "object", + "properties": { + "workspaces": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.ProjectWorkspace" + }, + "title": "workspaces", + "description": "Newest first, and at most 500. Not a prebuild's build, and not a deleted one." + } + }, + "title": "ListProjectWorkspacesResponse", + "additionalProperties": false + }, "spin.v1.ListProjectsRequest": { "type": "object", "title": "ListProjectsRequest", @@ -19669,6 +20949,25 @@ "title": "ListResourcePresetsResponse", "additionalProperties": false }, + "spin.v1.ListRunbooksRequest": { + "type": "object", + "title": "ListRunbooksRequest", + "additionalProperties": false + }, + "spin.v1.ListRunbooksResponse": { + "type": "object", + "properties": { + "runbooks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.Runbook" + }, + "title": "runbooks" + } + }, + "title": "ListRunbooksResponse", + "additionalProperties": false + }, "spin.v1.ListSSHKeysRequest": { "type": "object", "properties": { @@ -20104,6 +21403,15 @@ "title": "value" }, "description": "What each listed user still holds, by user id: what an administrator asks before taking\n access away. Kept off User, which other calls return without it." + }, + "refusedRemovals": { + "type": "object", + "title": "refused_removals", + "additionalProperties": { + "type": "string", + "title": "value" + }, + "description": "Why removing a listed user as an administrator, or disabling them, would be refused, by user\n id; absent where it would not be. The refusal is the database's (lockout), so a client that\n never reads this is refused the same." } }, "title": "ListUsersResponse", @@ -20632,6 +21940,152 @@ "additionalProperties": false, "description": "NetworkUsagePoint is what the machine's network carried over a step." }, + "spin.v1.Notification": { + "type": "object", + "properties": { + "id": { + "type": "string", + "title": "id", + "description": "The workspace event's id." + }, + "workspaceId": { + "type": "string", + "title": "workspace_id" + }, + "workspaceName": { + "type": "string", + "title": "workspace_name" + }, + "event": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.WorkspaceEventType" + } + ], + "title": "event" + }, + "createdAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "created_at" + }, + "subject": { + "type": "string", + "title": "subject", + "description": "One line saying what happened." + }, + "body": { + "type": "string", + "title": "body", + "description": "What happened, in full." + }, + "command": { + "type": "string", + "title": "command", + "description": "The command that does what the owner can do about it; empty where nothing is to be done." + }, + "deliveries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.NotificationDelivery" + }, + "title": "deliveries", + "description": "Empty where it was never sent: email off, or this kind turned off." + } + }, + "title": "Notification", + "additionalProperties": false, + "description": "Notification is one event of a workspace's timeline its owner is told of: what happened, and\n what they can do about it." + }, + "spin.v1.NotificationChannel": { + "type": "string", + "title": "NotificationChannel", + "enum": [ + "NOTIFICATION_CHANNEL_UNSPECIFIED", + "NOTIFICATION_CHANNEL_EMAIL" + ], + "description": "How a notification leaves the installation." + }, + "spin.v1.NotificationDelivery": { + "type": "object", + "properties": { + "channel": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.NotificationChannel" + } + ], + "title": "channel" + }, + "state": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.NotificationDeliveryState" + } + ], + "title": "state" + }, + "attempts": { + "type": "integer", + "title": "attempts", + "format": "int32" + }, + "lastError": { + "type": "string", + "title": "last_error", + "description": "What the last attempt that failed was told; empty once one succeeded." + }, + "sentAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "sent_at" + } + }, + "title": "NotificationDelivery", + "additionalProperties": false + }, + "spin.v1.NotificationDeliveryState": { + "type": "string", + "title": "NotificationDeliveryState", + "enum": [ + "NOTIFICATION_DELIVERY_STATE_UNSPECIFIED", + "NOTIFICATION_DELIVERY_STATE_PENDING", + "NOTIFICATION_DELIVERY_STATE_SENT", + "NOTIFICATION_DELIVERY_STATE_FAILED" + ], + "description": "Where one notification's delivery on one channel is.\n\n- `NOTIFICATION_DELIVERY_STATE_PENDING`: Not sent yet, or tried and to be tried again\n- `NOTIFICATION_DELIVERY_STATE_SENT`: The channel accepted it\n- `NOTIFICATION_DELIVERY_STATE_FAILED`: Every attempt failed; it is not tried again", + "x-enum-descriptions": [ + "", + "Not sent yet, or tried and to be tried again", + "The channel accepted it", + "Every attempt failed; it is not tried again" + ] + }, + "spin.v1.NotificationPreference": { + "type": "object", + "properties": { + "event": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.WorkspaceEventType" + } + ], + "title": "event" + }, + "email": { + "type": "boolean", + "title": "email" + } + }, + "title": "NotificationPreference", + "additionalProperties": false + }, "spin.v1.ObservedDestination": { "type": "object", "properties": { @@ -21191,7 +22645,7 @@ "log": { "type": "string", "title": "log", - "description": "The tail of what its build said, and why it failed." + "description": "The tail of what its build's create tasks wrote (GetPrebuild only), and why it failed." }, "error": { "type": "string", @@ -21218,12 +22672,56 @@ "title": "workspace_count", "format": "int32", "description": "In ListPrebuilds: the workspaces opened from it that are not deleted, whoever's they are." + }, + "reportedAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "reported_at", + "description": "When its build's guest said the checkout and create tasks were done; unset before it did." + }, + "spinYaml": { + "type": "boolean", + "title": "spin_yaml", + "description": "Whether the checkout had a .spin.yaml at its root, as the guest reported: without one the\n build is the clone alone, with no create tasks run. Read only with reported_at." + }, + "storedBytes": { + "type": [ + "string", + "null" + ], + "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." } }, "title": "Prebuild", "additionalProperties": false, "description": "A prebuild: one build of a project's ref at a commit, and the snapshot it left." }, + "spin.v1.PrebuildRefNotFound": { + "type": "object", + "properties": { + "ref": { + "type": "string", + "title": "ref" + }, + "since": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "since", + "description": "The job's first look that found it missing." + } + }, + "title": "PrebuildRefNotFound", + "additionalProperties": false, + "description": "A prebuild ref the project's forge has not." + }, "spin.v1.PrebuildState": { "type": "string", "title": "PrebuildState", @@ -21374,16 +22872,107 @@ }, "title": "shared_team_ids" }, - "readyPrebuildCount": { - "type": "integer", - "title": "ready_prebuild_count", - "format": "int32", - "description": "In ListProjects: how many of its prebuilds are ready to open from." + "readyPrebuildCount": { + "type": "integer", + "title": "ready_prebuild_count", + "format": "int32", + "description": "In ListProjects: how many of its prebuilds are ready to open from." + }, + "prebuildKeep": { + "type": "integer", + "title": "prebuild_keep", + "format": "int32", + "description": "How many of each ref's newest ready prebuilds are kept when no workspace was opened from them." + }, + "timeToReady": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.ProjectTimeToReady" + } + ], + "title": "time_to_ready", + "description": "In GetProject: how long its workspaces took to be ready. Unset where none has been." + } + }, + "title": "Project", + "additionalProperties": false, + "description": "A project: a repository and the shape of the workspace that opens it." + }, + "spin.v1.ProjectTimeToReady": { + "type": "object", + "properties": { + "workspaces": { + "type": "integer", + "title": "workspaces", + "format": "int32", + "description": "How many workspaces the times are over: 1 to 20." + }, + "median": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Duration" + } + ], + "title": "median" + }, + "slowest": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Duration" + } + ], + "title": "slowest" + } + }, + "title": "ProjectTimeToReady", + "additionalProperties": false, + "description": "How long a project's workspaces took from their create to their project being ready in them -\n the repository checked out and its create tasks done, as each one's guest first said it, the\n wait for a host and the boot included - over the last 20 that got there. One that never did -\n it failed, or was deleted first - is not counted, and neither is one opened from a prebuild:\n this is what opening without one costs. A workspace whose first boots failed its project counts\n from its create to the boot that went." + }, + "spin.v1.ProjectWorkspace": { + "type": "object", + "properties": { + "id": { + "type": "string", + "title": "id" + }, + "name": { + "type": "string", + "title": "name" + }, + "ownerId": { + "type": "string", + "title": "owner_id" + }, + "ownerName": { + "type": "string", + "title": "owner_name" + }, + "ownerEmail": { + "type": "string", + "title": "owner_email" + }, + "state": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.WorkspaceState" + } + ], + "title": "state", + "description": "As Workspace.state, DEGRADED included." + }, + "since": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "since", + "description": "Since when it has been in that state: when its guest answered for a running one, and when\n its row last changed for any other." } }, - "title": "Project", + "title": "ProjectWorkspace", "additionalProperties": false, - "description": "A project: a repository and the shape of the workspace that opens it." + "description": "A workspace open on a project, as the project's admins read it: whose it is and how it is, and\n nothing that lets them into it." }, "spin.v1.PublishVSCodeServersRequest": { "type": "object", @@ -21878,6 +23467,43 @@ "title": "RemoveAllowedEmailResponse", "additionalProperties": false }, + "spin.v1.RemoveHostRequest": { + "type": "object", + "properties": { + "id": { + "type": "string", + "title": "id" + } + }, + "title": "RemoveHostRequest", + "additionalProperties": false + }, + "spin.v1.RemoveHostResponse": { + "type": "object", + "properties": { + "removal": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.HostRemoval" + } + ], + "title": "removal", + "description": "removal is what was done: GIVE_BACK or FORGET." + }, + "givenBack": { + "type": "boolean", + "title": "given_back", + "description": "given_back is the machine terminated and its group asked for one less; false where the\n group no longer had it." + }, + "forgotten": { + "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." + } + }, + "title": "RemoveHostResponse", + "additionalProperties": false + }, "spin.v1.RemoveStoredVolumeRequest": { "type": "object", "properties": { @@ -22109,6 +23735,11 @@ "title": "agent_min_memory_mb", "format": "int32", "description": "What a workspace has to hold for its agent to start there, in MB, for whoever picks a preset." + }, + "fromConfig": { + "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." } }, "title": "ResourcePreset", @@ -22296,6 +23927,25 @@ "title": "RevokeRunnerResponse", "additionalProperties": false }, + "spin.v1.RevokeThirdPartyTermsRequest": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.ThirdPartyItem" + }, + "title": "items" + } + }, + "title": "RevokeThirdPartyTermsRequest", + "additionalProperties": false + }, + "spin.v1.RevokeThirdPartyTermsResponse": { + "type": "object", + "title": "RevokeThirdPartyTermsResponse", + "additionalProperties": false + }, "spin.v1.RevokeUserAPIKeyRequest": { "type": "object", "properties": { @@ -22364,6 +24014,85 @@ "title": "RunPrebuildResponse", "additionalProperties": false }, + "spin.v1.Runbook": { + "type": "object", + "properties": { + "id": { + "type": "string", + "title": "id", + "description": "Stable: alert rules and pages link /admin/runbooks/\u003cid\u003e." + }, + "title": { + "type": "string", + "title": "title" + }, + "severity": { + "type": "string", + "title": "severity", + "description": "critical, warning or info." + }, + "owner": { + "type": "string", + "title": "owner", + "description": "The role that keeps it true: operator, security." + }, + "lastReviewed": { + "type": "string", + "title": "last_reviewed", + "description": "YYYY-MM-DD: when it was last held to the release it describes." + }, + "appliesTo": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.RunbookAppliesTo" + } + ], + "title": "applies_to" + } + }, + "title": "Runbook", + "additionalProperties": false + }, + "spin.v1.RunbookAppliesTo": { + "type": "object", + "properties": { + "alerts": { + "type": "array", + "items": { + "type": "string" + }, + "title": "alerts", + "description": "Grafana alert rule uids." + }, + "jobs": { + "type": "array", + "items": { + "type": "string" + }, + "title": "jobs", + "description": "Control plane job names (Job.name)." + }, + "events": { + "type": "array", + "items": { + "type": "string" + }, + "title": "events", + "description": "The notices a workspace's owner gets, by WorkspaceEventType without its prefix: HELD." + }, + "dashboards": { + "type": "array", + "items": { + "type": "string" + }, + "title": "dashboards", + "description": "Grafana dashboard uids." + } + }, + "title": "RunbookAppliesTo", + "additionalProperties": false, + "description": "What sends an operator to a runbook, each as the installation names it." + }, "spin.v1.SSHKey": { "type": "object", "properties": { @@ -23262,6 +24991,27 @@ "title": "SetWorkspaceNetworkWatchResponse", "additionalProperties": false }, + "spin.v1.SettingReach": { + "type": "string", + "title": "SettingReach", + "enum": [ + "SETTING_REACH_UNSPECIFIED", + "SETTING_REACH_RUNNING_WORKSPACES", + "SETTING_REACH_NEW_WORKSPACES", + "SETTING_REACH_NEXT_HEARTBEAT", + "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.", + "x-enum-descriptions": [ + "", + "The workspaces running now, at the control plane's next look at them.", + "Workspaces created from now on; those that exist keep what they were made with.", + "Each runner at its next heartbeat, and the workspaces running on it.", + "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.", + "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.ShareProjectRequest": { "type": "object", "properties": { @@ -24249,6 +25999,11 @@ } ], "title": "created_at" + }, + "refusedRemoval": { + "type": "string", + "title": "refused_removal", + "description": "Why disabling or deleting it would be refused; empty where it would not be. An installation\n provider that the only administrators who can sign in sign in through (lockout)." } }, "title": "TeamIdentityProvider", @@ -24392,6 +26147,117 @@ "title": "TestHostWritebackResponse", "additionalProperties": false }, + "spin.v1.ThirdPartyAcceptance": { + "type": "object", + "properties": { + "termsVersion": { + "type": "string", + "title": "terms_version", + "description": "The version of the text that was accepted; an older one than the response's counts as none." + }, + "acceptedBy": { + "type": "string", + "title": "accepted_by", + "description": "Who accepted, by email: kept as it was when they did." + }, + "acceptedAt": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Timestamp" + } + ], + "title": "accepted_at" + } + }, + "title": "ThirdPartyAcceptance", + "additionalProperties": false, + "description": "ThirdPartyAcceptance is an administrator's acceptance of an item's terms." + }, + "spin.v1.ThirdPartyItem": { + "type": "string", + "title": "ThirdPartyItem", + "enum": [ + "THIRD_PARTY_ITEM_UNSPECIFIED", + "THIRD_PARTY_ITEM_VSCODE_SERVER", + "THIRD_PARTY_ITEM_AGENT_CLIS" + ], + "description": "ThirdPartyItem is what an administrator accepts the terms of, one download at a time: the\n software the control plane fetches together, as one extension.\n\n- `THIRD_PARTY_ITEM_VSCODE_SERVER`: Microsoft's VS Code server and its CLI: the vsc-\u003ccommit\u003e extensions.\n- `THIRD_PARTY_ITEM_AGENT_CLIS`: Claude Code, Codex, T3 Code and the libatomic T3 Code's server is linked against: the agents\n extension.", + "x-enum-descriptions": [ + "", + "Microsoft's VS Code server and its CLI: the vsc-\u003ccommit\u003e extensions.", + "Claude Code, Codex, T3 Code and the libatomic T3 Code's server is linked against: the agents\n extension." + ] + }, + "spin.v1.ThirdPartyPart": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "name" + }, + "maker": { + "type": "string", + "title": "maker", + "description": "Who makes it and serves the download." + }, + "license": { + "type": "string", + "title": "license" + }, + "licenseUrl": { + "type": "string", + "title": "license_url" + } + }, + "title": "ThirdPartyPart", + "additionalProperties": false, + "description": "ThirdPartyPart is one program an item downloads, and the license it comes under." + }, + "spin.v1.ThirdPartyTermsItem": { + "type": "object", + "properties": { + "item": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.ThirdPartyItem" + } + ], + "title": "item" + }, + "name": { + "type": "string", + "title": "name" + }, + "purpose": { + "type": "string", + "title": "purpose", + "description": "What a workspace gets from it." + }, + "parts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.ThirdPartyPart" + }, + "title": "parts" + }, + "acceptance": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.ThirdPartyAcceptance" + } + ], + "title": "acceptance", + "description": "Unset where nobody accepted the terms for it." + }, + "accepted": { + "type": "boolean", + "title": "accepted", + "description": "Whether this installation downloads it: accepted, as the current text." + } + }, + "title": "ThirdPartyTermsItem", + "additionalProperties": false + }, "spin.v1.UndeleteWorkspaceRequest": { "type": "object", "properties": { @@ -24476,6 +26342,53 @@ "title": "UntagImageResponse", "additionalProperties": false }, + "spin.v1.UpdateEmailSettingsRequest": { + "type": "object", + "properties": { + "host": { + "type": "string", + "title": "host" + }, + "port": { + "type": "integer", + "title": "port", + "format": "int32" + }, + "username": { + "type": "string", + "title": "username" + }, + "password": { + "type": [ + "string", + "null" + ], + "title": "password", + "description": "Absent keeps the password there is." + }, + "from": { + "type": "string", + "title": "from" + } + }, + "title": "UpdateEmailSettingsRequest", + "additionalProperties": false + }, + "spin.v1.UpdateEmailSettingsResponse": { + "type": "object", + "properties": { + "settings": { + "allOf": [ + { + "$ref": "#/components/schemas/spin.v1.EmailSettings" + } + ], + "title": "settings" + } + }, + "title": "UpdateEmailSettingsResponse", + "additionalProperties": false + }, "spin.v1.UpdateHostClassRequest": { "type": "object", "properties": { @@ -24567,6 +26480,35 @@ "title": "UpdateNetworkPolicyResponse", "additionalProperties": false }, + "spin.v1.UpdateNotificationPreferencesRequest": { + "type": "object", + "properties": { + "preferences": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.NotificationPreference" + }, + "title": "preferences", + "description": "Each event named is set; one not named keeps what it was." + } + }, + "title": "UpdateNotificationPreferencesRequest", + "additionalProperties": false + }, + "spin.v1.UpdateNotificationPreferencesResponse": { + "type": "object", + "properties": { + "preferences": { + "type": "array", + "items": { + "$ref": "#/components/schemas/spin.v1.NotificationPreference" + }, + "title": "preferences" + } + }, + "title": "UpdateNotificationPreferencesResponse", + "additionalProperties": false + }, "spin.v1.UpdateProjectRequest": { "type": "object", "properties": { @@ -24620,6 +26562,12 @@ "type": "integer", "title": "prebuild_rebase_every", "format": "int32" + }, + "prebuildKeep": { + "type": "integer", + "title": "prebuild_keep", + "format": "int32", + "description": "Zero is one, as at create" } }, "title": "UpdateProjectRequest", @@ -25759,6 +27707,11 @@ "type": "string", "title": "host_name", "description": "host_name is the name host_id's machine registered, for a person to tell hosts apart; empty\n with no host, or one that registered none. Answered by GetWorkspace and ListWorkspaces, so a\n list row says where each runs without a status read per row; never placed or trusted by." + }, + "withoutPrebuild": { + "type": "string", + "title": "without_prebuild", + "description": "without_prebuild is why a workspace opening a project at a ref it prebuilds started from none\n of its prebuilds, and cloned the repository at its first boot: none ready, the ready one of\n another image, its disk not cloneable yet. Empty with from_prebuild_id set, or for a project\n that prebuilds nothing." } }, "title": "Workspace", @@ -26002,9 +27955,11 @@ "WORKSPACE_EVENT_TYPE_RUNNING_CAP_SUSPENDED", "WORKSPACE_EVENT_TYPE_SUSPENSION_DUE", "WORKSPACE_EVENT_TYPE_KEPT", - "WORKSPACE_EVENT_TYPE_UNRESPONSIVE" + "WORKSPACE_EVENT_TYPE_UNRESPONSIVE", + "WORKSPACE_EVENT_TYPE_REHOMED", + "WORKSPACE_EVENT_TYPE_HELD" ], - "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", + "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", "x-enum-descriptions": [ "", "Workspace was created", @@ -26028,7 +27983,9 @@ "It ran at a stretch for as long as the installation allows: suspended with its processes, a start resumes them", "A suspension is minutes away and the question was asked: its terminals, its page, the CLI; a keep answers it", "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 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" ] }, "spin.v1.WorkspaceFailure": { @@ -26298,6 +28255,15 @@ } ], "title": "deadline" + }, + "typical": { + "allOf": [ + { + "$ref": "#/components/schemas/google.protobuf.Duration" + } + ], + "title": "typical", + "description": "typical is how long a start usually takes on the workspace's host class: the median, from\n the request to RUNNING (the same measure as since), of the newest starts that came up there.\n Unset for a transition that is not a start, and where too few have come up to say. Per step\n it is not: what a host says of its phases is kept only while one is under way." } }, "title": "WorkspaceProgress", @@ -26619,6 +28585,9 @@ { "name": "RunnerTokenService" }, + { + "name": "WorkspaceService" + }, { "name": "SettingsService" }, @@ -26626,9 +28595,6 @@ "name": "SetupService", "description": "SetupService handles initial platform setup and admin bootstrap.\n Most endpoints require admin authentication, except GetSetupStatus and PasswordLogin." }, - { - "name": "WorkspaceService" - }, { "name": "ShareService", "description": "ShareService manages snapshot sharing\n Snapshots can be shared with specific users or made public\n Users can create new workspaces from shared snapshots" diff --git a/src/assets/shots/snapshots.png b/src/assets/shots/snapshots.png index 6f5bef7..29ff62d 100644 Binary files a/src/assets/shots/snapshots.png and b/src/assets/shots/snapshots.png differ diff --git a/src/assets/shots/workspace.png b/src/assets/shots/workspace.png index f234c38..95014c6 100644 Binary files a/src/assets/shots/workspace.png and b/src/assets/shots/workspace.png differ diff --git a/src/assets/shots/workspaces.png b/src/assets/shots/workspaces.png index 4f6a3e8..fc7f800 100644 Binary files a/src/assets/shots/workspaces.png and b/src/assets/shots/workspaces.png differ diff --git a/src/content/docs/admin/configuration.md b/src/content/docs/admin/configuration.md index f394a35..d68b787 100644 --- a/src/content/docs/admin/configuration.md +++ b/src/content/docs/admin/configuration.md @@ -2,8 +2,8 @@ title: Installation settings description: "How an installation is configured: the file that seeds it, the dashboard that edits it, and how a changed file becomes a proposal." reads: - - "spin:configs/spin-example.yaml@v20261108.01" - - "spin:internal/controlplane/installconfig/apply.go@v20261108.01" + - "spin:configs/spin-example.yaml@v20261110.01" + - "spin:internal/controlplane/installconfig/apply.go@v20261110.01" --- An installation's settings live in its database, and an administrator edits all of them in the diff --git a/src/content/docs/admin/hosts.mdx b/src/content/docs/admin/hosts.mdx index d42165d..fece0e6 100644 --- a/src/content/docs/admin/hosts.mdx +++ b/src/content/docs/admin/hosts.mdx @@ -2,8 +2,8 @@ title: Operating hosts description: Drain, activate and revoke runners, see what runs where, replace a runner's machine, and add a runner outside the autoscaling group. reads: - - "spin:docs/runners.md@v20261108.01" - - "spin:cmd/cli/cmd/admin.go@v20261108.01" + - "spin:docs/runners.md@v20261110.01" + - "spin:cmd/cli/cmd/admin.go@v20261110.01" - "spin-terraform-aws:modules/runners/main.tf@v20261027.02" --- @@ -49,6 +49,14 @@ behind, what a revoke refuses, and how the capacity comes back. ## Replacing a runner's machine on AWS +A runner of the group that should go for good is given back to it, which terminates the machine +and is asked for one less. It drains as it goes, and one that is the only home of a workspace's +disk is refused, naming them: + +```bash +spin admin runner remove +``` + After a revoke, or when a runner is wedged, terminate its instance without lowering the group's size. The group starts another, which joins by its role: diff --git a/src/content/docs/admin/observability.md b/src/content/docs/admin/observability.md index a777c90..1a9c126 100644 --- a/src/content/docs/admin/observability.md +++ b/src/content/docs/admin/observability.md @@ -68,8 +68,8 @@ minute. ## What is not there -- **Nothing pages anyone.** Alert rules fire in the installation's Grafana, and no contact point - tells anyone. +- **Nothing pages the operator.** Alert rules fire in the installation's Grafana, and no contact + point tells anyone. A workspace's owner is emailed when it waits for them. - The collector accepts OpenTelemetry from whatever its security group lets in: the proxy and the runners. - AWS keeps its own records outside the installation: the VPC flow log and every machine's boot diff --git a/src/content/docs/concepts/images.md b/src/content/docs/concepts/images.md index a1f2b6d..e7ec073 100644 --- a/src/content/docs/concepts/images.md +++ b/src/content/docs/concepts/images.md @@ -2,8 +2,8 @@ title: Images description: What an image is in Spinbox, the default image, how an administrator publishes and retires images, and how to build your own starting point from a snapshot. reads: - - "spin:docs/storage/README.md@v20261108.01" - - "spin:cmd/cli/cmd/admin_storage.go@v20261108.01" + - "spin:docs/storage/README.md@v20261110.01" + - "spin:cmd/cli/cmd/admin_storage.go@v20261110.01" --- An image is a disk a workspace can start from. In Spinbox an image **is** a published snapshot diff --git a/src/content/docs/concepts/network.mdx b/src/content/docs/concepts/network.mdx index 3928373..e1bfb45 100644 --- a/src/content/docs/concepts/network.mdx +++ b/src/content/docs/concepts/network.mdx @@ -2,8 +2,8 @@ title: Network and egress description: How network policies control where a workspace connects, what is always blocked, how DNS works, and how to see what it reached. reads: - - "spin:docs/network/README.md@v20261108.01" - - "spin:configs/spin-example.yaml@v20261108.01" + - "spin:docs/network/README.md@v20261110.01" + - "spin:configs/spin-example.yaml@v20261110.01" --- import Figure from '../../../components/Figure.astro'; diff --git a/src/content/docs/concepts/runners.mdx b/src/content/docs/concepts/runners.mdx index ad641a1..38e7302 100644 --- a/src/content/docs/concepts/runners.mdx +++ b/src/content/docs/concepts/runners.mdx @@ -2,9 +2,9 @@ title: Runners and hosts description: What a runner is, how it joins, how workspaces are placed on it, how runners scale from zero, and what happens when one is lost. reads: - - "spin:docs/runners.md@v20261108.01" - - "spin:internal/controlplane/domain/autoscale/autoscale.go@v20261108.01" - - "spin:internal/controlplane/domain/hostclass/hostclass.go@v20261108.01" + - "spin:docs/runners.md@v20261110.01" + - "spin:internal/controlplane/domain/autoscale/autoscale.go@v20261110.01" + - "spin:internal/controlplane/domain/hostclass/hostclass.go@v20261110.01" - "spin-terraform-aws:modules/runners/main.tf@v20261027.02" --- @@ -97,6 +97,10 @@ had not yet uploaded. lost and waits for `--accept-data-loss`. - An administrator can let the control plane move workspaces on its own, after a runner has been silent for `rehome_after_seconds`, when no more than `rehome_max_unpublished_bytes` would - be lost. This is off by default. + be lost: [the workspace is moved, and its owner is told when it waits for them instead](). + This is off by default. -Nothing tells an owner that a workspace is stranded yet. +[The owner is told by email](): +when a workspace is held after its host was lost, when a stop could not be taken, when it was +stopped for not responding, and when it was moved off a lost host. Each event can be switched +off. diff --git a/src/content/docs/concepts/snapshots.md b/src/content/docs/concepts/snapshots.md index af66864..0d9a9a6 100644 --- a/src/content/docs/concepts/snapshots.md +++ b/src/content/docs/concepts/snapshots.md @@ -2,9 +2,9 @@ title: Snapshots and rollback description: Disk and memory snapshots, restoring and resetting a workspace, diffing two snapshots, cloning, and sharing a snapshot with others. reads: - - "spin:cmd/cli/cmd/snapshot.go@v20261108.01" - - "spin:cmd/cli/cmd/share.go@v20261108.01" - - "spin:docs/storage/README.md@v20261108.01" + - "spin:cmd/cli/cmd/snapshot.go@v20261110.01" + - "spin:cmd/cli/cmd/share.go@v20261110.01" + - "spin:docs/storage/README.md@v20261110.01" --- A snapshot is a point in a workspace's life that you can come back to. It is read-only and diff --git a/src/content/docs/concepts/volumes.mdx b/src/content/docs/concepts/volumes.mdx index db0daf4..574b87a 100644 --- a/src/content/docs/concepts/volumes.mdx +++ b/src/content/docs/concepts/volumes.mdx @@ -2,8 +2,8 @@ title: Disks and storage description: "How a workspace's disk is stored: layers in the bucket, a cache on the runner, encryption, when work is uploaded, and what deleting removes." reads: - - "spin:docs/storage/README.md@v20261108.01" - - "spin:internal/storage/qcow/manager.go@v20261108.01" + - "spin:docs/storage/README.md@v20261110.01" + - "spin:internal/storage/qcow/manager.go@v20261110.01" --- import Value from '../../../components/Value.astro'; diff --git a/src/content/docs/concepts/workspaces.md b/src/content/docs/concepts/workspaces.md index ffe97b5..c9aba83 100644 --- a/src/content/docs/concepts/workspaces.md +++ b/src/content/docs/concepts/workspaces.md @@ -2,9 +2,9 @@ title: Workspaces description: What a workspace is, its states, its resources and disk, what runs inside it, and how it is started, stopped, suspended and recovered. reads: - - "spin:cmd/cli/cmd/workspace.go@v20261108.01" - - "spin:docs/reconciliation.md@v20261108.01" - - "spin:docs/workspace-filesystem.md@v20261108.01" + - "spin:cmd/cli/cmd/workspace.go@v20261110.01" + - "spin:docs/reconciliation.md@v20261110.01" + - "spin:docs/workspace-filesystem.md@v20261110.01" --- A workspace is a virtual machine that belongs to a person, or to a team. It has its own @@ -40,8 +40,9 @@ spin workspace create --name retry --from-snapshot --wait A workspace is sized by a **preset**: its cores, its memory and its free disk. An administrator defines the presets (for example `small` and `large`) and marks one as the default. See -[Installation settings](/admin/configuration/). An installation with no default preset gives -1 core, 512 MB and 10 GB of free disk. +[Installation settings](/admin/configuration/). An installation whose configuration names no +presets is given one, `default`: 1 core and 512 MB, which grow to what its runner has, on 10 GB +of free disk. A preset is fixed, starting at its size and staying there, or it bursts: it starts at a floor and may grow up to its size, or up to whatever its runner has room for. A running workspace diff --git a/src/content/docs/overview/evaluate.md b/src/content/docs/overview/evaluate.md index e51fe71..678e47c 100644 --- a/src/content/docs/overview/evaluate.md +++ b/src/content/docs/overview/evaluate.md @@ -2,8 +2,8 @@ title: Evaluate Spinbox description: What Spinbox is, what it costs, how to try it on one Linux machine, what this release does not do, and how to install it - in that order. reads: - - "spin:hack/kvm-runner-check.sh@v20261108.01" - - "spin:taskfiles/e2e.yml@v20261108.01" + - "spin:hack/kvm-runner-check.sh@v20261110.01" + - "spin:taskfiles/e2e.yml@v20261110.01" - "spin-terraform-aws:README.md@v20261027.02" --- diff --git a/src/content/docs/overview/how-it-works.mdx b/src/content/docs/overview/how-it-works.mdx index 1fe5a78..dc69329 100644 --- a/src/content/docs/overview/how-it-works.mdx +++ b/src/content/docs/overview/how-it-works.mdx @@ -2,10 +2,10 @@ title: How it works description: The pieces of an installation (control plane, proxy, runners, database, bucket), how they connect, and how a workspace comes to run. reads: - - "spin:docs/reconciliation.md@v20261108.01" - - "spin:docs/storage/README.md@v20261108.01" - - "spin:internal/pgserver/server.go@v20261108.01" - - "spin:docs/releases.md@v20261108.01" + - "spin:docs/reconciliation.md@v20261110.01" + - "spin:docs/storage/README.md@v20261110.01" + - "spin:internal/pgserver/server.go@v20261110.01" + - "spin:docs/releases.md@v20261110.01" --- import Figure from '../../../components/Figure.astro'; diff --git a/src/content/docs/overview/index.md b/src/content/docs/overview/index.md index 4990a05..3f1a415 100644 --- a/src/content/docs/overview/index.md +++ b/src/content/docs/overview/index.md @@ -2,7 +2,7 @@ title: What is Spinbox description: What Spinbox is, who it is for, what it lets you do, and the projects an installation is made of. reads: - - "spin:internal/features/features.go@v20261108.01" + - "spin:internal/features/features.go@v20261110.01" --- Spinbox runs **workspaces**: virtual machines that a person or a program uses to run code. You diff --git a/src/content/docs/overview/limitations.md b/src/content/docs/overview/limitations.md index 7d6fad6..a20644c 100644 --- a/src/content/docs/overview/limitations.md +++ b/src/content/docs/overview/limitations.md @@ -55,8 +55,9 @@ The open items of the security model are listed in [Known gaps](/reference/secur ## Operations -- **Nothing pages anyone.** Metrics, logs and traces are kept inside the installation. Alert - rules fire in its Grafana, and no contact point tells anyone. +- **Nothing pages the operator.** Metrics, logs and traces are kept inside the installation. + Alert rules fire in its Grafana, and no contact point tells anyone. A workspace's owner is + emailed when it waits for them. - **An update is one way.** A release older than the one that last started the database refuses to start on it. Going back past a schema change is a point-in-time restore of the database. diff --git a/src/content/docs/overview/one-machine.md b/src/content/docs/overview/one-machine.md index 09bca32..80858a9 100644 --- a/src/content/docs/overview/one-machine.md +++ b/src/content/docs/overview/one-machine.md @@ -2,8 +2,8 @@ title: Try it on one machine description: The development stack on a single Linux host with KVM - from git clone to a running workspace and a command in it. Not an installation. reads: - - "spin:taskfiles/e2e.yml@v20261108.01" - - "spin:hack/kvm-runner-check.sh@v20261108.01" + - "spin:taskfiles/e2e.yml@v20261110.01" + - "spin:hack/kvm-runner-check.sh@v20261110.01" --- This is the **development stack**: the control plane, the proxy and the stores in containers, diff --git a/src/content/docs/reference/api/adminservice.md b/src/content/docs/reference/api/adminservice.md index 87a02c4..1777dc8 100644 --- a/src/content/docs/reference/api/adminservice.md +++ b/src/content/docs/reference/api/adminservice.md @@ -11,6 +11,23 @@ sidebar: AdminService manages installation-wide settings, user management, and resource presets. Only accessible to instance administrators. +## AcceptThirdPartyTerms + +`POST /spin.v1.AdminService/AcceptThirdPartyTerms` + +Accept the terms, as the version shown, for the items named: this installation then downloads them - the releases this control plane pins at once, and the newest daily. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `termsVersion` | string | The version of the text the administrator was shown: one that is not the current one is refused, so nobody accepts a text they did not read. | +| `items` | list of [ThirdPartyItem](/reference/api/types/#thirdpartyitem) | | + +**Response** + +No fields: `{}`. + ## AddAllowedEmail `POST /spin.v1.AdminService/AddAllowedEmail` @@ -243,6 +260,22 @@ A month of the bill shared out to the workspaces that caused it: the runners' by | `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. | +## GetEmailSettings + +`POST /spin.v1.AdminService/GetEmailSettings` + +The SMTP server the installation tells people through. The password is never read back. + +**Request** + +No fields: `{}`. + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `settings` | [EmailSettings](/reference/api/types/#emailsettings) | | + ## GetFleetVersions `POST /spin.v1.AdminService/GetFleetVersions` @@ -294,6 +327,9 @@ No fields: `{}`. | 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 @@ -346,6 +382,26 @@ No fields: `{}`. |---|---|---| | `mode` | [RegistrationMode](/reference/api/types/#registrationmode) | | +## GetRunbook + +`POST /spin.v1.AdminService/GetRunbook` + +One runbook, its markdown and where its file is at the pinned commit. NOT_FOUND for an id this release's runbooks do not have. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `id` | string | | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `runbook` | [Runbook](/reference/api/types/#runbook) | | +| `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 `POST /spin.v1.AdminService/GetSecuritySettings` @@ -417,6 +473,24 @@ No fields: `{}`. | `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. | +## GetThirdPartyTerms + +`POST /spin.v1.AdminService/GetThirdPartyTerms` + +The software this installation downloads from its makers, the terms it is used under, and which of it an administrator accepted the terms for: who, when, and which text. Nothing is downloaded of an item whose terms are not accepted (internal/controlplane/thirdparty). + +**Request** + +No fields: `{}`. + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `termsVersion` | string | The version of the text below, which an acceptance names. | +| `text` | list of string | The terms, a paragraph each. | +| `items` | list of [ThirdPartyTermsItem](/reference/api/types/#thirdpartytermsitem) | | + ## GetVSCodeServers `POST /spin.v1.AdminService/GetVSCodeServers` @@ -435,6 +509,24 @@ No fields: `{}`. | `publish` | [VSCodeServerPublish](/reference/api/types/#vscodeserverpublish) | | | `unavailable` | string | Why this control plane cannot publish - no object store, or a build with no machine tools to make the image with - and empty when it can. | +## GetWorkspaceNames + +`POST /spin.v1.AdminService/GetWorkspaceNames` + +The names of the workspaces ids are, whoever owns them and whatever state they are in, a deleted one among them: a record of the platform's logs names a workspace by its id, and ListWorkspaces is the caller's own. An id the installation no longer holds a row for is left out of the answer. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `ids` | list of string | At most 500: the ids a page of records names. | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `names` | map of string to string | Each id asked for that the installation holds a row for, to its workspace's name. | + ## ListAllowedEmails `POST /spin.v1.AdminService/ListAllowedEmails` @@ -582,6 +674,22 @@ List resource presets | `presets` | list of [ResourcePreset](/reference/api/types/#resourcepreset) | | | `page` | [PageResponse](/reference/api/types/#pageresponse) | | +## ListRunbooks + +`POST /spin.v1.AdminService/ListRunbooks` + +What an operator does when an alert fires, a job fails or an owner is told something went wrong: spin-stack/runbooks at the commit this release pins, served so it is read in the app. + +**Request** + +No fields: `{}`. + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `runbooks` | list of [Runbook](/reference/api/types/#runbook) | | + ## ListUserAPIKeys `POST /spin.v1.AdminService/ListUserAPIKeys` @@ -623,6 +731,7 @@ List all users | `users` | list of [User](/reference/api/types/#user) | | | `page` | [PageResponse](/reference/api/types/#pageresponse) | | | `holdings` | map of string to [UserHoldings](/reference/api/types/#userholdings) | What each listed user still holds, by user id: what an administrator asks before taking access away. Kept off User, which other calls return without it. | +| `refusedRemovals` | map of string to string | Why removing a listed user as an administrator, or disabling them, would be refused, by user id; absent where it would not be. The refusal is the database's (lockout), so a client that never reads this is refused the same. | ## PublishVSCodeServers @@ -705,6 +814,22 @@ No fields: `{}`. No fields: `{}`. +## RevokeThirdPartyTerms + +`POST /spin.v1.AdminService/RevokeThirdPartyTerms` + +Take the acceptance back for the items named: nothing more of them is downloaded. What was downloaded already stays until an administrator removes it. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `items` | list of [ThirdPartyItem](/reference/api/types/#thirdpartyitem) | | + +**Response** + +No fields: `{}`. + ## RevokeUserAPIKey `POST /spin.v1.AdminService/RevokeUserAPIKey` @@ -772,6 +897,28 @@ Take a ref off what it names: no new workspace gets those bytes by it, the disks No fields: `{}`. +## UpdateEmailSettings + +`POST /spin.v1.AdminService/UpdateEmailSettings` + +Set the SMTP server, checked against it - connected to and signed in to - before it is written. An empty host turns email off. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `host` | string | | +| `port` | integer (int32) | | +| `username` | string | | +| `password` | string or null | Absent keeps the password there is. | +| `from` | string | | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `settings` | [EmailSettings](/reference/api/types/#emailsettings) | | + ## UpdateHostClass `POST /spin.v1.AdminService/UpdateHostClass` diff --git a/src/content/docs/reference/api/hostservice.md b/src/content/docs/reference/api/hostservice.md index dfe2244..f8bba47 100644 --- a/src/content/docs/reference/api/hostservice.md +++ b/src/content/docs/reference/api/hostservice.md @@ -129,6 +129,26 @@ List all hosts (admin only) | `hosts` | list of [Host](/reference/api/types/#host) | | | `page` | [PageResponse](/reference/api/types/#pageresponse) | | +## RemoveHost + +`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. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `id` | string | | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `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. | + ## SetHostPolicy `POST /spin.v1.HostService/SetHostPolicy` diff --git a/src/content/docs/reference/api/index.md b/src/content/docs/reference/api/index.md index 8be4baf..f027cb8 100644 --- a/src/content/docs/reference/api/index.md +++ b/src/content/docs/reference/api/index.md @@ -25,14 +25,14 @@ curl -s https://app.example.com/spin.v1.WorkspaceService/ListWorkspaces \ - [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/): 8 procedures +- [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. - [RunnerTokenService](/reference/api/runnertokenservice/): 4 procedures -- [SettingsService](/reference/api/settingsservice/): 3 procedures -- [SetupService](/reference/api/setupservice/): SetupService handles initial platform setup and admin bootstrap. Most endpoints require admin authentication, except GetSetupStatus and PasswordLogin. - [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 diff --git a/src/content/docs/reference/api/projectservice.md b/src/content/docs/reference/api/projectservice.md index 85d4595..a2b402f 100644 --- a/src/content/docs/reference/api/projectservice.md +++ b/src/content/docs/reference/api/projectservice.md @@ -29,6 +29,7 @@ ProjectService is the installation's projects (spin#720): a repository and the s | `networkTags` | list of string | | | `prebuildRefs` | list of string | | | `prebuildRebaseEvery` | integer (int32) | Zero is the installation's default | +| `prebuildKeep` | integer (int32) | Zero is one: the newest of each ref | **Response** @@ -50,6 +51,25 @@ ProjectService is the installation's projects (spin#720): a repository and the s No fields: `{}`. +## GetPrebuild + +`POST /spin.v1.ProjectService/GetPrebuild` + +One of them whole, with what its build's create tasks wrote, to whoever sees the project. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `projectId` | string | | +| `prebuildId` | string | | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `prebuild` | [Prebuild](/reference/api/types/#prebuild) | | + ## GetProject `POST /spin.v1.ProjectService/GetProject` @@ -84,6 +104,27 @@ A project's prebuilds, to whoever sees it; and a build of one of its refs now, b | Field | Type | What it is | |---|---|---| | `prebuilds` | list of [Prebuild](/reference/api/types/#prebuild) | Newest first. | +| `storageMeasuredAt` | `Timestamp` | When storage-gc last read the store, which each stored_bytes is as of; unset before it has. | +| `retireUnusedDays` | integer (int32) | The installation's prebuild_retire_unused_days: a ready prebuild nobody opened a workspace from in this many days is retired, its ref's newest included. Zero retires none for that. | +| `refsNotFound` | list of [PrebuildRefNotFound](/reference/api/types/#prebuildrefnotfound) | The refs the project prebuilds that its forge says the repository has not - a branch deleted since it was named - as the prebuilds job last found them: nothing is built of one until the forge has it again or the project names it no longer. | + +## ListProjectWorkspaces + +`POST /spin.v1.ProjectService/ListProjectWorkspaces` + +Everybody's workspaces open on a project, to its admins and nobody else: a person it is only shared with is refused, and reads their own with ListWorkspaces. + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `projectId` | string | | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `workspaces` | list of [ProjectWorkspace](/reference/api/types/#projectworkspace) | Newest first, and at most 500. Not a prebuild's build, and not a deleted one. | ## ListProjects @@ -157,6 +198,7 @@ Changed, shared and deleted by its admins. A project with a workspace open on it | `networkTags` | list of string | | | `prebuildRefs` | list of string | | | `prebuildRebaseEvery` | integer (int32) | | +| `prebuildKeep` | integer (int32) | Zero is one, as at create | **Response** diff --git a/src/content/docs/reference/api/settingsservice.md b/src/content/docs/reference/api/settingsservice.md index fa2169b..2f92d8a 100644 --- a/src/content/docs/reference/api/settingsservice.md +++ b/src/content/docs/reference/api/settingsservice.md @@ -4,11 +4,28 @@ description: "spin.v1.SettingsService: each procedure, its request and its respo source: "spin:internal/controlplane/apidocs/spin.v1.openapi.json" editUrl: false sidebar: - order: 11 + order: 12 --- +## GetNotificationPreferences + +`POST /spin.v1.SettingsService/GetNotificationPreferences` + +Which of those the caller is emailed about. + +**Request** + +No fields: `{}`. + +**Response** + +| 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. | +| `emailConfigured` | boolean | | + ## GetUserSettings `POST /spin.v1.SettingsService/GetUserSettings` @@ -25,6 +42,39 @@ No fields: `{}`. |---|---|---| | `settings` | [UserSettings](/reference/api/types/#usersettings) | | +## ListNotifications + +`POST /spin.v1.SettingsService/ListNotifications` + +What happened to the caller's workspaces that they are told of, newest first, with whether each was sent and how. Recorded whether or not the installation can send email. + +**Request** + +No fields: `{}`. + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `notifications` | list of [Notification](/reference/api/types/#notification) | | +| `emailConfigured` | boolean | Whether the installation can send email at all. | + +## UpdateNotificationPreferences + +`POST /spin.v1.SettingsService/UpdateNotificationPreferences` + +**Request** + +| Field | Type | What it is | +|---|---|---| +| `preferences` | list of [NotificationPreference](/reference/api/types/#notificationpreference) | Each event named is set; one not named keeps what it was. | + +**Response** + +| Field | Type | What it is | +|---|---|---| +| `preferences` | list of [NotificationPreference](/reference/api/types/#notificationpreference) | | + ## UpdateUserSettings `POST /spin.v1.SettingsService/UpdateUserSettings` diff --git a/src/content/docs/reference/api/setupservice.md b/src/content/docs/reference/api/setupservice.md index c3c667e..615b9c5 100644 --- a/src/content/docs/reference/api/setupservice.md +++ b/src/content/docs/reference/api/setupservice.md @@ -4,7 +4,7 @@ description: "spin.v1.SetupService: each procedure, its request and its response source: "spin:internal/controlplane/apidocs/spin.v1.openapi.json" editUrl: false sidebar: - order: 12 + order: 13 --- @@ -113,6 +113,7 @@ No fields: `{}`. | `hasStorage` | boolean | True if the object store is configured; until it is, no workspace can be created | | `signedIn` | boolean | True if whoever asked is signed in: the wizard starts at the sign-in until they are, whatever the installation already has. | | `development` | boolean | True for a development installation, where the mock identity provider may be enabled. | +| `thirdPartyAccepted` | boolean | True where an administrator accepted the terms of any third-party software, as the current text: the wizard asks until one has, or until it is told to go on without. | ## PasswordLogin diff --git a/src/content/docs/reference/api/types.md b/src/content/docs/reference/api/types.md index 22593f3..09cfd00 100644 --- a/src/content/docs/reference/api/types.md +++ b/src/content/docs/reference/api/types.md @@ -101,6 +101,7 @@ BaseImage is the base image of one machine release, as published. | `pinned` | boolean | The one this control plane's release pins; given once it is published. | | `volumeId` | string | Its volume in the store, which RemoveStoredVolume takes when removable. | | `removable` | boolean | No disk was cloned from it and it is not the one given: RemoveStoredVolume untags it on the way and removes it. | +| `keptBecause` | string | Why it stays, in words, where it may not go. | ## BillDay @@ -197,6 +198,18 @@ One of: `DEVICE_LOGIN_STATUS_UNSPECIFIED`, `DEVICE_LOGIN_STATUS_PENDING`, `DEVIC | `branch` | string | Branch to clone (default: main) | | `installCommand` | string | Command to run after clone (default: ./install.sh) | +## EmailSettings + +EmailSettings is the SMTP server the installation sends its notifications through. No host is email off: what would have been sent is still recorded, and shown on each person's page. + +| Field | Type | What it is | +|---|---|---| +| `host` | string | | +| `port` | integer (int32) | 465 is TLS from the first byte; any other port is upgraded with STARTTLS where the server offers it, and a username is refused over a connection that is not encrypted. | +| `username` | string | | +| `passwordSet` | boolean | | +| `from` | string | The address mail is sent from, as the server allows this account to send. | + ## ExposedPort | Field | Type | What it is | @@ -221,6 +234,9 @@ ExtensionRelease is one release of an extension: the supervisor, or the VS Code | `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. | ## ExtensionVersion @@ -289,9 +305,11 @@ One host class's group, as the control plane last saw it. | `most` | integer (int32) | | | `waiting` | integer (int32) | Workspaces of the class that have nowhere to run yet, and when the first of them started waiting: this is what makes the control plane ask for a machine. | | `oldestWaiting` | `Timestamp` | | -| `busy` | integer (int32) | Workspaces of the class keeping its group up. | +| `busy` | integer (int32) | Workspaces of the class, and hosts a root shell holds, keeping its group up. | | `launchFailure` | string | Why the group has fewer machines running than it was asked for, in its cloud's own words - "AWS could not start a runner: <message>" - and when the cloud said it. Empty while it has as many, or while the cloud said nothing that explains 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` | | ## FleetHostVersion @@ -438,6 +456,8 @@ One of: `HEALTH_STATUS_UNSPECIFIED`, `HEALTH_STATUS_OK`, `HEALTH_STATUS_DEGRADED | `streamEnd` | [HostStreamEnd](/reference/api/types/#hoststreamend) | Why the host's last command stream ended, while it is not connected; UNSPECIFIED while it is connected, and where this control plane has not seen one end. stream_end_detail is the error the stream ended with, in its own words. | | `streamEndDetail` | string | | | `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. | ## HostCheck @@ -495,6 +515,12 @@ HostPolicy is what an installation decides about one host. An unset field is the | `maxWorkspaceIoMbPerSecond` | integer or null (int32) | What one machine may read and write per second here, in MiB and in operations, for the machines it starts afterwards. Unset is no bound. | | `maxWorkspaceIoOpsPerSecond` | integer or null (int32) | | +## HostRemoval + +HostRemoval is how a host leaves the fleet. - `HOST_REMOVAL_REVOKE`: A host registered with a token, or a machine of a cloud no group of this installation sizes: RevokeRunner. Nothing else can take its machine away. - `HOST_REMOVAL_GIVE_BACK`: A machine of an autoscaling group, connected: RemoveHost gives it back to its group, which terminates it and is asked for one less. Revoking it would leave the machine running and paid for, in a group that counts it. - `HOST_REMOVAL_FORGET`: A machine of an autoscaling group, not connected: RemoveHost gives back a machine the group still has, and forgets the host now rather than once it has been silent for host_forget_after_hours. + +One of: `HOST_REMOVAL_UNSPECIFIED`, `HOST_REMOVAL_REVOKE`, `HOST_REMOVAL_GIVE_BACK`, `HOST_REMOVAL_FORGET`. + ## HostShell | Field | Type | What it is | @@ -584,7 +610,6 @@ InstallationSettings contains global settings for the Spin installation | `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. | -| `vscodeFetch` | boolean | Whether the control plane fetches VS Code servers from Microsoft on its own: the release it pins, at start, the newest stable release, looked for daily, and the server of a client's commit the installation has not released. False, it fetches none, and a workspace is given a server an administrator published; no image carries 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. | @@ -594,7 +619,6 @@ InstallationSettings contains global settings for the Spin installation | `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. | -| `agentsFetch` | boolean | Whether the control plane fetches the agents' programs - Claude Code, Codex and T3 Code - from their publishers on its own: the triple it pins, at start, and the newest release of each, looked for daily. False, it fetches none, and a workspace is given a triple an operator published; no image carries one. | | `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 | | @@ -614,6 +638,9 @@ InstallationSettings contains global settings for the Spin installation | `nextRunAt` | `Timestamp` | When the schedule next starts it. | | `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. | +| `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 @@ -747,6 +774,51 @@ NetworkUsagePoint is what the machine's network carried over a step. | `sentBytes` | string (int64) | | | `receivedBytes` | string (int64) | | +## Notification + +Notification is one event of a workspace's timeline its owner is told of: what happened, and what they can do about it. + +| Field | Type | What it is | +|---|---|---| +| `id` | string | The workspace event's id. | +| `workspaceId` | string | | +| `workspaceName` | string | | +| `event` | [WorkspaceEventType](/reference/api/types/#workspaceeventtype) | | +| `createdAt` | `Timestamp` | | +| `subject` | string | One line saying what happened. | +| `body` | string | What happened, in full. | +| `command` | string | The command that does what the owner can do about it; empty where nothing is to be done. | +| `deliveries` | list of [NotificationDelivery](/reference/api/types/#notificationdelivery) | Empty where it was never sent: email off, or this kind turned off. | + +## NotificationChannel + +How a notification leaves the installation. + +One of: `NOTIFICATION_CHANNEL_UNSPECIFIED`, `NOTIFICATION_CHANNEL_EMAIL`. + +## NotificationDelivery + +| Field | Type | What it is | +|---|---|---| +| `channel` | [NotificationChannel](/reference/api/types/#notificationchannel) | | +| `state` | [NotificationDeliveryState](/reference/api/types/#notificationdeliverystate) | | +| `attempts` | integer (int32) | | +| `lastError` | string | What the last attempt that failed was told; empty once one succeeded. | +| `sentAt` | `Timestamp` | | + +## NotificationDeliveryState + +Where one notification's delivery on one channel is. - `NOTIFICATION_DELIVERY_STATE_PENDING`: Not sent yet, or tried and to be tried again - `NOTIFICATION_DELIVERY_STATE_SENT`: The channel accepted it - `NOTIFICATION_DELIVERY_STATE_FAILED`: Every attempt failed; it is not tried again + +One of: `NOTIFICATION_DELIVERY_STATE_UNSPECIFIED`, `NOTIFICATION_DELIVERY_STATE_PENDING`, `NOTIFICATION_DELIVERY_STATE_SENT`, `NOTIFICATION_DELIVERY_STATE_FAILED`. + +## NotificationPreference + +| Field | Type | What it is | +|---|---|---| +| `event` | [WorkspaceEventType](/reference/api/types/#workspaceeventtype) | | +| `email` | boolean | | + ## ObservedDestination ObservedDestination is one address the workspace was allowed to reach, with what the host's ruleset counted and the name its resolver answered with that address, where it holds one. @@ -865,11 +937,23 @@ A prebuild: one build of a project's ref at a commit, and the snapshot it left. | `parentId` | string | The prebuild it was built on, and how many builds it is from the image (0: built from it). | | `depth` | integer (int32) | | | `image` | string | | -| `log` | string | The tail of what its build said, and why it failed. | +| `log` | string | The tail of what its build's create tasks wrote (GetPrebuild only), and why it failed. | | `error` | string | | | `createdAt` | `Timestamp` | | | `builtAt` | `Timestamp` | | | `workspaceCount` | integer (int32) | In ListPrebuilds: the workspaces opened from it that are not deleted, whoever's they are. | +| `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. | + +## PrebuildRefNotFound + +A prebuild ref the project's forge has not. + +| Field | Type | What it is | +|---|---|---| +| `ref` | string | | +| `since` | `Timestamp` | The job's first look that found it missing. | ## PrebuildState @@ -910,6 +994,32 @@ A project: a repository and the shape of the workspace that opens it. | `sharedUserIds` | list of string | | | `sharedTeamIds` | list of string | | | `readyPrebuildCount` | integer (int32) | In ListProjects: how many of its prebuilds are ready to open from. | +| `prebuildKeep` | integer (int32) | How many of each ref's newest ready prebuilds are kept when no workspace was opened from them. | +| `timeToReady` | [ProjectTimeToReady](/reference/api/types/#projecttimetoready) | In GetProject: how long its workspaces took to be ready. Unset where none has been. | + +## ProjectTimeToReady + +How long a project's workspaces took from their create to their project being ready in them - the repository checked out and its create tasks done, as each one's guest first said it, the wait for a host and the boot included - over the last 20 that got there. One that never did - it failed, or was deleted first - is not counted, and neither is one opened from a prebuild: this is what opening without one costs. A workspace whose first boots failed its project counts from its create to the boot that went. + +| Field | Type | What it is | +|---|---|---| +| `workspaces` | integer (int32) | How many workspaces the times are over: 1 to 20. | +| `median` | `Duration` | | +| `slowest` | `Duration` | | + +## ProjectWorkspace + +A workspace open on a project, as the project's admins read it: whose it is and how it is, and nothing that lets them into it. + +| Field | Type | What it is | +|---|---|---| +| `id` | string | | +| `name` | string | | +| `ownerId` | string | | +| `ownerName` | string | | +| `ownerEmail` | string | | +| `state` | [WorkspaceState](/reference/api/types/#workspacestate) | As Workspace.state, DEGRADED included. | +| `since` | `Timestamp` | Since when it has been in that state: when its guest answered for a running one, and when its row last changed for any other. | ## QuarantineDenial @@ -1001,6 +1111,7 @@ ResourcePreset is a class of workspace: its size, and how a workspace of it may | `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). | | `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. | ## Resources @@ -1015,6 +1126,28 @@ 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. | +## Runbook + +| Field | Type | What it is | +|---|---|---| +| `id` | string | Stable: alert rules and pages link /admin/runbooks/<id>. | +| `title` | string | | +| `severity` | string | critical, warning or info. | +| `owner` | string | The role that keeps it true: operator, security. | +| `lastReviewed` | string | YYYY-MM-DD: when it was last held to the release it describes. | +| `appliesTo` | [RunbookAppliesTo](/reference/api/types/#runbookappliesto) | | + +## RunbookAppliesTo + +What sends an operator to a runbook, each as the installation names it. + +| Field | Type | What it is | +|---|---|---| +| `alerts` | list of string | Grafana alert rule uids. | +| `jobs` | list of string | Control plane job names (Job.name). | +| `events` | list of string | The notices a workspace's owner gets, by WorkspaceEventType without its prefix: HELD. | +| `dashboards` | list of string | Grafana dashboard uids. | + ## SSHKey User's uploaded SSH public key @@ -1071,6 +1204,12 @@ ServiceHealth is one service over a window: the traces begun in it - what it was | `traces` | string (int64) | | | `failedTraces` | string (int64) | | +## 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. + +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`. + ## Snapshot A snapshot is a rotation of a workspace's volume, published as a commit. It has no name outside its id. @@ -1241,6 +1380,7 @@ What the supervisor inside the guest last reported. Absent (`connected` false wi | `roleCelExpression` | string | CEL expression for role assignment | | `enabled` | boolean | | | `createdAt` | `Timestamp` | | +| `refusedRemoval` | string | Why disabling or deleting it would be refused; empty where it would not be. An installation provider that the only administrators who can sign in sign in through (lockout). | ## TeamMember @@ -1276,6 +1416,44 @@ TelemetryFlow is what one exporter of the collector did over the last window. | `sent` | string (int64) | | | `failed` | string (int64) | | +## ThirdPartyAcceptance + +ThirdPartyAcceptance is an administrator's acceptance of an item's terms. + +| Field | Type | What it is | +|---|---|---| +| `termsVersion` | string | The version of the text that was accepted; an older one than the response's counts as none. | +| `acceptedBy` | string | Who accepted, by email: kept as it was when they did. | +| `acceptedAt` | `Timestamp` | | + +## ThirdPartyItem + +ThirdPartyItem is what an administrator accepts the terms of, one download at a time: the software the control plane fetches together, as one extension. - `THIRD_PARTY_ITEM_VSCODE_SERVER`: Microsoft's VS Code server and its CLI: the vsc-<commit> extensions. - `THIRD_PARTY_ITEM_AGENT_CLIS`: Claude Code, Codex, T3 Code and the libatomic T3 Code's server is linked against: the agents extension. + +One of: `THIRD_PARTY_ITEM_UNSPECIFIED`, `THIRD_PARTY_ITEM_VSCODE_SERVER`, `THIRD_PARTY_ITEM_AGENT_CLIS`. + +## ThirdPartyPart + +ThirdPartyPart is one program an item downloads, and the license it comes under. + +| Field | Type | What it is | +|---|---|---| +| `name` | string | | +| `maker` | string | Who makes it and serves the download. | +| `license` | string | | +| `licenseUrl` | string | | + +## ThirdPartyTermsItem + +| Field | Type | What it is | +|---|---|---| +| `item` | [ThirdPartyItem](/reference/api/types/#thirdpartyitem) | | +| `name` | string | | +| `purpose` | string | What a workspace gets from it. | +| `parts` | list of [ThirdPartyPart](/reference/api/types/#thirdpartypart) | | +| `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. | + ## User | Field | Type | What it is | @@ -1394,6 +1572,7 @@ VolumeRekey is a workspace's disk to re-key or being re-keyed. | `projectReportedAt` | `Timestamp` | project_reported_at is when its guest said how its project went in this run, unset until it has: an empty project_error before then is a clone still going, not one that went. project_head is the commit it checked out, as the guest said it; empty when it did not say one. | | `projectHead` | string | | | `hostName` | string | host_name is the name host_id's machine registered, for a person to tell hosts apart; empty with no host, or one that registered none. Answered by GetWorkspace and ListWorkspaces, so a list row says where each runs without a status read per row; never placed or trusted by. | +| `withoutPrebuild` | string | without_prebuild is why a workspace opening a project at a ref it prebuilds started from none of its prebuilds, and cloned the repository at its first boot: none ready, the ready one of another image, its disk not cloneable yet. Empty with from_prebuild_id set, or for a project that prebuilds nothing. | ## WorkspaceAction @@ -1458,9 +1637,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_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 -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`. +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`. ## WorkspaceFailure @@ -1518,6 +1697,7 @@ WorkspaceProgress is a transition under way. | `phase` | [WorkspacePhase](/reference/api/types/#workspacephase) | phase is what the host is doing now; UNSPECIFIED when it has not said. | | `since` | `Timestamp` | since is when the transition began, and deadline when the control plane gives up on it - a wait for a host, or a start or a stop the host does not finish - and fails the workspace. | | `deadline` | `Timestamp` | | +| `typical` | `Duration` | typical is how long a start usually takes on the workspace's host class: the median, from the request to RUNNING (the same measure as since), of the newest starts that came up there. Unset for a transition that is not a start, and where too few have come up to say. Per step it is not: what a host says of its phases is kept only while one is under way. | ## WorkspaceProxyStatus diff --git a/src/content/docs/reference/api/workspaceservice.md b/src/content/docs/reference/api/workspaceservice.md index 4c25e17..b731f3e 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: 13 + order: 11 --- @@ -31,7 +31,7 @@ No fields: `{}`. `POST /spin.v1.WorkspaceService/AttachVSCodeServer` -Give a running workspace the VS Code server of a client's commit, while it runs: published first when this installation has not got it and fetches servers on its own (InstallationSettings.vscode_fetch), refused as FAILED_PRECONDITION when it does not. Asked again until it answers attached. +Give a running workspace the VS Code server of a client's commit, while it runs: published first when this installation has not got it and an administrator accepted the VS Code server's terms (AdminService.AcceptThirdPartyTerms), refused as FAILED_PRECONDITION, saying so, when nobody did. Asked again until it answers attached. **Request** @@ -147,11 +147,11 @@ 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 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, 512 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. | -| `projectId` | string | A project the caller sees: the workspace is the project's - its image, preset and tags, which the request then names none of - in team_id, the caller's personal team when empty, and its guest clones the project's repository at ref, the project's own when empty. Refused while the repository is on a forge the installation connects to (ForgeService) and the caller has not connected their account there. | +| `projectId` | string | A project the caller sees: the workspace is the project's - its image and tags, which the request then names neither of, and its preset unless preset names another - in team_id, the caller's personal team when empty, and its guest clones the project's repository at ref, the project's own when empty. Refused while the repository is on a forge the installation connects to (ForgeService) and the caller has not connected their account there. | | `ref` | string | | | `requestId` | string | Optional, at most 128 bytes: the client's key for this create, so a retry after an answer it never got is answered with the workspace the first attempt made. The same key with another request is refused (FAILED_PRECONDITION). | | `agentVolumeId` | string | Optional: an agent's home of the caller's to mount (ListAgentVolumes), one no workspace mounts now - the history of a workspace since erased, found again in this one. Empty makes the workspace a new one. Refused while no host has room: a workspace that waits for a host gets its new home when it is placed, and mounts none it was named. | diff --git a/src/content/docs/reference/cli/admin.md b/src/content/docs/reference/cli/admin.md index 5cb6d2b..547886f 100644 --- a/src/content/docs/reference/cli/admin.md +++ b/src/content/docs/reference/cli/admin.md @@ -31,7 +31,7 @@ Available Commands: volume Re-key a workspace's disk Flags: - -h, --help help for admin + -h, --help[=true|false] help for admin Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -57,8 +57,8 @@ Available Commands: by What each workspace, team or owner cost this month, and what nobody did Flags: - -h, --help help for costs - --month string the month, as 2026-10 (default: this month) + -h, --help[=true|false] help for costs + --month string the month, as 2026-10 (default: this month) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -81,8 +81,8 @@ Usage: spin admin costs by [flags] Flags: - -h, --help help for by - --month string the month, as 2026-10 (default: this month) + -h, --help[=true|false] help for by + --month string the month, as 2026-10 (default: this month) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -103,7 +103,7 @@ Usage: spin admin health [flags] Flags: - -h, --help help for health + -h, --help[=true|false] help for health Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -126,7 +126,7 @@ Available Commands: run Run a job now rather than when it is next due Flags: - -h, --help help for jobs + -h, --help[=true|false] help for jobs Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -146,7 +146,7 @@ Usage: spin admin jobs list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -165,7 +165,7 @@ Usage: spin admin jobs run [flags] Flags: - -h, --help help for run + -h, --help[=true|false] help for run Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -190,9 +190,9 @@ Usage: spin admin logs [query] [flags] Flags: - -h, --help help for logs - --limit int32 how many records, newest first: 1 to 1000 (default 100) - --since duration how far back to look, at most 744h (31 days) (default 1h0m0s) + -h, --help[=true|false] help for logs + --limit int32 how many records, newest first: 1 to 1000 (default 100) + --since duration how far back to look, at most 744h (31 days) (default 1h0m0s) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -215,10 +215,11 @@ Available Commands: drain Stop a runner taking new workspaces, until it is activated list List all runners policy What a runner may do, as against what it is + remove Take a runner of an autoscaling group out of the fleet: give it back to its group, or forget it revoke Revoke a runner's access, for a machine that should never connect again Flags: - -h, --help help for runner + -h, --help[=true|false] help for runner Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -240,7 +241,7 @@ Usage: spin admin runner activate [flags] Flags: - -h, --help help for activate + -h, --help[=true|false] help for activate Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -266,9 +267,9 @@ Usage: spin admin runner drain [flags] Flags: - -h, --help help for drain - --leave-stopped With --suspend: leave them stopped until their owners start them (a drain that shrinks the fleet) - --suspend Suspend the runner's running workspaces so they resume elsewhere + -h, --help[=true|false] help for drain + --leave-stopped[=true|false] With --suspend: leave them stopped until their owners start them (a drain that shrinks the fleet) + --suspend[=true|false] Suspend the runner's running workspaces so they resume elsewhere Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -286,7 +287,7 @@ Usage: spin admin runner list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -315,13 +316,13 @@ Usage: Flags: --cpu-cores int32 cores this runner advertises; unset advertises what it has --disk-gb int32 disk this runner advertises; unset advertises what it has - -h, --help help for policy + -h, --help[=true|false] help for policy --max-workspace-cpu-cores int32 the cores one workspace may grow to there --max-workspace-io-mb-per-second int32 MiB one workspace may read, and write, a second there; unset is no bound --max-workspace-io-ops-per-second int32 I/O operations one workspace may read, and write, a second there; unset is no bound --max-workspace-memory-mb int32 the memory one workspace may grow to there --memory-mb int32 memory this runner advertises; unset advertises what it has - --preemptible a stop on this runner is the machine being taken away, not a restart + --preemptible[=true|false] a stop on this runner is the machine being taken away, not a restart --preemption-metadata-url string where that cloud's metadata service answers; empty is its own link-local address --preemption-source string the cloud that announces a reclaim: aws, gcp or azure (implies --preemptible) --shutdown-grace duration how long this runner stays up after a stop signal so its workspaces can be moved off it @@ -335,6 +336,34 @@ 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 runner remove + +``` +Take a runner that is a machine of an autoscaling group out of the fleet. + +A connected one is cordoned and given back to its group, which terminates the machine and is +asked for one less; it drains as it goes, and its row goes when it has. One that is not connected +is given back if its group still has its machine, and forgotten now, without waiting out +host_forget_after_hours. + +A runner that is the only home of a workspace's disk is refused, naming them: stop them, which +publishes each disk, or move them first. A runner registered with a token is revoked instead +(spin admin runner revoke). + +Usage: + spin admin runner remove [flags] + +Flags: + -h, --help[=true|false] help for remove + -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 +``` + #### spin admin runner revoke ``` @@ -353,9 +382,9 @@ Usage: spin admin runner revoke [flags] Flags: - -h, --help help for revoke - --leave-workspaces revoke although workspaces are on this host; each runs again only once recovered elsewhere - -y, --yes Skip confirmation + -h, --help[=true|false] help for revoke + --leave-workspaces[=true|false] revoke although workspaces are on this host; each runs again only once recovered elsewhere + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -389,7 +418,7 @@ Available Commands: recording What a root shell's sessions recorded, asciicast v2, each session's in turn Flags: - -h, --help help for shell + -h, --help[=true|false] help for shell Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -409,7 +438,7 @@ Usage: spin admin shell approve [flags] Flags: - -h, --help help for approve + -h, --help[=true|false] help for approve Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -427,7 +456,7 @@ Usage: spin admin shell close [flags] Flags: - -h, --help help for close + -h, --help[=true|false] help for close Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -445,7 +474,7 @@ Usage: spin admin shell list [runner-id] [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -470,10 +499,10 @@ Usage: spin admin shell open [flags] Flags: - -h, --help help for open - --incident Open on the runner as it is, its workspaces running, without emptying it first - --minutes int32 How long the shell is open once it opens, up to the installation's host_shell_max_minutes (default 30) - --reason string Why: said to whoever approves it, and kept + -h, --help[=true|false] help for open + --incident[=true|false] Open on the runner as it is, its workspaces running, without emptying it first + --minutes int32 How long the shell is open once it opens, up to the installation's host_shell_max_minutes (default 30) + --reason string Why: said to whoever approves it, and kept Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -493,7 +522,7 @@ Usage: spin admin shell recording [flags] Flags: - -h, --help help for recording + -h, --help[=true|false] help for recording Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -518,7 +547,7 @@ Available Commands: untag-image Take a ref off the image it names Flags: - -h, --help help for storage + -h, --help[=true|false] help for storage Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -540,7 +569,7 @@ Usage: spin admin storage explain [flags] Flags: - -h, --help help for explain + -h, --help[=true|false] help for explain Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -559,7 +588,7 @@ Usage: spin admin storage list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -581,8 +610,8 @@ Usage: spin admin storage remove [flags] Flags: - -h, --help help for remove - -y, --yes Skip confirmation + -h, --help[=true|false] help for remove + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -602,7 +631,7 @@ Usage: spin admin storage untag-image [flags] Flags: - -h, --help help for untag-image + -h, --help[=true|false] help for untag-image Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -626,7 +655,7 @@ Available Commands: revoke Revoke a registration token Flags: - -h, --help help for token + -h, --help[=true|false] help for token Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -667,16 +696,16 @@ Flags: --description string Description for the token --disk-gb int32 disk each host it registers advertises; unset advertises what it has --expires duration how long the token registers hosts; unset is the control plane's 24 hours, and at most 30 days - -h, --help help for create + -h, --help[=true|false] help for create --max-workspace-cpu-cores int32 the cores one workspace may grow to there --max-workspace-io-mb-per-second int32 MiB one workspace may read, and write, a second there; unset is no bound --max-workspace-io-ops-per-second int32 I/O operations one workspace may read, and write, a second there; unset is no bound --max-workspace-memory-mb int32 the memory one workspace may grow to there --memory-mb int32 memory each host it registers advertises; unset advertises what it has - --preemptible a stop on each host it registers is the machine being taken away, not a restart + --preemptible[=true|false] a stop on each host it registers is the machine being taken away, not a restart --preemption-metadata-url string where that cloud's metadata service answers; empty is its own link-local address --preemption-source string the cloud that announces a reclaim: aws, gcp or azure (implies --preemptible) - --reusable a pool's token: it registers every host that presents it until it expires + --reusable[=true|false] a pool's token: it registers every host that presents it until it expires --shutdown-grace duration how long each host it registers stays up after a stop signal so its workspaces can be moved off it --team string The team to scope the runner to, by id, path or me --writeback-background-bytes int dirty page cache at which each host it registers starts writing back (vm.dirty_background_bytes), below the limit @@ -698,8 +727,8 @@ Usage: spin admin token list [flags] Flags: - -h, --help help for list - --include-used Include already-used tokens + -h, --help[=true|false] help for list + --include-used[=true|false] Include already-used tokens Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -717,7 +746,7 @@ Usage: spin admin token revoke [flags] Flags: - -h, --help help for revoke + -h, --help[=true|false] help for revoke Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -735,7 +764,7 @@ Usage: spin admin versions [flags] Flags: - -h, --help help for versions + -h, --help[=true|false] help for versions Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -758,7 +787,7 @@ Available Commands: rekeys The disks being re-keyed, and the ones a revoked host's keys marked for it Flags: - -h, --help help for volume + -h, --help[=true|false] help for volume Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -776,14 +805,15 @@ Copy a workspace's disk, whole, under a key of its own, point the workspace at t delete the disk - which destroys the key it was under, and every snapshot of the disk with it: those are what that key opens. What to do when the key is assumed taken, by a host that held it. -The workspace must be stopped or quarantined. A disk something was cloned from is refused. +The workspace is anybody's, named by its id. It must be stopped or quarantined. A disk something +was cloned from is refused. Usage: - spin admin volume rekey [flags] + spin admin volume rekey [flags] Flags: - -h, --help help for rekey - -y, --yes Skip confirmation + -h, --help[=true|false] help for rekey + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -801,7 +831,7 @@ Usage: spin admin volume rekeys [flags] Flags: - -h, --help help for rekeys + -h, --help[=true|false] help for rekeys Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/agent.md b/src/content/docs/reference/cli/agent.md index e01a63c..48f58a0 100644 --- a/src/content/docs/reference/cli/agent.md +++ b/src/content/docs/reference/cli/agent.md @@ -39,11 +39,11 @@ Available Commands: home The agent's homes: volumes that outlive their workspaces Flags: - -h, --help help for agent - -i, --identity string Identity file (private key) - --port int The port on this computer the session forwards T3 Code to (default 3773) - --start Start the workspace first if it is stopped - --timeout duration How long to wait for the workspace to be running; by default, until the control plane gives up on it + -h, --help[=true|false] help for agent + -i, --identity string Identity file (private key) + --port int The port on this computer the session forwards T3 Code to (default 3773) + --start[=true|false] Start the workspace first if it is stopped + --timeout duration How long to wait for the workspace to be running; by default, until the control plane gives up on it Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -71,7 +71,7 @@ Available Commands: list Your agent homes, and which workspace mounts each Flags: - -h, --help help for home + -h, --help[=true|false] help for home Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -91,7 +91,7 @@ Usage: spin agent home delete [flags] Flags: - -h, --help help for delete + -h, --help[=true|false] help for delete Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -109,7 +109,7 @@ Usage: spin agent home list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/api-key.md b/src/content/docs/reference/cli/api-key.md index 918c2be..509dcff 100644 --- a/src/content/docs/reference/cli/api-key.md +++ b/src/content/docs/reference/cli/api-key.md @@ -26,7 +26,7 @@ Available Commands: revoke Revoke an API key Flags: - -h, --help help for api-key + -h, --help[=true|false] help for api-key Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -70,7 +70,7 @@ 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 help for create + -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 --project strings A project whose workspaces the key reaches, by id (can be repeated; default: any) @@ -93,7 +93,7 @@ Usage: spin api-key list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -111,8 +111,8 @@ Usage: spin api-key revoke [flags] Flags: - -h, --help help for revoke - -y, --yes Skip confirmation + -h, --help[=true|false] help for revoke + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/code.md b/src/content/docs/reference/cli/code.md index faaed3f..8410854 100644 --- a/src/content/docs/reference/cli/code.md +++ b/src/content/docs/reference/cli/code.md @@ -19,20 +19,24 @@ runs), through whichever the editor has of Microsoft's Remote-SSH extension on Open VSX). --editor names the editor's command when it is not 'code'. With Remote-SSH, before VS Code connects, the workspace is asked whether it has the server for -your VS Code. When it has not, it is given it while it runs - published first if this installation -has not got that version, which takes minutes once and is said as it goes. Where that cannot -be done, VS Code downloads its own server into the workspace (about 220 MB), which this says. +your VS Code. When it has not, it is given it while it runs - prepared first if this installation +has not got that version, once for the whole installation, which this waits for and says as it +goes. Where that cannot be done - nobody accepted the server's terms in Admin → Extensions, or +the publish failed - VS Code downloads its own server into the workspace's temporary directory +(about 220 MB), which this says - or, where that directory has no room for it, refuses with what +resolves it, rather than leave VS Code to fail the download and reconnect without end. With Open Remote - SSH, the editor downloads and runs its own server in the workspace, as that extension is set up to; spin writes the SSH config and opens the folder, and nothing more. Spin installs and configures neither extension. The server an installation -publishes is Microsoft's, licensed for internal use only: one that sells workspaces to others -leaves VS Code to download its own. +publishes is Microsoft's, licensed for an organization's own use. An editor that runs spin itself - the Spinbox extension - names its own commit with --vscode-commit and --no-open: no local 'code' is looked for, the workspace is given that -commit's server as above, the SSH config is written, and nothing is opened. +commit's server as above, the SSH config is written, and nothing is opened. With -o json the +answer is JSON Lines: a {"preparing": {...}} line for each step of a server being prepared, then +the result, whose not_given says why the workspace was not given one. Examples: spin code my-workspace @@ -44,10 +48,10 @@ Usage: Flags: --editor string The editor's command, one with Remote-SSH or Open Remote - SSH installed (default "code") - -h, --help help for code + -h, --help[=true|false] help for code -i, --identity string Identity file (private key); default: the first key this machine holds that your keyring lists - --no-open Write the SSH config and give the workspace the server, and open nothing; needs --vscode-commit - --start Start the workspace first if it is stopped + --no-open[=true|false] Write the SSH config and give the workspace the server, and open nothing; needs --vscode-commit + --start[=true|false] Start the workspace first if it is stopped --timeout duration How long to wait for the workspace to be running; by default, until the control plane gives up on it --vscode-commit string The commit of the VS Code that will connect, instead of asking a local 'code'; needs --no-open --vscode-version string The version of that VS Code, which is only said; needs --vscode-commit diff --git a/src/content/docs/reference/cli/cp.md b/src/content/docs/reference/cli/cp.md index 34a5f50..122263f 100644 --- a/src/content/docs/reference/cli/cp.md +++ b/src/content/docs/reference/cli/cp.md @@ -24,11 +24,11 @@ Usage: spin cp [flags] Flags: - -h, --help help for cp - -i, --identity string Identity file (private key) - --start Start the workspace first if it is stopped - --timeout duration How long to wait for the workspace to be running; by default, until the control plane gives up on it - -u, --user string User to copy as (default "root") + -h, --help[=true|false] help for cp + -i, --identity string Identity file (private key) + --start[=true|false] Start the workspace first if it is stopped + --timeout duration How long to wait for the workspace to be running; by default, until the control plane gives up on it + -u, --user string User to copy as (default "root") Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/exec.md b/src/content/docs/reference/cli/exec.md index 7d0336a..62ef498 100644 --- a/src/content/docs/reference/cli/exec.md +++ b/src/content/docs/reference/cli/exec.md @@ -37,16 +37,16 @@ Usage: spin exec -- [args...] [flags] Flags: - --attach string Print a detached run's output until it ends, and exit with its status - -d, --detach Start the command, print its run id and leave it running - -h, --help help for exec - -i, --identity string Identity file (private key) - --no-tty Do not allocate a terminal - --start Start the workspace first if it is stopped - --timeout duration How long to wait for the workspace to be running; by default, until the control plane gives up on it - -t, --tty Allocate a terminal even if this one is not - -u, --user string User to run the command as (default "root") - -w, --workdir string Directory to run the command in + --attach string Print a detached run's output until it ends, and exit with its status + -d, --detach[=true|false] Start the command, print its run id and leave it running + -h, --help[=true|false] help for exec + -i, --identity string Identity file (private key) + --no-tty[=true|false] Do not allocate a terminal + --start[=true|false] Start the workspace first if it is stopped + --timeout duration How long to wait for the workspace to be running; by default, until the control plane gives up on it + -t, --tty[=true|false] Allocate a terminal even if this one is not + -u, --user string User to run the command as (default "root") + -w, --workdir string Directory to run the command in Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/git.md b/src/content/docs/reference/cli/git.md index 05a452d..76bf949 100644 --- a/src/content/docs/reference/cli/git.md +++ b/src/content/docs/reference/cli/git.md @@ -29,7 +29,7 @@ Available Commands: repos List the repositories your account reaches, or those whose name has query in it Flags: - -h, --help help for git + -h, --help[=true|false] help for git Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -54,9 +54,9 @@ Usage: spin git connect [flags] Flags: - --forge string The forge (default "github") - -h, --help help for connect - --no-browser Do not open the forge's page in a browser + --forge string The forge (default "github") + -h, --help[=true|false] help for connect + --no-browser[=true|false] Do not open the forge's page in a browser Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -75,8 +75,8 @@ Usage: spin git disconnect [flags] Flags: - -h, --help help for disconnect - -y, --yes Skip confirmation + -h, --help[=true|false] help for disconnect + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -94,7 +94,7 @@ Usage: spin git list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -112,8 +112,8 @@ Usage: spin git repos [query] [flags] Flags: - --forge string The forge (default "github") - -h, --help help for repos + --forge string The forge (default "github") + -h, --help[=true|false] help for repos Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/index.md b/src/content/docs/reference/cli/index.md index 4d298f5..1ae7a13 100644 --- a/src/content/docs/reference/cli/index.md +++ b/src/content/docs/reference/cli/index.md @@ -51,7 +51,7 @@ Available Commands: Flags: --config string config file (default is $HOME/.spin/config.yaml) - -h, --help help for spin + -h, --help[=true|false] help for spin -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/login.md b/src/content/docs/reference/cli/login.md index d471782..bceb66c 100644 --- a/src/content/docs/reference/cli/login.md +++ b/src/content/docs/reference/cli/login.md @@ -40,10 +40,10 @@ Usage: spin login [flags] Flags: - --endpoint string API endpoint URL (default: SPIN_ENDPOINT, the profile's, or https://app.spinbox.dev) - -h, --help help for login - --no-browser do not open the code's page in a browser; with -o json, write the code as a first line of JSON - --token-stdin read an API key (Settings > API Keys) from standard input instead of signing in with a code + --endpoint string API endpoint URL (default: SPIN_ENDPOINT, the profile's, or https://app.spinbox.dev) + -h, --help[=true|false] help for login + --no-browser[=true|false] do not open the code's page in a browser; with -o json, write the code as a first line of JSON + --token-stdin[=true|false] read an API key (Settings > API Keys) from standard input instead of signing in with a code Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/logout.md b/src/content/docs/reference/cli/logout.md index 112a798..409f1a4 100644 --- a/src/content/docs/reference/cli/logout.md +++ b/src/content/docs/reference/cli/logout.md @@ -16,7 +16,7 @@ Usage: spin logout [flags] Flags: - -h, --help help for logout + -h, --help[=true|false] help for logout Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/mcp.md b/src/content/docs/reference/cli/mcp.md index c7f2e06..bb91665 100644 --- a/src/content/docs/reference/cli/mcp.md +++ b/src/content/docs/reference/cli/mcp.md @@ -24,7 +24,7 @@ Usage: spin mcp [flags] Flags: - -h, --help help for mcp + -h, --help[=true|false] help for mcp Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/open.md b/src/content/docs/reference/cli/open.md index 32c1e12..990e6f1 100644 --- a/src/content/docs/reference/cli/open.md +++ b/src/content/docs/reference/cli/open.md @@ -17,7 +17,7 @@ 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, and its first access is signed here with a key of your +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. Examples: @@ -29,13 +29,14 @@ Usage: spin open [flags] Flags: - -h, --help help for open - --name string Workspace name (auto-generated if empty) - --no-connect Create the workspace and print it, without connecting - --project string The project to open, by slug, when more than one has the repository - --team string The team the workspace is made in, by id, path or me (your personal team if empty) - --timeout duration How long --wait waits; by default, until the control plane gives up on it - --wait Return once the workspace is running, with --no-connect + -h, --help[=true|false] help for open + --name string Workspace name (auto-generated if empty) + --no-connect[=true|false] Create the workspace and print it, without connecting + --preset string The preset it is sized by, by name (default: the project's) + --project string The project to open, by slug, when more than one has the repository + --team string The team the workspace is made in, by id, path or me (your personal team if empty) + --timeout duration How long --wait waits; by default, until the control plane gives up on it + --wait[=true|false] Return once the workspace is running, with --no-connect Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/port.md b/src/content/docs/reference/cli/port.md index 67df134..9d67396 100644 --- a/src/content/docs/reference/cli/port.md +++ b/src/content/docs/reference/cli/port.md @@ -25,7 +25,7 @@ Available Commands: unexpose Unexpose a port from a workspace Flags: - -h, --help help for port + -h, --help[=true|false] help for port Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -52,7 +52,7 @@ Usage: spin port access [flags] Flags: - -h, --help help for access + -h, --help[=true|false] help for access Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -89,8 +89,8 @@ Usage: Flags: --access string who may reach it: private (the default), whitelist or public --description string Description of the exposed port - -h, --help help for expose - --https The port speaks TLS; the proxy does not verify its certificate, and its URL is {port}s- + -h, --help[=true|false] help for expose + --https[=true|false] The port speaks TLS; the proxy does not verify its certificate, and its URL is {port}s- Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -114,7 +114,7 @@ Usage: spin port grant [flags] Flags: - -h, --help help for grant + -h, --help[=true|false] help for grant Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -137,7 +137,7 @@ Usage: spin port list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -158,7 +158,7 @@ Usage: spin port revoke [flags] Flags: - -h, --help help for revoke + -h, --help[=true|false] help for revoke Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -182,7 +182,7 @@ Usage: spin port unexpose [flags] Flags: - -h, --help help for unexpose + -h, --help[=true|false] help for unexpose Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/project.md b/src/content/docs/reference/cli/project.md index 86bb67e..de74304 100644 --- a/src/content/docs/reference/cli/project.md +++ b/src/content/docs/reference/cli/project.md @@ -34,7 +34,7 @@ Available Commands: update Save a project whole: every flag is what it becomes Flags: - -h, --help help for project + -h, --help[=true|false] help for project Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -60,10 +60,11 @@ Usage: Flags: --description string A line about it - -h, --help help for create + -h, --help[=true|false] help for create --image string The image a workspace of it starts from (default: the installation's) --name string What the project is called --network-tag strings A network policy a workspace of it runs under, by name (repeatable) + --prebuild-keep int32 How many of each ref's newest prebuilds are kept when no workspace was opened from them (default: 1) --prebuild-rebase-every int32 Every how many builds of a ref one is built from the image again (default: 10) --prebuild-ref stringArray A ref it prebuilds: built as it moves, and what opening the project at it is cloned from (repeatable; the builds run as you) --preset string The preset a workspace of it is sized by (default: the installation's) @@ -87,8 +88,8 @@ Usage: spin project delete [flags] Flags: - -h, --help help for delete - -y, --yes Skip confirmation + -h, --help[=true|false] help for delete + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -106,7 +107,7 @@ Usage: spin project list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -126,7 +127,7 @@ Usage: spin project prebuild [flags] Flags: - -h, --help help for prebuild + -h, --help[=true|false] help for prebuild Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -147,7 +148,7 @@ Usage: spin project prebuilds [flags] Flags: - -h, --help help for prebuilds + -h, --help[=true|false] help for prebuilds Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -170,11 +171,11 @@ Usage: spin project share [flags] Flags: - --admin stringArray A person who administers it, by id (repeatable; at least one) - --everyone Everybody signed in sees it - -h, --help help for share - --team stringArray A team whose members see it, by id, path or me (repeatable) - --user stringArray A person who sees it, by id (repeatable) + --admin stringArray A person who administers it, by id (repeatable; at least one) + --everyone[=true|false] Everybody signed in sees it + -h, --help[=true|false] help for share + --team stringArray A team whose members see it, by id, path or me (repeatable) + --user stringArray A person who sees it, by id (repeatable) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -195,10 +196,11 @@ Usage: Flags: --description string A line about it - -h, --help help for update + -h, --help[=true|false] help for update --image string The image a workspace of it starts from (default: the installation's) --name string What the project is called --network-tag strings A network policy a workspace of it runs under, by name (repeatable) + --prebuild-keep int32 How many of each ref's newest prebuilds are kept when no workspace was opened from them (default: 1) --prebuild-rebase-every int32 Every how many builds of a ref one is built from the image again (default: 10) --prebuild-ref stringArray A ref it prebuilds: built as it moves, and what opening the project at it is cloned from (repeatable; the builds run as you) --preset string The preset a workspace of it is sized by (default: the installation's) diff --git a/src/content/docs/reference/cli/settings.md b/src/content/docs/reference/cli/settings.md index 6d8cb6c..d1f4262 100644 --- a/src/content/docs/reference/cli/settings.md +++ b/src/content/docs/reference/cli/settings.md @@ -26,7 +26,7 @@ Available Commands: taskfile Configure startup Taskfile Flags: - -h, --help help for settings + -h, --help[=true|false] help for settings Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -51,11 +51,11 @@ Usage: spin settings dotfiles [flags] Flags: - --branch string Branch to clone (default "main") - --clear Clear dotfiles configuration - -h, --help help for dotfiles - --install string Install command (default "./install.sh") - --repo string Git repository URL + --branch string Branch to clone (default "main") + --clear[=true|false] Clear dotfiles configuration + -h, --help[=true|false] help for dotfiles + --install string Install command (default "./install.sh") + --repo string Git repository URL Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -73,7 +73,7 @@ Usage: spin settings get [flags] Flags: - -h, --help help for get + -h, --help[=true|false] help for get Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -101,7 +101,7 @@ Usage: spin settings set [flags] Flags: - -h, --help help for set + -h, --help[=true|false] help for set Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -124,10 +124,10 @@ Usage: spin settings taskfile [flags] Flags: - --clear Clear Taskfile configuration - --file string Taskfile to upload - -h, --help help for taskfile - --validate string Validate a Taskfile without saving + --clear[=true|false] Clear Taskfile configuration + --file string Taskfile to upload + -h, --help[=true|false] help for taskfile + --validate string Validate a Taskfile without saving Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/share.md b/src/content/docs/reference/cli/share.md index ea495aa..37a74b5 100644 --- a/src/content/docs/reference/cli/share.md +++ b/src/content/docs/reference/cli/share.md @@ -29,7 +29,7 @@ Available Commands: remove Remove a user's access to a snapshot Flags: - -h, --help help for share + -h, --help[=true|false] help for share Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -49,8 +49,8 @@ Usage: spin share add [flags] Flags: - --acknowledge-findings Give the snapshot away although its files hold what looks like credentials - -h, --help help for add + --acknowledge-findings[=true|false] Give the snapshot away although its files hold what looks like credentials + -h, --help[=true|false] help for add Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -68,8 +68,8 @@ Usage: spin share browse [flags] Flags: - -h, --help help for browse - --public Include public snapshots (default true) + -h, --help[=true|false] help for browse + --public[=true|false] Include public snapshots (default true) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -87,7 +87,7 @@ Usage: spin share list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -105,7 +105,7 @@ Usage: spin share private [flags] Flags: - -h, --help help for private + -h, --help[=true|false] help for private Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -123,8 +123,8 @@ Usage: spin share public [flags] Flags: - --acknowledge-findings Give the snapshot away although its files hold what looks like credentials - -h, --help help for public + --acknowledge-findings[=true|false] Give the snapshot away although its files hold what looks like credentials + -h, --help[=true|false] help for public Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -142,7 +142,7 @@ Usage: spin share remove [flags] Flags: - -h, --help help for remove + -h, --help[=true|false] help for remove Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/smoke.md b/src/content/docs/reference/cli/smoke.md index 26ded69..da83edf 100644 --- a/src/content/docs/reference/cli/smoke.md +++ b/src/content/docs/reference/cli/smoke.md @@ -29,7 +29,7 @@ Usage: spin smoke [flags] Flags: - -h, --help help for smoke + -h, --help[=true|false] help for smoke --image string The image to start from (default: the installation's) --network-tag strings Network policy to run under, by name (repeatable) --preset string The preset it is sized by (default: the installation's) diff --git a/src/content/docs/reference/cli/snapshot.md b/src/content/docs/reference/cli/snapshot.md index f9cb0b6..fa7020b 100644 --- a/src/content/docs/reference/cli/snapshot.md +++ b/src/content/docs/reference/cli/snapshot.md @@ -26,7 +26,7 @@ Available Commands: list List a workspace's snapshots, including those of disks it was restored away from Flags: - -h, --help help for snapshot + -h, --help[=true|false] help for snapshot Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -48,11 +48,11 @@ Usage: spin snapshot create [flags] Flags: - --description string What the snapshot is of - -h, --help help for create - --timeout duration How long --wait waits (default 5m0s) - --wait Return once the snapshot is published - --with-memory Keep the running processes too, so a restore resumes them + --description string What the snapshot is of + -h, --help[=true|false] help for create + --timeout duration How long --wait waits (default 5m0s) + --wait[=true|false] Return once the snapshot is published + --with-memory[=true|false] Keep the running processes too, so a restore resumes them Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -70,8 +70,8 @@ Usage: spin snapshot delete [flags] Flags: - -h, --help help for delete - -y, --yes Skip confirmation + -h, --help[=true|false] help for delete + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -97,9 +97,9 @@ Usage: spin snapshot diff [flags] Flags: - --from string The earlier snapshot (default: what the workspace was created from) - -h, --help help for diff - --under string Compare only this path of the filesystem, from its root (default: all of it) + --from string The earlier snapshot (default: what the workspace was created from) + -h, --help[=true|false] help for diff + --under string Compare only this path of the filesystem, from its root (default: all of it) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -117,7 +117,7 @@ Usage: spin snapshot list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/ssh-config.md b/src/content/docs/reference/cli/ssh-config.md index 698ed0c..b2a6fdf 100644 --- a/src/content/docs/reference/cli/ssh-config.md +++ b/src/content/docs/reference/cli/ssh-config.md @@ -25,8 +25,8 @@ Usage: spin ssh-config [flags] Flags: - -h, --help help for ssh-config - -i, --identity string Identity file (private key); default: the first key this machine holds that your keyring lists + -h, --help[=true|false] help for ssh-config + -i, --identity string Identity file (private key); default: the first key this machine holds that your keyring lists Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/ssh-key.md b/src/content/docs/reference/cli/ssh-key.md index 55a02f3..8fa68c1 100644 --- a/src/content/docs/reference/cli/ssh-key.md +++ b/src/content/docs/reference/cli/ssh-key.md @@ -27,7 +27,7 @@ Available Commands: list List the SSH keys you log in with Flags: - -h, --help help for ssh-key + -h, --help[=true|false] help for ssh-key Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -55,8 +55,8 @@ Usage: spin ssh-key add [flags] Flags: - -h, --help help for add - --no-browser print the page where your passkey confirms, instead of opening it + -h, --help[=true|false] help for add + --no-browser[=true|false] print the page where your passkey confirms, instead of opening it Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -74,8 +74,8 @@ Usage: spin ssh-key delete [flags] Flags: - -h, --help help for delete - -y, --yes Skip confirmation + -h, --help[=true|false] help for delete + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -93,7 +93,7 @@ Usage: spin ssh-key list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/ssh.md b/src/content/docs/reference/cli/ssh.md index ebcd39d..621b110 100644 --- a/src/content/docs/reference/cli/ssh.md +++ b/src/content/docs/reference/cli/ssh.md @@ -23,11 +23,11 @@ Usage: spin ssh [ssh-argument...] [flags] Flags: - -h, --help help for ssh - -i, --identity string Identity file (private key) - --start Start the workspace first if it is stopped - --timeout duration How long to wait for the workspace to be running; by default, until the control plane gives up on it - -u, --user string SSH username (certificates are issued for root today) (default "root") + -h, --help[=true|false] help for ssh + -i, --identity string Identity file (private key) + --start[=true|false] Start the workspace first if it is stopped + --timeout duration How long to wait for the workspace to be running; by default, until the control plane gives up on it + -u, --user string SSH username (certificates are issued for root today) (default "root") Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/team.md b/src/content/docs/reference/cli/team.md index c9d9d63..84b887a 100644 --- a/src/content/docs/reference/cli/team.md +++ b/src/content/docs/reference/cli/team.md @@ -29,7 +29,7 @@ Available Commands: secret Manage the secrets the egress proxy adds for a team's workspaces Flags: - -h, --help help for team + -h, --help[=true|false] help for team Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -55,7 +55,7 @@ Usage: Flags: --description string Team description - -h, --help help for create + -h, --help[=true|false] help for create --parent string Parent team ID or path --slug string URL-friendly slug (auto-generated if empty) @@ -76,9 +76,9 @@ Usage: spin team delete [flags] Flags: - -h, --help help for delete - --recursive Delete children too (dangerous!) - -y, --yes Skip confirmation + -h, --help[=true|false] help for delete + --recursive[=true|false] Delete children too (dangerous!) + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -96,7 +96,7 @@ Usage: spin team get [flags] Flags: - -h, --help help for get + -h, --help[=true|false] help for get Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -114,9 +114,9 @@ Usage: spin team list [flags] Flags: - --all Include all descendant teams - -h, --help help for list - --parent string Filter by parent team + --all[=true|false] Include all descendant teams + -h, --help[=true|false] help for list + --parent string Filter by parent team Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -141,7 +141,7 @@ Available Commands: role Update a member's role Flags: - -h, --help help for member + -h, --help[=true|false] help for member Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -161,8 +161,8 @@ Usage: spin team member add [flags] Flags: - -h, --help help for add - --role string Role: owner, admin, member (default "member") + -h, --help[=true|false] help for add + --role string Role: owner, admin, member (default "member") Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -180,7 +180,7 @@ Usage: spin team member list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -198,7 +198,7 @@ Usage: spin team member remove [flags] Flags: - -h, --help help for remove + -h, --help[=true|false] help for remove Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -216,7 +216,7 @@ Usage: spin team member role [flags] Flags: - -h, --help help for role + -h, --help[=true|false] help for role Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -243,7 +243,7 @@ Available Commands: set Make a team's policy, or replace what it allows Flags: - -h, --help help for policy + -h, --help[=true|false] help for policy Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -263,8 +263,8 @@ Usage: spin team policy delete [flags] Flags: - -h, --help help for delete - -y, --yes Skip confirmation + -h, --help[=true|false] help for delete + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -282,7 +282,7 @@ Usage: spin team policy list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -306,8 +306,8 @@ Usage: spin team policy set [flags] Flags: - -h, --help help for set - --rule stringArray Destinations and ports, as dest,dest:port,port (repeatable) + -h, --help[=true|false] help for set + --rule stringArray Destinations and ports, as dest,dest:port,port (repeatable) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -335,7 +335,7 @@ Available Commands: set Set a team's secret, read from standard input or kept in Secrets Manager or Parameter Store Flags: - -h, --help help for secret + -h, --help[=true|false] help for secret Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -355,8 +355,8 @@ Usage: spin team secret delete [flags] Flags: - -h, --help help for delete - -y, --yes Skip confirmation + -h, --help[=true|false] help for delete + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -374,7 +374,7 @@ Usage: spin team secret list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -404,9 +404,9 @@ Usage: spin team secret set [flags] Flags: - -h, --help help for set - --host stringArray A host the secret may be sent to, named exactly (repeatable) - --ref string The ARN of the Secrets Manager secret or the Parameter Store parameter the team keeps the value in + -h, --help[=true|false] help for set + --host stringArray A host the secret may be sent to, named exactly (repeatable) + --ref string The ARN of the Secrets Manager secret or the Parameter Store parameter the team keeps the value in Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/update.md b/src/content/docs/reference/cli/update.md index 504bdb6..7217c9c 100644 --- a/src/content/docs/reference/cli/update.md +++ b/src/content/docs/reference/cli/update.md @@ -21,7 +21,7 @@ Usage: spin update [flags] Flags: - -h, --help help for update + -h, --help[=true|false] help for update Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/version.md b/src/content/docs/reference/cli/version.md index 84df3f9..ec08955 100644 --- a/src/content/docs/reference/cli/version.md +++ b/src/content/docs/reference/cli/version.md @@ -16,7 +16,7 @@ Usage: spin version [flags] Flags: - -h, --help help for version + -h, --help[=true|false] help for version Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/vscode.md b/src/content/docs/reference/cli/vscode.md index 6e06b08..7afc900 100644 --- a/src/content/docs/reference/cli/vscode.md +++ b/src/content/docs/reference/cli/vscode.md @@ -20,7 +20,7 @@ Available Commands: install Install the Spinbox extension that carries this CLI's release into VS Code Flags: - -h, --help help for vscode + -h, --help[=true|false] help for vscode Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -55,8 +55,8 @@ Usage: spin vscode install [flags] Flags: - --editor string The editor's command: code, code-insiders, codium, cursor (default "code") - -h, --help help for install + --editor string The editor's command: code, code-insiders, codium, cursor (default "code") + -h, --help[=true|false] help for install Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/whoami.md b/src/content/docs/reference/cli/whoami.md index af1db7c..9f2ea1c 100644 --- a/src/content/docs/reference/cli/whoami.md +++ b/src/content/docs/reference/cli/whoami.md @@ -16,7 +16,7 @@ Usage: spin whoami [flags] Flags: - -h, --help help for whoami + -h, --help[=true|false] help for whoami Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/cli/workspace.md b/src/content/docs/reference/cli/workspace.md index 7ae9675..472749d 100644 --- a/src/content/docs/reference/cli/workspace.md +++ b/src/content/docs/reference/cli/workspace.md @@ -54,7 +54,7 @@ Available Commands: watch Record where a workspace connects, into its logs Flags: - -h, --help help for workspace + -h, --help[=true|false] help for workspace Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -80,7 +80,7 @@ Usage: spin workspace bandwidth [flags] Flags: - -h, --help help for bandwidth + -h, --help[=true|false] help for bandwidth Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -105,10 +105,10 @@ Usage: spin workspace clone [flags] Flags: - -h, --help help for clone - --name string The clone's name (generated if empty) - --timeout duration How long --wait waits; by default, until the control plane gives up on it - --wait Return once the clone is running + -h, --help[=true|false] help for clone + --name string The clone's name (generated if empty) + --timeout duration How long --wait waits; by default, until the control plane gives up on it + --wait[=true|false] Return once the clone is running Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -132,8 +132,8 @@ Usage: spin workspace console [flags] Flags: - -h, --help help for console - --lines int32 How many lines from the end (default 200) + -h, --help[=true|false] help for console + --lines int32 How many lines from the end (default 200) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -155,8 +155,9 @@ You log in to it with a key you added ('spin ssh-key add'), and so does each gue What it applies of yours - dotfiles, shell, environment, editor settings, Taskfile, and this workspace's own --env over your environment - is your settings, as you saved them. -A project (--project) is the workspace's shape - its image, preset and network policies - and -the repository its guest clones into /workspace/, at --ref or the project's own; +A project (--project) is the workspace's shape - its image and network policies, and its preset +unless --preset names another - and the repository its guest clones into +/workspace/, at --ref or the project's own; the workspace is made in --team, or your personal team. A project whose repository is on GitHub opens once you have connected your GitHub account (Settings → Git in the dashboard). @@ -166,6 +167,7 @@ Examples: spin workspace create --name build --env GOPROXY=direct --network-tag registry-only spin workspace create --name copy --from-snapshot spin workspace create --team /engineering --project qboot --ref release/2 + spin workspace create --project qboot --preset large Usage: spin workspace create [flags] @@ -174,16 +176,16 @@ Flags: --agent-home string An agent's home of yours to mount, by id (spin agent home list): the chats of a workspace since erased --env strings Environment variables (KEY=VALUE) --from-snapshot string Start from a snapshot instead of an image - -h, --help help for create + -h, --help[=true|false] help for create --image string the ref of the disk image to start from, with its version (default: the base image of the machine this installation runs) --name string Workspace name (auto-generated if empty) --network-tag strings Network policy to run under, by name (repeatable) - --preset string The preset it is sized by, by name (default: the installation's) + --preset string The preset it is sized by, by name (default: the project's, or the installation's) --project string A project to open, by slug: its image, preset and policies, and its repository cloned --ref string The branch or tag to open the project at (default: the project's) --team string The team, by id, path or me (your personal team if empty) --timeout duration How long --wait waits; by default, until the control plane gives up on it - --wait Return once the workspace is running + --wait[=true|false] Return once the workspace is running Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -203,10 +205,10 @@ Usage: spin workspace delete [flags] Flags: - --force Delete it in a state a delete is otherwise refused in: one stuck starting or stopping - -h, --help help for delete - --permanently Erase it now instead of keeping it in the trash - -y, --yes Skip confirmation + --force[=true|false] Delete it in a state a delete is otherwise refused in: one stuck starting or stopping + -h, --help[=true|false] help for delete + --permanently[=true|false] Erase it now instead of keeping it in the trash + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -224,7 +226,7 @@ Usage: spin workspace deleted [flags] Flags: - -h, --help help for deleted + -h, --help[=true|false] help for deleted Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -244,8 +246,8 @@ Usage: spin workspace denials [flags] Flags: - -h, --help help for denials - --limit int32 How many of the newest to read (default 100) + -h, --help[=true|false] help for denials + --limit int32 How many of the newest to read (default 100) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -269,7 +271,7 @@ Usage: spin workspace egress [flags] Flags: - -h, --help help for egress + -h, --help[=true|false] help for egress Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -287,7 +289,7 @@ Usage: spin workspace get [flags] Flags: - -h, --help help for get + -h, --help[=true|false] help for get Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -321,11 +323,11 @@ Usage: spin workspace grant [flags] Flags: - --cpu int32 Cores it is to hold - --for duration How long the grant lasts before it is given back on its own (default: until it is given back) - -h, --help help for grant - --memory int32 Memory it is to hold, in MB - --move Move it to a host with room when its own has none (it is paused while it moves) + --cpu int32 Cores it is to hold + --for duration How long the grant lasts before it is given back on its own (default: until it is given back) + -h, --help[=true|false] help for grant + --memory int32 Memory it is to hold, in MB + --move[=true|false] Move it to a host with room when its own has none (it is paused while it moves) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -350,7 +352,7 @@ Available Commands: remove Take a guest out Flags: - -h, --help help for guests + -h, --help[=true|false] help for guests Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -370,8 +372,8 @@ Usage: spin workspace guests add [flags] Flags: - -h, --help help for add - --no-browser print the page where your passkey confirms, instead of opening it + -h, --help[=true|false] help for add + --no-browser[=true|false] print the page where your passkey confirms, instead of opening it Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -389,7 +391,7 @@ Usage: spin workspace guests list [flags] Flags: - -h, --help help for list + -h, --help[=true|false] help for list Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -408,7 +410,7 @@ Usage: spin workspace guests remove [flags] Flags: - -h, --help help for remove + -h, --help[=true|false] help for remove Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -426,8 +428,8 @@ Usage: spin workspace history [flags] Flags: - -h, --help help for history - --limit int32 Number of events to show (default 50) + -h, --help[=true|false] help for history + --limit int32 Number of events to show (default 50) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -449,7 +451,7 @@ Usage: spin workspace keep [flags] Flags: - -h, --help help for keep + -h, --help[=true|false] help for keep Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -467,8 +469,8 @@ Usage: spin workspace list [flags] Flags: - -h, --help help for list - --state string Filter by state (running, stopped, etc.) + -h, --help[=true|false] help for list + --state string Filter by state (running, stopped, etc.) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -494,9 +496,9 @@ Usage: spin workspace logs [query] [flags] Flags: - -h, --help help for logs - --limit int32 how many lines, newest first: 1 to 1000 (default 100) - --since duration how far back to look, at most 744h (31 days) (default 1h0m0s) + -h, --help[=true|false] help for logs + --limit int32 how many lines, newest first: 1 to 1000 (default 100) + --since duration how far back to look, at most 744h (31 days) (default 1h0m0s) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -521,7 +523,7 @@ Usage: spin workspace move [flags] Flags: - -h, --help help for move + -h, --help[=true|false] help for move Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -545,7 +547,7 @@ Usage: spin workspace policies [flags] Flags: - -h, --help help for policies + -h, --help[=true|false] help for policies Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -566,9 +568,9 @@ Usage: spin workspace quarantine [flags] Flags: - -h, --help help for quarantine - --reason string Why it is held: kept on the audit entry for the act - -y, --yes Skip confirmation + -h, --help[=true|false] help for quarantine + --reason string Why it is held: kept on the audit entry for the act + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -592,8 +594,8 @@ Usage: spin workspace recover [flags] Flags: - --accept-data-loss go ahead and give up the work the old host had not published - -h, --help help for recover + --accept-data-loss[=true|false] go ahead and give up the work the old host had not published + -h, --help[=true|false] help for recover Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -613,7 +615,7 @@ Usage: spin workspace release [flags] Flags: - -h, --help help for release + -h, --help[=true|false] help for release Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -636,10 +638,10 @@ Usage: spin workspace reset [flags] Flags: - -h, --help help for reset - --start Start the workspace on the disk it was created from and wait until it is running - --timeout duration How long --start waits; by default, until the control plane gives up on it - -y, --yes Skip confirmation + -h, --help[=true|false] help for reset + --start[=true|false] Start the workspace on the disk it was created from and wait until it is running + --timeout duration How long --start waits; by default, until the control plane gives up on it + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -665,10 +667,10 @@ Usage: spin workspace restore [snapshot-id] [flags] Flags: - -h, --help help for restore - --start Start the workspace on the restored disk and wait until it is running - --timeout duration How long --start waits; by default, until the control plane gives up on it - --with-memory Resume the snapshot's processes too; the workspace may be running + -h, --help[=true|false] help for restore + --start[=true|false] Start the workspace on the restored disk and wait until it is running + --timeout duration How long --start waits; by default, until the control plane gives up on it + --with-memory[=true|false] Resume the snapshot's processes too; the workspace may be running Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -700,7 +702,7 @@ Usage: spin workspace retag [flags] Flags: - -h, --help help for retag + -h, --help[=true|false] help for retag --network-tag strings Network policy to run under, by name (repeatable); the whole set, not an addition Global Flags: @@ -723,10 +725,10 @@ Usage: spin workspace start [flags] Flags: - --from-disk boot a suspended workspace from its disk, dropping the memory it was suspended with - -h, --help help for start - --timeout duration How long --wait waits; by default, until the control plane gives up on it - --wait Return once the workspace is running + --from-disk[=true|false] boot a suspended workspace from its disk, dropping the memory it was suspended with + -h, --help[=true|false] help for start + --timeout duration How long --wait waits; by default, until the control plane gives up on it + --wait[=true|false] Return once the workspace is running Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -749,7 +751,7 @@ Usage: spin workspace status [flags] Flags: - -h, --help help for status + -h, --help[=true|false] help for status Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -770,10 +772,10 @@ Usage: spin workspace stop [flags] Flags: - --force Stop the machine without waiting for the guest; also ends a stop that did not finish - -h, --help help for stop - --timeout duration How long --wait waits; by default, until the control plane gives up on it - --wait Return once the workspace is stopped + --force[=true|false] Stop the machine without waiting for the guest; also ends a stop that did not finish + -h, --help[=true|false] help for stop + --timeout duration How long --wait waits; by default, until the control plane gives up on it + --wait[=true|false] Return once the workspace is stopped Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -800,7 +802,7 @@ Usage: spin workspace suspend [flags] Flags: - -h, --help help for suspend + -h, --help[=true|false] help for suspend Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -820,7 +822,7 @@ Usage: spin workspace threads [flags] Flags: - -h, --help help for threads + -h, --help[=true|false] help for threads Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -840,7 +842,7 @@ Usage: spin workspace undelete [flags] Flags: - -h, --help help for undelete + -h, --help[=true|false] help for undelete Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -861,8 +863,8 @@ Usage: spin workspace unquarantine [flags] Flags: - -h, --help help for unquarantine - -y, --yes Skip confirmation + -h, --help[=true|false] help for unquarantine + -y, --yes[=true|false] Skip confirmation Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -888,10 +890,10 @@ Usage: spin workspace update [flags] Flags: - --env strings Environment variables (KEY=VALUE) - -h, --help help for update - --name string New workspace name - --wake-on-access Resume it, when suspended, for a signed-in visitor of one of its ports (never an anonymous one) + --env strings Environment variables (KEY=VALUE) + -h, --help[=true|false] help for update + --name string New workspace name + --wake-on-access[=true|false] Resume it, when suspended, for a signed-in visitor of one of its ports (never an anonymous one) Global Flags: --config string config file (default is $HOME/.spin/config.yaml) @@ -915,8 +917,8 @@ Usage: spin workspace watch [flags] Flags: - -h, --help help for watch - --off Stop recording where the workspace connects + -h, --help[=true|false] help for watch + --off[=true|false] Stop recording where the workspace connects Global Flags: --config string config file (default is $HOME/.spin/config.yaml) diff --git a/src/content/docs/reference/configuration/file.md b/src/content/docs/reference/configuration/file.md index 91e3e65..e9ddd33 100644 --- a/src/content/docs/reference/configuration/file.md +++ b/src/content/docs/reference/configuration/file.md @@ -56,16 +56,6 @@ settings: # named and only allowing - nothing brokered. Any team may then reach past what the policies # below allow, so it is off unless decided. team_network_policies: false - # Whether the control plane fetches VS Code servers from Microsoft on its own: the newest stable - # release, looked for daily, and the server of a client's commit the installation has not - # released, and at start the release this one pins. Off, it fetches none, and workspaces get - # the servers an administrator published; no image carries one. - vscode_fetch: false - # Whether the control plane fetches the agent CLIs - Claude Code and Codex - from their - # publishers on its own: the pair this release pins at start, and the newest of each, looked - # for daily. Off, it fetches none, and workspaces get the pair an operator published; no image - # carries one. - agents_fetch: false # 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; it reads only a secret or a parameter tagged the # same. Unset, a team's secrets are sealed in the database and none is a reference. @@ -138,7 +128,9 @@ registration: - acme.com - contractor@example.com -# What a person may choose when creating a workspace. One preset may be the default. +# 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. # 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 # grows to its size; to_host starts at the floor and grows to what its host has. diff --git a/src/content/docs/reference/security/known-gaps.md b/src/content/docs/reference/security/known-gaps.md index 7ec4348..05a884a 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/dafe286161a95bb1dd1dba3a99f722946ad65961/docs/security/README.md) at `dafe28616`. 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/b7ba5206f12ba93a829a48e354be7fce6bc65db4/docs/security/README.md) at `b7ba5206f`. 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. diff --git a/src/content/docs/reference/security/rules.md b/src/content/docs/reference/security/rules.md index cf43ac7..c14fdc1 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/dafe286161a95bb1dd1dba3a99f722946ad65961/docs/security/README.md) at `dafe28616`. 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/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/). | # | Rule | Gate | |---|---|---| diff --git a/src/content/docs/reference/status/index.md b/src/content/docs/reference/status/index.md index a1783a2..28e6bbe 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/dafe286161a95bb1dd1dba3a99f722946ad65961/docs/ROADMAP.md). The page is written by `task reference` from `spin features` at spin `dafe28616`, 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/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. ## Built @@ -17,130 +17,132 @@ 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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/vm_test.go#L189), a test of `internal/e2e` | [`TestAWorkspaceBootsARealGuest`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/vm_test.go#L189) | -| Create, start, stop and delete | [`WorkspaceService/CreateWorkspace`](/reference/api/workspaceservice/) | [`TestE2E_WorkspaceCRUD`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/background_test.go#L381), a test of `internal/e2e` | [`TestATrashedWorkspaceIsWholeWhenItsOwnerUndeletesIt`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/background_test.go#L413)
[`TestAWorkspaceWhoseDaysInTheTrashAreUpIsErasedFromItsHost`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/background_test.go#L381) | -| Idle suspend, with a question before it that a keep answers | [`TestAWorkspaceIsAskedBeforeItsSuspensionAndAKeepAnswersIt`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/background_test.go#L108), a test of `internal/e2e` | [`TestAWorkspaceIsAskedBeforeItsSuspensionAndAKeepAnswersIt`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/background_test.go#L70), a test of `internal/e2e` | [`TestAWorkspaceThatRanForAsLongAsAllowedIsSuspended`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/background_test.go#L70) | -| A process inside holds its workspace awake while it lives | [`TestAProcessHoldsItsWorkspaceAwakeWhileItLives`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/background_test.go#L191), a test of `internal/e2e` | [`TestAProcessHoldsItsWorkspaceAwakeWhileItLives`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/background_test.go#L191) | -| Suspend with the processes where they are; a start resumes them | [`TestAWorkspaceNobodyUsesIsSuspendedAndAStartResumesIt`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/background_test.go#L36), a test of `internal/e2e` | [`TestE2E_ASuspendedWorkspaceResumesWhereItWas`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/cmd/cli/journeys_e2e_test.go#L288)
[`TestAWorkspaceNobodyUsesIsSuspendedAndAStartResumesIt`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/background_test.go#L344), a test of `internal/e2e` | [`TestABusyWorkspaceIsLentCoresAndGivesThemBack`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/background_test.go#L344)
[`TestABusyWorkspaceIsLentMemoryAndGivesItBack`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/background_test.go#L290), a test of `internal/e2e` | [`TestAGrantWhoseTimeIsUpIsGivenBackToTheMachine`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/background_test.go#L290)
[`TestAResumedWorkspaceIsGivenWhatItIsGrantedWhileItRuns`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/bandwidth_test.go#L118), a test of `internal/e2e` | [`TestAnAdministratorChangesARunningWorkspacesBandwidth`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/bandwidth_test.go#L118)
[`TestAWorkspacesBandwidthHoldsAcrossItsRunsAndItsRunner`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/hosts_flows_test.go#L65), a test of `internal/e2e` | [`TestHostsAMoveTakesARunningWorkspaceToAnotherHost`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/clone_test.go#L64), a test of `internal/e2e` | [`TestACloneHoldsWhatItsSourceWroteAndItsShape`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/hosts_flows_test.go#L100), a test of `internal/e2e` | [`TestHostsAWorkspaceWhoseHostIsGoneIsRecoveredOnAnother`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/hosts_flows_test.go#L100) | -| A workspace outlives its runner | [`TestAWorkspaceOutlivesItsRunner`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/vm_test.go#L314), a test of `internal/e2e` | [`TestAWorkspaceOutlivesItsRunner`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/vm_test.go#L314) | -| Quarantine, by an administrator | [`WorkspaceService/QuarantineWorkspace`](/reference/api/workspaceservice/) | [`TestE2E_AQuarantinedWorkspaceIsHeldUntilReleased`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/cmd/cli/journeys_e2e_test.go#L337)
[`TestE2E_AWorkspacesConsoleIsWhatItsMachinePrinted`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/env_test.go#L22), a test of `internal/e2e` | [`TestTheOwnersSettingsArriveInTheGuest`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/env_test.go#L74)
[`TestAWorkspacesOwnEnvironmentIsInItsOwnersLoginShell`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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 the installation fetches them (agents_fetch) or an operator publishes them: no image carries Claude Code, which only Anthropic may distribute.* | [`TestTheAgentCLIsAreOnPathWithThePinnedVersions`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/agentclis_test.go#L20), a test of `internal/e2e` | [`TestTheAgentCLIsAreOnPathWithThePinnedVersions`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/agentclis_test.go#L20) | -| 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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/t3_test.go#L79)
[`TestE2E_TheAgentIsServedOnThisComputerWhileTheSessionIsOpen`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/cmd/cli/journeys_e2e_test.go#L94)
[`agent.spec.ts`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/agentcredentials_test.go#L29), a test of `internal/e2e` | [`TestAPersonSignsInToTheAgentOnceForEveryWorkspaceOfTheirs`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/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) | ### 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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/project_test.go#L153), a test of `internal/e2e` | [`TestAProjectsWorkspaceOpensAtTheCommitItWasAskedFor`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/project_test.go#L153)
[`TestE2E_AURLOpensTheWorkspaceItNames`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/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) | | 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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/project_test.go#L27), a test of `internal/e2e` | [`TestAProjectsWorkspaceHasItsRepositoryCheckedOutAtTheRef`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/prebuild_test.go#L24), a test of `internal/e2e` | [`TestAProjectOpensAsItsPrebuildMadeIt`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/prebuild_test.go#L24) | -| A team's workspaces run on the installation's hosts | [`TestATeamsWorkspaceRunsOnTheInstallationsHost`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/team_test.go#L20), a test of `internal/e2e` | [`TestATeamsWorkspaceRunsOnTheInstallationsHost`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/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) | ### 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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/clone_test.go#L64)
[`TestADiskSnapshottedPastTheThresholdIsCompactedWhileItRuns`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/compaction_test.go#L19) | -| Snapshots with memory, resumed with their processes | [`TestARunningWorkspaceResumesFromASnapshotsMemory`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/restore_test.go#L175), a test of `internal/e2e` | [`TestARunningWorkspaceResumesFromASnapshotsMemory`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/restore_test.go#L175) | -| Restore a workspace to a snapshot | [`TestARestoredWorkspaceBootsOnTheSnapshotItWasRestoredTo`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/restore_test.go#L29), a test of `internal/e2e` | [`TestARestoredWorkspaceBootsOnTheSnapshotItWasRestoredTo`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/restore_test.go#L29)
[`TestE2E_TheQuickstartsDiffIsWhatTheSiteShows`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/diff_test.go#L28), a test of `internal/e2e` | [`TestADiffOfTwoSnapshotsNamesWhatWasAddedChangedAndRemoved`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/diff_test.go#L95)
[`TestE2E_TheQuickstartsDiffIsWhatTheSiteShows`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/clone_test.go#L23), a test of `internal/e2e` | [`TestASharedSnapshotIsCreatedFromByThePersonItIsSharedWith`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/cmd/cli/journeys_e2e_test.go#L171) | -| A long chain is compacted while the workspace runs | [`TestADiskSnapshottedPastTheThresholdIsCompactedWhileItRuns`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/compaction_test.go#L19), a test of `internal/e2e` | [`TestADiskSnapshottedPastTheThresholdIsCompactedWhileItRuns`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/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) | ### 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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/retag_test.go#L163), a test of `internal/e2e` | [`TestAWorkspaceNamedNoPolicyReachesNothing`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/retag_test.go#L71)
[`TestChangingAWorkspacesPoliciesReachesTheHostThatRunsIt`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/resolver_test.go#L76), a test of `internal/e2e` | [`TestAWorkspaceAsksItsResolverOnlyWhatItsPolicyNames`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/resolver_test.go#L76) | -| A policy changed reaches the host that runs the workspace | [`TestChangingAWorkspacesPoliciesReachesTheHostThatRunsIt`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/retag_test.go#L24), a test of `internal/e2e` | [`TestAnEditedPolicyChangesWhatARunningGuestReaches`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/retag_test.go#L100)
[`TestChangingAWorkspacesPoliciesReachesTheHostThatRunsIt`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/brokered_test.go#L27), a test of `internal/e2e` | [`TestABrokeredRequestIsSeenAsTheProxyReadIt`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/egress_process_test.go#L21), a test of `internal/e2e` | [`TestTheEgressProxyIsAProcessOfItsOwnThatTheRunnerStartsAgain`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/brokered_test.go#L71), a test of `internal/e2e` | [`TestAPersonsRuleAndAnAgentsOnOneNameEachArriveWithTheirOwnInjection`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/brokered_test.go#L99)
[`TestABrokeredNameForTheAgentIsTheAgentsAlone`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/brokered_test.go#L167), a test of `internal/e2e` | [`TestAWebSocketToABrokeredNameCarriesTheGuestsBytesAndRefusesAPathOutOfScope`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/brokered_test.go#L195)
[`TestAWebSocketToABrokeredNameIsCarriedAfterItsHandshake`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/brokered_test.go#L230), a test of `internal/e2e` | [`TestHTTP2ToABrokeredNameIsTheRealHosts`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/brokered_test.go#L230)
[`TestEachStreamOfAnHTTP2ConnectionToABrokeredNameCarriesTheRulesHeader`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/seal_test.go#L21), a test of `internal/e2e` | [`TestAnAgentReachesOnlyBrokeredNames`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/brokered_test.go#L137)
[`TestARealWorkspaceMarksTheAgentItsSupervisorStarts`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/cmd/proxy/lane_test.go#L144)
[`workspace-sign-in.spec.ts`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/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 | ### 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/dafe286161a95bb1dd1dba3a99f722946ad65961/cmd/cli/e2e_test.go#L1217)
[`auth.spec.ts`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/identity_test.go#L58), a test of `internal/e2e` | [`TestAWorkspacesIdentityIsTheHostsSignatureOfItsSet`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/vscodehotplug_test.go#L23), a test of `internal/e2e` | [`TestTheCarriedVSCodeServerRunsOfflineAndAnswersOverTheSSHTunnel`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/vscodeserver_test.go#L86)
[`TestAVSCodeServerOfAnotherCommitIsHandedToTheRunningMachine`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/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) | ### 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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/config_file_test.go#L92) | -| Resource presets | [`AdminService/CreateResourcePreset`](/reference/api/adminservice/) | [`admin.spec.ts`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/dashboard/e2e/admin.spec.ts#L439): 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/dafe286161a95bb1dd1dba3a99f722946ad65961/dashboard/e2e/admin.spec.ts#L235): closed, open and a domain on the allowlist decide who registers
[`admin.spec.ts`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/dashboard/e2e/admin.spec.ts#L168): 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/dafe286161a95bb1dd1dba3a99f722946ad65961/cmd/cli/e2e_test.go#L609)
[`admin.spec.ts`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/dashboard/e2e/admin.spec.ts#L937): 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/dafe286161a95bb1dd1dba3a99f722946ad65961/cmd/cli/e2e_test.go#L1075)
[`admin.spec.ts`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/dashboard/e2e/admin.spec.ts#L730): 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/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 | | 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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/runner_token_test.go#L99)
[`TestARegistrationTokenExpiredOrRevokedRegistersNothing`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/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) | | 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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/hosts_test.go#L420) | -| A host that reboots brings its workspaces back | [`TestAHostRebootBringsItsWorkspacesBack`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/restart_test.go#L38), a test of `internal/e2e` | [`TestAHostRebootBringsItsWorkspacesBack`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/preemption_test.go#L26), a test of `internal/e2e` | [`TestACloudsReclaimWarningEmptiesTheHostBeforeAnySignal`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/writeback_test.go#L28), a test of `internal/e2e` | [`TestCustomWritebackValuesAreMeasuredOnTheRunner`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/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 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 | |---|---|---| -| Platform logs, workspace logs and traces, searched in the product | [`LogService/SearchPlatformLogs`](/reference/api/logservice/) | [`TestAWorkspacesLinesAndTracesAreFoundBySearchingForIt`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/observe_test.go#L179)
[`TestE2E_TheInstallationsLogsAreSearchable`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/dashboard/e2e/admin.spec.ts#L1223): 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/dafe286161a95bb1dd1dba3a99f722946ad65961/dashboard/e2e/admin.spec.ts#L1192): 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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/host_report_test.go#L98) | +| 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 | 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/dafe286161a95bb1dd1dba3a99f722946ad65961/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/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/suspend_test.go#L126), a test of `internal/e2e` | [`TestAMachineAdoptedWithoutItsReleasesIsSuspendedWithItsDisk`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/internal/e2e/suspend_test.go#L126)
[`TestAVSCodeServerOfAnotherCommitIsHandedToTheRunningMachine`](https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/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/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) | ## Partly there @@ -152,7 +154,6 @@ Each is an item of `docs/ROADMAP.md`, with the command that checks it. - **What a workspace grew to is asked for and never recorded** (Workspaces) - **Placement cannot be told which kind of host a workspace belongs on** (Workspaces) -- **A workspace whose host never comes back is moved only when little would be lost** (Administration) ## Limits @@ -173,5 +174,5 @@ Not planned: a limit of the platform or of where it runs today. [Limitations](/o - **No multi-factor authentication of Spinbox's own** (Access): Sign in through a provider that enforces it. - **No team invitations** (Access): A person signs in once before they can be added to a team; a workspace's guests are invited by email. - **Team roles are fixed** (Access): Owner, admin and member. -- **Nothing pages anyone** (Observability): Metrics, logs and traces stay inside the installation; alert rules fire in its Grafana and no contact point tells anyone. +- **Nothing pages the operator** (Observability): Metrics, logs and traces stay inside the installation; alert rules fire in its Grafana and no contact point tells anyone. A workspace's owner is emailed when it waits for them. - **An update is one way** (Administration): A release older than the one that last started the database refuses to start on it. diff --git a/src/content/docs/security/data.md b/src/content/docs/security/data.md index f378e8d..88ec560 100644 --- a/src/content/docs/security/data.md +++ b/src/content/docs/security/data.md @@ -2,8 +2,8 @@ title: Data and encryption description: How disks, memory snapshots and the installation's secrets are encrypted, where each key lives, and what each kind of delete destroys. reads: - - "spin:docs/security/README.md@v20261108.01" - - "spin:docs/storage/README.md@v20261108.01" + - "spin:docs/security/README.md@v20261110.01" + - "spin:docs/storage/README.md@v20261110.01" - "spin-terraform-aws:modules/controlplane/attested_key.tf@v20261027.02" --- diff --git a/src/content/docs/security/identity.md b/src/content/docs/security/identity.md index 5eb61bf..414fb5a 100644 --- a/src/content/docs/security/identity.md +++ b/src/content/docs/security/identity.md @@ -2,8 +2,8 @@ title: Identity and access description: How users, API keys, runners and machines prove who they are, how every request is authorized, and what limits each machine's cloud role. reads: - - "spin:docs/security/README.md@v20261108.01" - - "spin:internal/controlplane/server/middleware/scopes.go@v20261108.01" + - "spin:docs/security/README.md@v20261110.01" + - "spin:internal/controlplane/server/middleware/scopes.go@v20261110.01" - "spin-terraform-aws:modules/controlplane/boundary.tf@v20261027.02" --- diff --git a/src/content/docs/security/supply-chain.md b/src/content/docs/security/supply-chain.md index 7d8728a..f1c7726 100644 --- a/src/content/docs/security/supply-chain.md +++ b/src/content/docs/security/supply-chain.md @@ -2,8 +2,8 @@ title: Supply chain description: How a release is built, signed and verified, how Spin OS makes every machine run exactly what the release signed, and what each image is made of. reads: - - "spin:docs/releases.md@v20261108.01" - - "spin:docs/machine.md@v20261108.01" + - "spin:docs/releases.md@v20261110.01" + - "spin:docs/machine.md@v20261110.01" --- ## Releases are signed diff --git a/src/content/docs/use/access.md b/src/content/docs/use/access.md index 40d32a2..9f3faee 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/dafe286161a95bb1dd1dba3a99f722946ad65961/docs/decisions/ADR-0031-a-passkey-buys-a-key-the-control-plane-certifies.md). +[ADR-0031](https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/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/cli.md b/src/content/docs/use/cli.md index f388709..09e8365 100644 --- a/src/content/docs/use/cli.md +++ b/src/content/docs/use/cli.md @@ -2,10 +2,10 @@ title: The CLI description: Install the spin CLI, sign in, use profiles for several installations, and get JSON output for scripts. reads: - - "spin:cmd/cli/cmd/root.go@v20261108.01" - - "spin:cmd/cli/cmd/auth.go@v20261108.01" - - "spin:cmd/cli/cmd/errcode.go@v20261108.01" - - "spin:taskfiles/release.yml@v20261108.01" + - "spin:cmd/cli/cmd/root.go@v20261110.01" + - "spin:cmd/cli/cmd/auth.go@v20261110.01" + - "spin:cmd/cli/cmd/errcode.go@v20261110.01" + - "spin:taskfiles/release.yml@v20261110.01" --- `spin` is one binary. It does everything the dashboard does for a user, and the diff --git a/src/content/docs/use/dashboard.md b/src/content/docs/use/dashboard.md index cd860c5..7d4943e 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 v20261108.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 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/). ## A person's workspaces diff --git a/src/content/docs/use/editors.md b/src/content/docs/use/editors.md index 0fcf35e..d51b08f 100644 --- a/src/content/docs/use/editors.md +++ b/src/content/docs/use/editors.md @@ -2,10 +2,10 @@ title: Editors and SSH description: Connect to a workspace with spin ssh, plain ssh, scp and rsync, VS Code Remote-SSH, or the terminal in the dashboard. reads: - - "spin:cmd/cli/cmd/ssh.go@v20261108.01" - - "spin:cmd/cli/cmd/sshconfig.go@v20261108.01" - - "spin:cmd/cli/cmd/code.go@v20261108.01" - - "spin:cmd/cli/cmd/exec.go@v20261108.01" + - "spin:cmd/cli/cmd/ssh.go@v20261110.01" + - "spin:cmd/cli/cmd/sshconfig.go@v20261110.01" + - "spin:cmd/cli/cmd/code.go@v20261110.01" + - "spin:cmd/cli/cmd/exec.go@v20261110.01" --- Every way into a workspace goes through the installation's relay. You never need network access @@ -71,11 +71,11 @@ carries a server: an administrator publishes them from **Admin → Storage**. Before VS Code connects, `spin code` asks the workspace whether it has the server for your VS Code. If it has not, and the installation has published that version, the running workspace -is given it. If the installation has not, it is published first only when the installation -fetches servers from Microsoft on its own (`vscode_fetch` in the -[configuration file](/reference/configuration/file/), off by default), which takes minutes the -first time. Otherwise VS Code downloads its own server into the workspace, about 220 MB, and -`spin code` says so before connecting. +is given it. If the installation has not, it prepares that version first, once for the whole +installation, where an administrator has accepted the server's terms (**Admin → Extensions**). +Otherwise VS Code downloads its own server into the workspace, about 220 MB, and `spin code` +says so before connecting; where the workspace has no room for that download, it refuses and +says what would free it. The server is Microsoft's, and its [licence](https://code.visualstudio.com/license/server) allows it for an organization's own internal use only. An installation that offers workspaces diff --git a/src/data/features.json b/src/data/features.json index 0c506b0..32fab04 100644 --- a/src/data/features.json +++ b/src/data/features.json @@ -516,7 +516,7 @@ "name": "Claude Code, Codex and T3 Code on every workspace's PATH, at the versions the release pins, with their own defaults", "state": "built", "proof": "e2e:TestTheAgentCLIsAreOnPathWithThePinnedVersions", - "note": "Where the installation fetches them (agents_fetch) or an operator publishes them: no image carries Claude Code, which only Anthropic may distribute.", + "note": "Where an administrator accepted their terms (Admin → Extensions) or an operator publishes them: no image carries Claude Code, which only Anthropic may distribute.", "endToEnd": [ "go:internal/e2e.TestTheAgentCLIsAreOnPathWithThePinnedVersions" ] @@ -859,10 +859,19 @@ }, { "area": "Administration", - "name": "A workspace whose host never comes back is moved only when little would be lost", - "state": "not", - "proof": "", - "note": "" + "name": "A workspace whose host never comes back is moved when little would be lost, and its owner is told when it waits for them", + "state": "built", + "proof": "rpc:spin.v1.WorkspaceService/RecoverWorkspace", + "note": "", + "endToEndGap": "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" + }, + { + "area": "Observability", + "name": "A workspace's owner is told by email when it waits for them or something happened to it, each event switchable", + "state": "built", + "proof": "rpc:spin.v1.SettingsService/UpdateNotificationPreferences", + "note": "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.", + "endToEndGap": "no lane has an SMTP server: delivery is tested against a generated mail server, with every attempt and retry recorded (internal/controlplane/notify)" }, { "area": "Observability", @@ -1034,10 +1043,10 @@ }, { "area": "Observability", - "name": "Nothing pages anyone", + "name": "Nothing pages the operator", "state": "limit", "proof": "", - "note": "Metrics, logs and traces stay inside the installation; alert rules fire in its Grafana and no contact point tells anyone." + "note": "Metrics, logs and traces stay inside the installation; alert rules fire in its Grafana and no contact point tells anyone. A workspace's owner is emailed when it waits for them." }, { "area": "Administration", diff --git a/src/data/figures.json b/src/data/figures.json index 1fdb488..627c827 100644 --- a/src/data/figures.json +++ b/src/data/figures.json @@ -1,6 +1,6 @@ { "datapath": { - "source": "https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/docs/network/datapath", + "source": "https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/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/dafe286161a95bb1dd1dba3a99f722946ad65961/docs/network/egress-policy", + "source": "https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/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/dafe286161a95bb1dd1dba3a99f722946ad65961/docs/network/isolation", + "source": "https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/docs/network/isolation", "width": 499, "words": [ "Same address, different segment", @@ -220,7 +220,7 @@ ] }, "traffic": { - "source": "https://github.com/spin-stack/spin/blob/dafe286161a95bb1dd1dba3a99f722946ad65961/docs/security/traffic", + "source": "https://github.com/spin-stack/spin/blob/b7ba5206f12ba93a829a48e354be7fce6bc65db4/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 e7db360..c0878db 100644 --- a/src/data/pricing.json +++ b/src/data/pricing.json @@ -1,6 +1,6 @@ { - "generated": "2026-11-09", - "published": "2026-11-07T00:28:52Z", + "generated": "2026-11-11", + "published": "2026-11-10T17:38:52Z", "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 2dc40f5..993e8f7 100644 --- a/src/data/reference.json +++ b/src/data/reference.json @@ -1,8 +1,8 @@ { "spin": { "installs": "v20261027.01", - "commit": "dafe286161a95bb1dd1dba3a99f722946ad65961", - "tag": "v20261108.01", + "commit": "b7ba5206f12ba93a829a48e354be7fce6bc65db4", + "tag": "v20261110.01", "machine": "v20261026.01" }, "terraform": { @@ -10,15 +10,15 @@ "release": "v20261027.02" }, "brand": { - "commit": "85864c646d05aeedc46af942df0f86674283333d" + "commit": "e5d547cff92ba84137e7d3af0eae5eee04c63cd8" }, "counts": { - "built": 89, + "built": 91, "partial": 0, - "notBuilt": 3, + "notBuilt": 2, "limits": 17, "endToEnd": 83, - "gap": 6 + "gap": 8 }, - "openapiSha256": "3633dc4c9651092c47f1bf60cecde510322e2e148472f8aff582abca2c0dc0cc" + "openapiSha256": "df426012d8424746aed6a141797c96a4e0495082d4dad613dac78bad6b738929" } diff --git a/src/data/shots.json b/src/data/shots.json index f176373..61a6918 100644 --- a/src/data/shots.json +++ b/src/data/shots.json @@ -1,6 +1,6 @@ { - "release": "v20261108.01", - "commit": "dafe286161a95bb1dd1dba3a99f722946ad65961", + "release": "v20261110.01", + "commit": "b7ba5206f12ba93a829a48e354be7fce6bc65db4", "shots": [ { "name": "workspaces", diff --git a/tools/refgen/commands.go b/tools/refgen/commands.go index 7be8fd3..c89213e 100644 --- a/tools/refgen/commands.go +++ b/tools/refgen/commands.go @@ -107,7 +107,8 @@ var ( fence = regexp.MustCompile("^```(bash|sh|shell|console)\\s*$") // A cobra flag line: " -o, --output string text" or " --wait text". The type, // when there is one, is a single word before the description's run of spaces. - flagLine = regexp.MustCompile(`^\s+(?:-(\w), )?--([\w-]+)(?: (\w+))?(?:\s{2,}|$)`) + // A flag that takes no value is printed with the values it may be given, --wait[=true|false]. + flagLine = regexp.MustCompile(`^\s+(?:-(\w), )?--([\w-]+)(?:\[=[^\]\s]*\])?(?: (\w+))?(?:\s{2,}|$)`) ) type shellLine struct { diff --git a/tools/refgen/prose_test.go b/tools/refgen/prose_test.go index 2999002..ace71d9 100644 --- a/tools/refgen/prose_test.go +++ b/tools/refgen/prose_test.go @@ -102,3 +102,20 @@ func TestSpinDocBecomesAPage(t *testing.T) { t.Errorf("shellFences:\n%s\nwant:\n%s", got, want) } } + +// A flag is read from the help whether it takes a value, takes none, or is printed with the +// values a flag that takes none may be given. +func TestFlagsOfReadsEveryFormAFlagIsPrintedIn(t *testing.T) { + flags := flagsOf("Usage:\n spin x [flags]\n\nFlags:\n" + + " -h, --help[=true|false] help for x\n" + + " --name string Workspace name\n" + + " --wait[=true|false] Return once it runs\n" + + " --force Do not wait\n\nGlobal Flags:\n" + + " -o, --output string text or json\n") + for name, value := range map[string]bool{"help": false, "h": false, "name": true, "wait": false, "force": false, "output": true, "o": true} { + f, ok := flags[name] + if !ok || f.value != value { + t.Errorf("--%s: read %v, takes a value %v; want read, takes a value %v", name, ok, f.value, value) + } + } +} diff --git a/versions.yaml b/versions.yaml index 46abb2f..9c4ca6e 100644 --- a/versions.yaml +++ b/versions.yaml @@ -7,8 +7,8 @@ - name: spin kind: git source: https://github.com/spin-stack/spin - version: v20261108.01 - pin: dafe286161a95bb1dd1dba3a99f722946ad65961 + version: v20261110.01 + pin: b7ba5206f12ba93a829a48e354be7fce6bc65db4 track: github-release note: >- The release the site documents (D2: the newest, exactly). The daily sync moves it to the next @@ -29,7 +29,7 @@ kind: git source: https://github.com/spin-stack/brand version: main - pin: 85864c646d05aeedc46af942df0f86674283333d + pin: e5d547cff92ba84137e7d3af0eae5eee04c63cd8 track: branch note: >- The palette and the logos. brand cuts no releases, so its main is what it has to say. The