chore: loosen static validation when using dynamic parameters (#17516)

Co-authored-by: Steven Masley <stevenmasley@gmail.com>
This commit is contained in:
ケイラ
2025-04-23 10:15:49 -06:00
committed by GitHub
co-authored by Steven Masley
parent 3b4343ddf3
commit 36a72a2b25
10 changed files with 64 additions and 13 deletions
+3
View File
@@ -11453,6 +11453,9 @@ const docTemplate = `{
"autostart_schedule": {
"type": "string"
},
"enable_dynamic_parameters": {
"type": "boolean"
},
"name": {
"type": "string"
},
+3
View File
@@ -10211,6 +10211,9 @@
"autostart_schedule": {
"type": "string"
},
"enable_dynamic_parameters": {
"type": "boolean"
},
"name": {
"type": "string"
},
+3
View File
@@ -676,6 +676,9 @@ func createWorkspace(
if req.TemplateVersionID != uuid.Nil {
builder = builder.VersionID(req.TemplateVersionID)
}
if req.EnableDynamicParameters && api.Experiments.Enabled(codersdk.ExperimentDynamicParameters) {
builder = builder.UsingDynamicParameters()
}
workspaceBuild, provisionerJob, provisionerDaemons, err = builder.Build(
ctx,
+28 -13
View File
@@ -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
@@ -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.
@@ -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),
}
@@ -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)
}
+1
View File
@@ -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) {
+20
View File
@@ -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 {
+2
View File
@@ -1462,6 +1462,7 @@ None
{
"automatic_updates": "always",
"autostart_schedule": "string",
"enable_dynamic_parameters": true,
"name": "string",
"rich_parameter_values": [
{
@@ -1484,6 +1485,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|------------------------------|-------------------------------------------------------------------------------|----------|--------------|---------------------------------------------------------------------------------------------------------|
| `automatic_updates` | [codersdk.AutomaticUpdates](#codersdkautomaticupdates) | false | | |
| `autostart_schedule` | string | false | | |
| `enable_dynamic_parameters` | boolean | false | | |
| `name` | string | true | | |
| `rich_parameter_values` | array of [codersdk.WorkspaceBuildParameter](#codersdkworkspacebuildparameter) | false | | Rich parameter values allows for additional parameters to be provided during the initial provision. |
| `template_id` | string | false | | Template ID specifies which template should be used for creating the workspace. |
+2
View File
@@ -25,6 +25,7 @@ of the template will be used.
{
"automatic_updates": "always",
"autostart_schedule": "string",
"enable_dynamic_parameters": true,
"name": "string",
"rich_parameter_values": [
{
@@ -605,6 +606,7 @@ of the template will be used.
{
"automatic_updates": "always",
"autostart_schedule": "string",
"enable_dynamic_parameters": true,
"name": "string",
"rich_parameter_values": [
{
+1
View File
@@ -467,6 +467,7 @@ export interface CreateWorkspaceRequest {
readonly rich_parameter_values?: readonly WorkspaceBuildParameter[];
readonly automatic_updates?: AutomaticUpdates;
readonly template_version_preset_id?: string;
readonly enable_dynamic_parameters?: boolean;
}
// From codersdk/deployment.go
@@ -282,6 +282,7 @@ const CreateWorkspacePageExperimental: FC = () => {
const workspace = await createWorkspaceMutation.mutateAsync({
...workspaceRequest,
enable_dynamic_parameters: true,
userId: owner.id,
});
onCreateWorkspace(workspace);