diff --git a/cli/testdata/coder_server_--help.golden b/cli/testdata/coder_server_--help.golden index 70e81cd42c..d09060409c 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 bfd9ed467b..6a7062d56e 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 aef7e1b05f..9561ab112e 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 c3570a10f9..3d928d115f 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 b999f4a4b5..18075b3d87 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 780872a03a..0fb5b03139 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 e6980788cb..a1f8948a25 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 template authors only.", - xerrors.New("Workspace builds with a custom log level are restricted to template authors only."), + "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, + "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 dc758e5a76..f6d4a0baed 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 1655fb9d2f..ce36d1054f 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 08b77eba69..6db4b529d0 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 61a1e052b0..ef3db56cd6 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 70e81cd42c..d09060409c 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 b026033973..0068cc1920 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 0950b03f1e..2b2df5e5f6 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 7b08798c74..4043ffa370 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 b776d3fc6f..2f545c1c78 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 e0507ea27f..e11947b4a8 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 12f39c8669..ef568fd88f 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, } }