From 21d892b75966148125a25a691a1cc49bd52b3219 Mon Sep 17 00:00:00 2001 From: Juanadelacuesta <8647634+Juanadelacuesta@users.noreply.github.com> Date: Mon, 11 Nov 2024 17:43:22 +0100 Subject: [PATCH 1/4] func: User url rules to scape non alphanumeric values in hcl variables --- api/jobs.go | 6 ++---- api/jobs_test.go | 12 +++++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/api/jobs.go b/api/jobs.go index 907f548c434..54344bd357c 100644 --- a/api/jobs.go +++ b/api/jobs.go @@ -12,7 +12,6 @@ import ( "net/url" "sort" "strconv" - "strings" "time" "github.com/hashicorp/cronexpr" @@ -324,6 +323,7 @@ func (j *Jobs) Submission(jobID string, version int, q *QueryOptions) (*JobSubmi if err != nil { return nil, nil, err } + return &sub, qm, nil } @@ -1061,9 +1061,7 @@ func (js *JobSubmission) Canonicalize() { // characters to preserve them. This way, when the job gets stopped and // restarted in the UI, variable values will be parsed correctly. for k, v := range js.VariableFlags { - if strings.Contains(v, "\n") { - js.VariableFlags[k] = strings.ReplaceAll(v, "\n", "\\n") - } + js.VariableFlags[k] = url.QueryEscape(v) } } diff --git a/api/jobs_test.go b/api/jobs_test.go index fa68dcf9ae7..1e22fa80ebf 100644 --- a/api/jobs_test.go +++ b/api/jobs_test.go @@ -1503,7 +1503,17 @@ func TestJobs_JobSubmission_Canonicalize(t *testing.T) { VariableFlags: map[string]string{"test": "foo\nbar"}, } js.Canonicalize() - must.Eq(t, js.VariableFlags["test"], "foo\\nbar") + + must.Eq(t, js.VariableFlags["test"], "foo%0Abar") + }) + + t.Run("non-alphabetic chars", func(t *testing.T) { + js := &JobSubmission{ + Source: "abc123", + VariableFlags: map[string]string{"test": `"foo": "bar"`}, + } + js.Canonicalize() + must.Eq(t, js.VariableFlags["test"], "%22foo%22%3A+%22bar%22") }) } From 677636dcdf9cb4545f5109df3bc0ef8366a26838 Mon Sep 17 00:00:00 2001 From: Juanadelacuesta <8647634+Juanadelacuesta@users.noreply.github.com> Date: Tue, 12 Nov 2024 10:28:44 +0100 Subject: [PATCH 2/4] docs: add changelog --- .changelog/24423.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/24423.txt diff --git a/.changelog/24423.txt b/.changelog/24423.txt new file mode 100644 index 00000000000..d785f7cedf1 --- /dev/null +++ b/.changelog/24423.txt @@ -0,0 +1,3 @@ +```release-note:improvement +api: Sanitise hcl variables before storage on JobSubmission +``` From 0d8cba36b37d679e41d9fab00134f6b82f5f1459 Mon Sep 17 00:00:00 2001 From: Juanadelacuesta <8647634+Juanadelacuesta@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:35:25 +0100 Subject: [PATCH 3/4] func: unscape flags before returning --- command/agent/job_endpoint.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/command/agent/job_endpoint.go b/command/agent/job_endpoint.go index 374422be667..fd0c0c03501 100644 --- a/command/agent/job_endpoint.go +++ b/command/agent/job_endpoint.go @@ -8,6 +8,7 @@ import ( "io" "maps" "net/http" + "net/url" "slices" "strconv" "strings" @@ -493,7 +494,8 @@ func (s *HTTPServer) jobSubmissionQuery(resp http.ResponseWriter, req *http.Requ } var out structs.JobSubmissionResponse - if err := s.agent.RPC("Job.GetJobSubmission", &args, &out); err != nil { + err := s.agent.RPC("Job.GetJobSubmission", &args, &out) + if err != nil { return nil, err } @@ -502,6 +504,13 @@ func (s *HTTPServer) jobSubmissionQuery(resp http.ResponseWriter, req *http.Requ return nil, CodedError(404, "job source not found") } + for k, v := range out.Submission.VariableFlags { + out.Submission.VariableFlags[k], err = url.QueryUnescape(v) + if err != nil { + return nil, err + } + } + return out.Submission, nil } From a186048b8a4c5faceed2581052ed4221f409a72e Mon Sep 17 00:00:00 2001 From: Phil Renaud Date: Thu, 21 Nov 2024 11:14:22 -0500 Subject: [PATCH 4/4] use JSON.stringify instead of bespoke value quoting to handle in-value-multi-line cases --- ui/app/utils/json-to-hcl.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/app/utils/json-to-hcl.js b/ui/app/utils/json-to-hcl.js index ba49a9a5328..36993f1de61 100644 --- a/ui/app/utils/json-to-hcl.js +++ b/ui/app/utils/json-to-hcl.js @@ -16,7 +16,8 @@ export default function jsonToHcl(obj) { for (const key in obj) { const value = obj[key]; - const hclValue = typeof value === 'string' ? `"${value}"` : value; + const hclValue = typeof value === 'string' ? JSON.stringify(value) : value; + hclLines.push(`${key}=${hclValue}\n`); }