feat(service): auto-inject WORK_DIR and resolve file-type params in task script rendering

- ProcessTask injects $WORK_DIR only when script template uses it

- File/directory type params: resolves file_id to filename before rendering

- ValidateParams validates file/directory params as valid int64 file IDs

- RenderScript no longer shell-escapes file/directory type values

- Log rendered script before submitting to Slurm for debugging

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
dailz
2026-04-16 17:56:28 +08:00
parent c1d0665b42
commit 07ae8ad6cd
2 changed files with 69 additions and 3 deletions

View File

@@ -58,6 +58,9 @@ func ValidateParams(params []model.ParameterSchema, values map[string]string) er
}
}
case model.ParamTypeFile, model.ParamTypeDirectory:
if _, err := strconv.ParseInt(val, 10, 64); err != nil {
errs = append(errs, fmt.Sprintf("parameter %q must be a valid file ID (integer), got %q", p.Name, val))
}
case model.ParamTypeString:
}
}
@@ -71,7 +74,9 @@ func ValidateParams(params []model.ParameterSchema, values map[string]string) er
// RenderScript replaces $PARAM tokens in the template with user-provided values.
// Only tokens defined in the schema are replaced. Replacement is done longest-name-first
// to avoid partial matches (e.g., $JOB_NAME before $JOB).
// All values are shell-escaped using single-quote wrapping.
// String, integer, boolean, and enum values are shell-escaped using single-quote wrapping.
// File and directory values (including WORK_DIR) are inserted raw (no escaping) because
// they are paths used in SBATCH directives and command arguments.
func RenderScript(template string, params []model.ParameterSchema, values map[string]string) string {
sorted := make([]model.ParameterSchema, len(params))
copy(sorted, params)
@@ -79,6 +84,9 @@ func RenderScript(template string, params []model.ParameterSchema, values map[st
return len(sorted[i].Name) > len(sorted[j].Name)
})
// Add virtual "WORK_DIR" entry so $WORK_DIR is replaced without escaping.
sorted = append(sorted, model.ParameterSchema{Name: "WORK_DIR", Type: model.ParamTypeFile})
result := template
for _, p := range sorted {
val, ok := values[p.Name]
@@ -89,8 +97,13 @@ func RenderScript(template string, params []model.ParameterSchema, values map[st
continue
}
}
escaped := "'" + strings.ReplaceAll(val, "'", "'\\''") + "'"
result = strings.ReplaceAll(result, "$"+p.Name, escaped)
if p.Type == model.ParamTypeFile || p.Type == model.ParamTypeDirectory {
result = strings.ReplaceAll(result, "$"+p.Name, val)
} else {
escaped := "'" + strings.ReplaceAll(val, "'", "'\\''") + "'"
result = strings.ReplaceAll(result, "$"+p.Name, escaped)
}
}
return result
}