Skip to content

chore: loosen static validation when using dynamic parameters #17516

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
chore: loosen static validation when using dynamic parameters
  • Loading branch information
aslilac committed Apr 22, 2025
commit 89c717b52138ab011addc8d97b69c6d0b993b047
3 changes: 3 additions & 0 deletions coderd/apidoc/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions coderd/apidoc/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions coderd/workspaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,9 @@ func createWorkspace(
if req.TemplateVersionID != uuid.Nil {
builder = builder.VersionID(req.TemplateVersionID)
}
if req.EnableDynamicParameters {
builder = builder.UsingDynamicParameters()
}

workspaceBuild, provisionerJob, provisionerDaemons, err = builder.Build(
ctx,
Expand Down
41 changes: 28 additions & 13 deletions coderd/wsbuilder/wsbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ type Builder struct {
logLevel string
deploymentValues *codersdk.DeploymentValues

richParameterValues []codersdk.WorkspaceBuildParameter
initiator uuid.UUID
reason database.BuildReason
templateVersionPresetID uuid.UUID
richParameterValues []codersdk.WorkspaceBuildParameter
dynamicParametersEnabled bool
initiator uuid.UUID
reason database.BuildReason
templateVersionPresetID uuid.UUID

// used during build, makes function arguments less verbose
ctx context.Context
Expand Down Expand Up @@ -178,6 +179,11 @@ func (b Builder) MarkPrebuild() Builder {
return b
}

func (b Builder) UsingDynamicParameters() Builder {
b.dynamicParametersEnabled = true
return b
}

// SetLastWorkspaceBuildInTx prepopulates the Builder's cache with the last workspace build. This allows us
// to avoid a repeated database query when the Builder's caller also needs the workspace build, e.g. auto-start &
// auto-stop.
Expand Down Expand Up @@ -578,6 +584,7 @@ func (b *Builder) getParameters() (names, values []string, err error) {
if err != nil {
return nil, nil, BuildError{http.StatusBadRequest, "Unable to build workspace with unsupported parameters", err}
}

resolver := codersdk.ParameterResolver{
Rich: db2sdk.WorkspaceBuildParameters(lastBuildParameters),
}
Expand All @@ -586,16 +593,24 @@ func (b *Builder) getParameters() (names, values []string, err error) {
if err != nil {
return nil, nil, BuildError{http.StatusInternalServerError, "failed to convert template version parameter", err}
}
value, err := resolver.ValidateResolve(
tvp,
b.findNewBuildParameterValue(templateVersionParameter.Name),
)
if err != nil {
// At this point, we've queried all the data we need from the database,
// so the only errors are problems with the request (missing data, failed
// validation, immutable parameters, etc.)
return nil, nil, BuildError{http.StatusBadRequest, fmt.Sprintf("Unable to validate parameter %q", templateVersionParameter.Name), err}

var value string
if !b.dynamicParametersEnabled {
var err error
value, err = resolver.ValidateResolve(
tvp,
b.findNewBuildParameterValue(templateVersionParameter.Name),
)
if err != nil {
// At this point, we've queried all the data we need from the database,
// so the only errors are problems with the request (missing data, failed
// validation, immutable parameters, etc.)
return nil, nil, BuildError{http.StatusBadRequest, fmt.Sprintf("Unable to validate parameter %q", templateVersionParameter.Name), err}
}
} else {
value = resolver.Resolve(tvp, b.findNewBuildParameterValue(templateVersionParameter.Name))
}

names = append(names, templateVersionParameter.Name)
values = append(values, value)
}
Expand Down
1 change: 1 addition & 0 deletions codersdk/organizations.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ type CreateWorkspaceRequest struct {
RichParameterValues []WorkspaceBuildParameter `json:"rich_parameter_values,omitempty"`
AutomaticUpdates AutomaticUpdates `json:"automatic_updates,omitempty"`
TemplateVersionPresetID uuid.UUID `json:"template_version_preset_id,omitempty" format:"uuid"`
EnableDynamicParameters bool `json:"enable_dynamic_parameters,omitempty"`
}

func (c *Client) OrganizationByName(ctx context.Context, name string) (Organization, error) {
Expand Down
20 changes: 20 additions & 0 deletions codersdk/richparameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,26 @@ func (r *ParameterResolver) ValidateResolve(p TemplateVersionParameter, v *Works
return resolvedValue.Value, nil
}

// Resolve returns the value of the parameter. It does not do any validation,
// and is meant for use with the new dynamic parameters code path.
func (r *ParameterResolver) Resolve(p TemplateVersionParameter, v *WorkspaceBuildParameter) string {
prevV := r.findLastValue(p)
// First, the provided value
resolvedValue := v
// Second, previous value if not ephemeral
if resolvedValue == nil && !p.Ephemeral {
resolvedValue = prevV
}
// Last, default value
if resolvedValue == nil {
resolvedValue = &WorkspaceBuildParameter{
Name: p.Name,
Value: p.DefaultValue,
}
}
return resolvedValue.Value
}

// findLastValue finds the value from the previous build and returns it, or nil if the parameter had no value in the
// last build.
func (r *ParameterResolver) findLastValue(p TemplateVersionParameter) *WorkspaceBuildParameter {
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/api/schemas.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions docs/reference/api/workspaces.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions site/src/api/typesGenerated.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ const CreateWorkspacePageExperimental: FC = () => {

const workspace = await createWorkspaceMutation.mutateAsync({
...workspaceRequest,
enable_dynamic_parameters: true,
userId: owner.id,
});
onCreateWorkspace(workspace);
Expand Down
Loading