diff --git a/cli/testdata/coder_server_--help.golden b/cli/testdata/coder_server_--help.golden index 70e81cd42c997..d09060409c034 100644 --- a/cli/testdata/coder_server_--help.golden +++ b/cli/testdata/coder_server_--help.golden @@ -74,6 +74,9 @@ Use a YAML configuration file when your server launch become unwieldy. Write out the current server config as YAML to stdout. Introspection / Logging Options + --enable-terraform-debug-mode bool, $CODER_ENABLE_TERRAFORM_DEBUG_MODE (default: false) + Allow administrators to enable Terraform debug output. + --log-human string, $CODER_LOGGING_HUMAN (default: /dev/stderr) Output human-readable logs to a given file. diff --git a/cli/testdata/server-config.yaml.golden b/cli/testdata/server-config.yaml.golden index bfd9ed467bca8..6a7062d56eebe 100644 --- a/cli/testdata/server-config.yaml.golden +++ b/cli/testdata/server-config.yaml.golden @@ -197,6 +197,9 @@ introspection: # Output Stackdriver compatible logs to a given file. # (default: , type: string) stackdriverPath: "" + # Allow administrators to enable Terraform debug output. + # (default: false, type: bool) + enableTerraformDebugMode: false oauth2: github: # Client ID for Login with GitHub. diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index aef7e1b05f89d..9561ab112e18b 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -7270,6 +7270,9 @@ const docTemplate = `{ "disable_session_expiry_refresh": { "type": "boolean" }, + "enable_terraform_debug_mode": { + "type": "boolean" + }, "experiments": { "type": "array", "items": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index c3570a10f9c36..3d928d115fc17 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -6493,6 +6493,9 @@ "disable_session_expiry_refresh": { "type": "boolean" }, + "enable_terraform_debug_mode": { + "type": "boolean" + }, "experiments": { "type": "array", "items": { diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index b999f4a4b52c0..18075b3d87cf7 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -316,7 +316,8 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { builder := wsbuilder.New(workspace, database.WorkspaceTransition(createBuild.Transition)). Initiator(apiKey.UserID). RichParameterValues(createBuild.RichParameterValues). - LogLevel(string(createBuild.LogLevel)) + LogLevel(string(createBuild.LogLevel)). + DeploymentValues(api.Options.DeploymentValues) if createBuild.TemplateVersionID != uuid.Nil { builder = builder.VersionID(createBuild.TemplateVersionID) diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index 780872a03aeec..0fb5b03139224 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -640,11 +640,50 @@ func TestWorkspaceBuildStatus(t *testing.T) { func TestWorkspaceBuildDebugMode(t *testing.T) { t.Parallel() + t.Run("DebugModeDisabled", func(t *testing.T) { + t.Parallel() + + // Create user + deploymentValues := coderdtest.DeploymentValues(t) + deploymentValues.EnableTerraformDebugMode = false + + adminClient := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, DeploymentValues: deploymentValues}) + owner := coderdtest.CreateFirstUser(t, adminClient) + + // Template author: create a template + version := coderdtest.CreateTemplateVersion(t, adminClient, owner.OrganizationID, nil) + template := coderdtest.CreateTemplate(t, adminClient, owner.OrganizationID, version.ID) + coderdtest.AwaitTemplateVersionJob(t, adminClient, version.ID) + + // Template author: create a workspace + workspace := coderdtest.CreateWorkspace(t, adminClient, owner.OrganizationID, template.ID) + coderdtest.AwaitWorkspaceBuildJob(t, adminClient, workspace.LatestBuild.ID) + + // Template author: try to start a workspace build in debug mode + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + _, err := adminClient.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + TemplateVersionID: workspace.LatestBuild.TemplateVersionID, + Transition: codersdk.WorkspaceTransitionStart, + LogLevel: "debug", + }) + + // Template author: expect an error as the debug mode is disabled + require.NotNil(t, err) + var sdkError *codersdk.Error + isSdkError := xerrors.As(err, &sdkError) + require.True(t, isSdkError) + require.Contains(t, sdkError.Message, "Terraform debug mode is disabled in the deployment configuration.") + }) t.Run("AsRegularUser", func(t *testing.T) { t.Parallel() // Create users - templateAuthorClient := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + deploymentValues := coderdtest.DeploymentValues(t) + deploymentValues.EnableTerraformDebugMode = true + + templateAuthorClient := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, DeploymentValues: deploymentValues}) templateAuthor := coderdtest.CreateFirstUser(t, templateAuthorClient) regularUserClient, _ := coderdtest.CreateAnotherUser(t, templateAuthorClient, templateAuthor.OrganizationID) @@ -672,15 +711,54 @@ func TestWorkspaceBuildDebugMode(t *testing.T) { var sdkError *codersdk.Error isSdkError := xerrors.As(err, &sdkError) require.True(t, isSdkError) - require.Contains(t, sdkError.Message, "Workspace builds with a custom log level are restricted to template authors only.") + require.Contains(t, sdkError.Message, "Workspace builds with a custom log level are restricted to administrators only.") }) t.Run("AsTemplateAuthor", func(t *testing.T) { t.Parallel() // Create users - adminClient := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + deploymentValues := coderdtest.DeploymentValues(t) + deploymentValues.EnableTerraformDebugMode = true + + adminClient := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, DeploymentValues: deploymentValues}) + admin := coderdtest.CreateFirstUser(t, adminClient) + templateAuthorClient, _ := coderdtest.CreateAnotherUser(t, adminClient, admin.OrganizationID, rbac.RoleTemplateAdmin()) + + // Template author: create a template + version := coderdtest.CreateTemplateVersion(t, templateAuthorClient, admin.OrganizationID, nil) + template := coderdtest.CreateTemplate(t, templateAuthorClient, admin.OrganizationID, version.ID) + coderdtest.AwaitTemplateVersionJob(t, templateAuthorClient, version.ID) + + // Template author: create a workspace + workspace := coderdtest.CreateWorkspace(t, templateAuthorClient, admin.OrganizationID, template.ID) + coderdtest.AwaitWorkspaceBuildJob(t, templateAuthorClient, workspace.LatestBuild.ID) + + // Template author: try to start a workspace build in debug mode + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + _, err := templateAuthorClient.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + TemplateVersionID: workspace.LatestBuild.TemplateVersionID, + Transition: codersdk.WorkspaceTransitionStart, + LogLevel: "debug", + }) + + // Template author: expect an error as the debug mode is disabled + require.NotNil(t, err) + var sdkError *codersdk.Error + isSdkError := xerrors.As(err, &sdkError) + require.True(t, isSdkError) + require.Contains(t, sdkError.Message, "Workspace builds with a custom log level are restricted to administrators only.") + }) + t.Run("AsAdmin", func(t *testing.T) { + t.Parallel() + + // Create users + deploymentValues := coderdtest.DeploymentValues(t) + deploymentValues.EnableTerraformDebugMode = true + + adminClient := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, DeploymentValues: deploymentValues}) admin := coderdtest.CreateFirstUser(t, adminClient) - templateAdminClient, _ := coderdtest.CreateAnotherUser(t, adminClient, admin.OrganizationID, rbac.RoleTemplateAdmin()) // Interact as template admin echoResponses := &echo.Responses{ @@ -713,19 +791,19 @@ func TestWorkspaceBuildDebugMode(t *testing.T) { }, }}, } - version := coderdtest.CreateTemplateVersion(t, templateAdminClient, admin.OrganizationID, echoResponses) - template := coderdtest.CreateTemplate(t, templateAdminClient, admin.OrganizationID, version.ID) - coderdtest.AwaitTemplateVersionJob(t, templateAdminClient, version.ID) + version := coderdtest.CreateTemplateVersion(t, adminClient, admin.OrganizationID, echoResponses) + template := coderdtest.CreateTemplate(t, adminClient, admin.OrganizationID, version.ID) + coderdtest.AwaitTemplateVersionJob(t, adminClient, version.ID) // Create workspace - workspace := coderdtest.CreateWorkspace(t, templateAdminClient, admin.OrganizationID, template.ID) - coderdtest.AwaitWorkspaceBuildJob(t, templateAdminClient, workspace.LatestBuild.ID) + workspace := coderdtest.CreateWorkspace(t, adminClient, admin.OrganizationID, template.ID) + coderdtest.AwaitWorkspaceBuildJob(t, adminClient, workspace.LatestBuild.ID) // Create workspace build ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - build, err := templateAdminClient.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + build, err := adminClient.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ TemplateVersionID: workspace.LatestBuild.TemplateVersionID, Transition: codersdk.WorkspaceTransitionStart, ProvisionerState: []byte(" "), @@ -733,10 +811,10 @@ func TestWorkspaceBuildDebugMode(t *testing.T) { }) require.Nil(t, err) - build = coderdtest.AwaitWorkspaceBuildJob(t, templateAdminClient, build.ID) + build = coderdtest.AwaitWorkspaceBuildJob(t, adminClient, build.ID) // Watch for incoming logs - logs, closer, err := templateAdminClient.WorkspaceBuildLogsAfter(ctx, build.ID, 0) + logs, closer, err := adminClient.WorkspaceBuildLogsAfter(ctx, build.ID, 0) require.NoError(t, err) defer closer.Close() diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go index e6980788cb9e8..a1f8948a25aa5 100644 --- a/coderd/wsbuilder/wsbuilder.go +++ b/coderd/wsbuilder/wsbuilder.go @@ -34,11 +34,13 @@ import ( // build, job, err := b.Build(...) type Builder struct { // settings that control the kind of build you get - workspace database.Workspace - trans database.WorkspaceTransition - version versionTarget - state stateTarget - logLevel string + workspace database.Workspace + trans database.WorkspaceTransition + version versionTarget + state stateTarget + logLevel string + deploymentValues *codersdk.DeploymentValues + richParameterValues []codersdk.WorkspaceBuildParameter initiator uuid.UUID reason database.BuildReason @@ -128,6 +130,12 @@ func (b Builder) LogLevel(l string) Builder { return b } +func (b Builder) DeploymentValues(dv *codersdk.DeploymentValues) Builder { + // nolint: revive + b.deploymentValues = dv + return b +} + func (b Builder) Initiator(u uuid.UUID) Builder { // nolint: revive b.initiator = u @@ -638,11 +646,19 @@ func (b *Builder) authorize(authFunc func(action rbac.Action, object rbac.Object } } - if b.logLevel != "" && !authFunc(rbac.ActionUpdate, template) { + if b.logLevel != "" && !authFunc(rbac.ActionRead, rbac.ResourceDeploymentValues) { + return BuildError{ + http.StatusBadRequest, + "Workspace builds with a custom log level are restricted to administrators only.", + xerrors.New("Workspace builds with a custom log level are restricted to administrators only."), + } + } + + if b.logLevel != "" && b.deploymentValues != nil && !b.deploymentValues.EnableTerraformDebugMode { return BuildError{ http.StatusBadRequest, - "Workspace builds with a custom log level are restricted to template authors only.", - xerrors.New("Workspace builds with a custom log level are restricted to template authors only."), + "Terraform debug mode is disabled in the deployment configuration.", + xerrors.New("Terraform debug mode is disabled in the deployment configuration."), } } return nil diff --git a/codersdk/deployment.go b/codersdk/deployment.go index dc758e5a76242..f6d4a0baedfc8 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -165,6 +165,7 @@ type DeploymentValues struct { WgtunnelHost clibase.String `json:"wgtunnel_host,omitempty" typescript:",notnull"` DisableOwnerWorkspaceExec clibase.Bool `json:"disable_owner_workspace_exec,omitempty" typescript:",notnull"` ProxyHealthStatusInterval clibase.Duration `json:"proxy_health_status_interval,omitempty" typescript:",notnull"` + EnableTerraformDebugMode clibase.Bool `json:"enable_terraform_debug_mode,omitempty" typescript:",notnull"` Config clibase.YAMLConfigPath `json:"config,omitempty" typescript:",notnull"` WriteConfig clibase.Bool `json:"write_config,omitempty" typescript:",notnull"` @@ -1215,10 +1216,20 @@ when required by your organization's security policy.`, YAML: "stackdriverPath", Annotations: clibase.Annotations{}.Mark(annotationExternalProxies, "true"), }, + { + Name: "Enable Terraform debug mode", + Description: "Allow administrators to enable Terraform debug output.", + Flag: "enable-terraform-debug-mode", + Env: "CODER_ENABLE_TERRAFORM_DEBUG_MODE", + Default: "false", + Value: &c.EnableTerraformDebugMode, + Group: &deploymentGroupIntrospectionLogging, + YAML: "enableTerraformDebugMode", + }, // ☢️ Dangerous settings { - Name: "DANGEROUS: Allow all CORs requests", - Description: "For security reasons, CORs requests are blocked except between workspace apps owned by the same user. If external requests are required, setting this to true will set all cors headers as '*'. This should never be used in production.", + Name: "DANGEROUS: Allow all CORS requests", + Description: "For security reasons, CORS requests are blocked except between workspace apps owned by the same user. If external requests are required, setting this to true will set all cors headers as '*'. This should never be used in production.", Flag: "dangerous-allow-cors-requests", Env: "CODER_DANGEROUS_ALLOW_CORS_REQUESTS", Hidden: true, // Hidden, should only be used by yarn dev server diff --git a/docs/api/general.md b/docs/api/general.md index 1655fb9d2fb00..ce36d1054fbed 100644 --- a/docs/api/general.md +++ b/docs/api/general.md @@ -196,6 +196,7 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \ "disable_password_auth": true, "disable_path_apps": true, "disable_session_expiry_refresh": true, + "enable_terraform_debug_mode": true, "experiments": ["string"], "git_auth": { "value": [ diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 08b77eba69a11..6db4b529d0587 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -1873,6 +1873,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "disable_password_auth": true, "disable_path_apps": true, "disable_session_expiry_refresh": true, + "enable_terraform_debug_mode": true, "experiments": ["string"], "git_auth": { "value": [ @@ -2204,6 +2205,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "disable_password_auth": true, "disable_path_apps": true, "disable_session_expiry_refresh": true, + "enable_terraform_debug_mode": true, "experiments": ["string"], "git_auth": { "value": [ @@ -2398,6 +2400,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `disable_password_auth` | boolean | false | | | | `disable_path_apps` | boolean | false | | | | `disable_session_expiry_refresh` | boolean | false | | | +| `enable_terraform_debug_mode` | boolean | false | | | | `experiments` | array of string | false | | | | `git_auth` | [clibase.Struct-array_codersdk_GitAuthConfig](#clibasestruct-array_codersdk_gitauthconfig) | false | | | | `http_address` | string | false | | Http address is a string because it may be set to zero to disable. | diff --git a/docs/cli/server.md b/docs/cli/server.md index 61a1e052b0f10..ef3db56cd6314 100644 --- a/docs/cli/server.md +++ b/docs/cli/server.md @@ -223,6 +223,17 @@ Disable workspace apps that are not served from subdomains. Path-based apps can Disable automatic session expiry bumping due to activity. This forces all sessions to become invalid after the session expiry duration has been reached. +### --enable-terraform-debug-mode + +| | | +| ----------- | ----------------------------------------------------------- | +| Type | bool | +| Environment | $CODER_ENABLE_TERRAFORM_DEBUG_MODE | +| YAML | introspection.logging.enableTerraformDebugMode | +| Default | false | + +Allow administrators to enable Terraform debug output. + ### --swagger-enable | | | diff --git a/enterprise/cli/testdata/coder_server_--help.golden b/enterprise/cli/testdata/coder_server_--help.golden index 70e81cd42c997..d09060409c034 100644 --- a/enterprise/cli/testdata/coder_server_--help.golden +++ b/enterprise/cli/testdata/coder_server_--help.golden @@ -74,6 +74,9 @@ Use a YAML configuration file when your server launch become unwieldy. Write out the current server config as YAML to stdout. Introspection / Logging Options + --enable-terraform-debug-mode bool, $CODER_ENABLE_TERRAFORM_DEBUG_MODE (default: false) + Allow administrators to enable Terraform debug output. + --log-human string, $CODER_LOGGING_HUMAN (default: /dev/stderr) Output human-readable logs to a given file. diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index b026033973e1b..0068cc192033e 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -374,6 +374,7 @@ export interface DeploymentValues { readonly wgtunnel_host?: string readonly disable_owner_workspace_exec?: boolean readonly proxy_health_status_interval?: number + readonly enable_terraform_debug_mode?: boolean // This is likely an enum in an external package ("github.com/coder/coder/cli/clibase.YAMLConfigPath") readonly config?: string readonly write_config?: boolean diff --git a/site/src/components/Workspace/Workspace.stories.tsx b/site/src/components/Workspace/Workspace.stories.tsx index 0950b03f1edd3..2b2df5e5f6fcf 100644 --- a/site/src/components/Workspace/Workspace.stories.tsx +++ b/site/src/components/Workspace/Workspace.stories.tsx @@ -156,6 +156,25 @@ export const FailedWithLogs: Story = { }, } +export const FailedWithRetry: Story = { + args: { + ...Running.args, + workspace: { + ...Mocks.MockFailedWorkspace, + latest_build: { + ...Mocks.MockFailedWorkspace.latest_build, + job: { + ...Mocks.MockFailedWorkspace.latest_build.job, + error: + "recv workspace provision: plan terraform: terraform plan: exit status 1", + }, + }, + }, + failedBuildLogs: makeFailedBuildLogs(), + canRetryDebugMode: true, + }, +} + export const Deleting: Story = { args: { ...Running.args, diff --git a/site/src/components/Workspace/Workspace.tsx b/site/src/components/Workspace/Workspace.tsx index 7b08798c74d54..4043ffa37039c 100644 --- a/site/src/components/Workspace/Workspace.tsx +++ b/site/src/components/Workspace/Workspace.tsx @@ -60,7 +60,7 @@ export interface WorkspaceProps { builds?: TypesGen.WorkspaceBuild[] templateWarnings?: TypesGen.TemplateVersionWarning[] canUpdateWorkspace: boolean - canUpdateTemplate: boolean + canRetryDebugMode: boolean canChangeVersions: boolean hideSSHButton?: boolean hideVSCodeDesktopButton?: boolean @@ -92,7 +92,7 @@ export const Workspace: FC> = ({ resources, builds, canUpdateWorkspace, - canUpdateTemplate, + canRetryDebugMode, canChangeVersions, workspaceErrors, hideSSHButton, @@ -236,7 +236,7 @@ export const Workspace: FC> = ({ { jest.spyOn(api, "getTemplate").mockResolvedValueOnce(MockTemplate) jest.spyOn(api, "getTemplateVersionRichParameters").mockResolvedValueOnce([]) + jest + .spyOn(api, "getDeploymentValues") + .mockResolvedValueOnce(MockDeploymentConfig) jest.spyOn(api, "watchStartupLogs").mockImplementation((_, options) => { options.onDone() return new WebSocket("") diff --git a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx index b776d3fc6fe0e..2f545c1c7804f 100644 --- a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx @@ -61,6 +61,7 @@ export const WorkspaceReadyPage = ({ workspace, template, templateVersion, + deploymentValues, builds, getBuildsError, buildError, @@ -75,6 +76,9 @@ export const WorkspaceReadyPage = ({ const deadline = getDeadline(workspace) const canUpdateWorkspace = Boolean(permissions?.updateWorkspace) const canUpdateTemplate = Boolean(permissions?.updateTemplate) + const canRetryDebugMode = + Boolean(permissions?.viewDeploymentValues) && + Boolean(deploymentValues?.enable_terraform_debug_mode) const { t } = useTranslation("workspacePage") const favicon = getFaviconByStatus(workspace.latest_build) const navigate = useNavigate() @@ -166,7 +170,7 @@ export const WorkspaceReadyPage = ({ resources={workspace.latest_build.resources} builds={builds} canUpdateWorkspace={canUpdateWorkspace} - canUpdateTemplate={canUpdateTemplate} + canRetryDebugMode={canRetryDebugMode} canChangeVersions={canUpdateTemplate} hideSSHButton={featureVisibility["browser_only"]} hideVSCodeDesktopButton={featureVisibility["browser_only"]} diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index e0507ea27ff66..e11947b4a845e 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -1583,6 +1583,13 @@ export const MockPermissions: Permissions = { viewDeploymentStats: true, } +export const MockDeploymentConfig: Types.DeploymentConfig = { + config: { + enable_terraform_debug_mode: true, + }, + options: [], +} + export const MockAppearance: TypesGen.AppearanceConfig = { logo_url: "", service_banner: { diff --git a/site/src/xServices/workspace/workspaceXService.ts b/site/src/xServices/workspace/workspaceXService.ts index 12f39c86694e3..ef568fd88ff03 100644 --- a/site/src/xServices/workspace/workspaceXService.ts +++ b/site/src/xServices/workspace/workspaceXService.ts @@ -55,6 +55,7 @@ export interface WorkspaceContext { template?: TypesGen.Template permissions?: Permissions templateVersion?: TypesGen.TemplateVersion + deploymentValues?: TypesGen.DeploymentValues build?: TypesGen.WorkspaceBuild // Builds builds?: TypesGen.WorkspaceBuild[] @@ -100,6 +101,7 @@ export const checks = { readWorkspace: "readWorkspace", updateWorkspace: "updateWorkspace", updateTemplate: "updateTemplate", + viewDeploymentValues: "viewDeploymentValues", } as const const permissionsToCheck = ( @@ -130,6 +132,12 @@ const permissionsToCheck = ( }, action: "update", }, + [checks.viewDeploymentValues]: { + object: { + resource_type: "deployment_config", + }, + action: "read", + }, } as const) export const workspaceMachine = createMachine( @@ -488,6 +496,7 @@ export const workspaceMachine = createMachine( template: (_, event) => event.data.template, templateVersion: (_, event) => event.data.templateVersion, permissions: (_, event) => event.data.permissions as Permissions, + deploymentValues: (_, event) => event.data.deploymentValues, }), assignError: assign({ error: (_, event) => event.data, @@ -740,10 +749,17 @@ async function loadInitialWorkspaceData({ }), ]) + const canViewDeploymentValues = Boolean( + (permissions as Permissions)?.viewDeploymentValues, + ) + const deploymentValues = canViewDeploymentValues + ? (await API.getDeploymentValues())?.config + : undefined return { workspace, template, templateVersion, permissions, + deploymentValues, } }