From 0a27068bdad1fb41228eb0c3a733695b04ba0172 Mon Sep 17 00:00:00 2001 From: emxxapo Date: Tue, 26 May 2026 06:01:04 +0000 Subject: [PATCH 1/2] fix: validate spec:inputs:regex instead of logging a no-op warning Replace the misleading WARN message with actual regex validation. Valid inputs now pass silently; invalid inputs produce a validation error. --- src/parser.ts | 3 +- .../.gitlab-ci-input-template.yml | 9 +++++ .../regex-validation-pass/.gitlab-ci.yml | 7 ++++ .../.gitlab-ci-input-template.yml | 9 +++++ .../regex-validation/.gitlab-ci.yml | 7 ++++ .../include-inputs/integration.test.ts | 38 +++++++++++++++++++ 6 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 tests/test-cases/include-inputs/input-templates/regex-validation-pass/.gitlab-ci-input-template.yml create mode 100644 tests/test-cases/include-inputs/input-templates/regex-validation-pass/.gitlab-ci.yml create mode 100644 tests/test-cases/include-inputs/input-templates/regex-validation/.gitlab-ci-input-template.yml create mode 100644 tests/test-cases/include-inputs/input-templates/regex-validation/.gitlab-ci.yml diff --git a/src/parser.ts b/src/parser.ts index 8abfab4af..70776f44b 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -443,7 +443,8 @@ function validateInput (ctx: any) { const regex = inputsSpecification.spec.inputs[interpolationKey]?.regex; if (regex) { - ctx.writeStreams?.stderr(chalk`{black.bgYellowBright WARN } spec:inputs:regex is currently not supported via gitlab-ci-local. This will just be a no-op.\n`); + assert(new RegExp(regex).test(String(inputValue)), + chalk`This GitLab CI configuration is invalid: \`{blueBright ${configFilePath}}\`: \`{blueBright ${interpolationKey}}\` input: \`{blueBright ${inputValue}}\` does not match required regex: {blueBright ${regex}}.`); } } diff --git a/tests/test-cases/include-inputs/input-templates/regex-validation-pass/.gitlab-ci-input-template.yml b/tests/test-cases/include-inputs/input-templates/regex-validation-pass/.gitlab-ci-input-template.yml new file mode 100644 index 000000000..668afe097 --- /dev/null +++ b/tests/test-cases/include-inputs/input-templates/regex-validation-pass/.gitlab-ci-input-template.yml @@ -0,0 +1,9 @@ +--- +spec: + inputs: + version: + regex: ^v\d+\.\d+\.\d+$ +--- +deploy: + script: + - echo $[[ inputs.version ]] diff --git a/tests/test-cases/include-inputs/input-templates/regex-validation-pass/.gitlab-ci.yml b/tests/test-cases/include-inputs/input-templates/regex-validation-pass/.gitlab-ci.yml new file mode 100644 index 000000000..74492808e --- /dev/null +++ b/tests/test-cases/include-inputs/input-templates/regex-validation-pass/.gitlab-ci.yml @@ -0,0 +1,7 @@ +--- +include: + - local: '/.gitlab-ci-input-template.yml' + inputs: + version: "v1.2.3" +stages: + - test diff --git a/tests/test-cases/include-inputs/input-templates/regex-validation/.gitlab-ci-input-template.yml b/tests/test-cases/include-inputs/input-templates/regex-validation/.gitlab-ci-input-template.yml new file mode 100644 index 000000000..668afe097 --- /dev/null +++ b/tests/test-cases/include-inputs/input-templates/regex-validation/.gitlab-ci-input-template.yml @@ -0,0 +1,9 @@ +--- +spec: + inputs: + version: + regex: ^v\d+\.\d+\.\d+$ +--- +deploy: + script: + - echo $[[ inputs.version ]] diff --git a/tests/test-cases/include-inputs/input-templates/regex-validation/.gitlab-ci.yml b/tests/test-cases/include-inputs/input-templates/regex-validation/.gitlab-ci.yml new file mode 100644 index 000000000..d513876a0 --- /dev/null +++ b/tests/test-cases/include-inputs/input-templates/regex-validation/.gitlab-ci.yml @@ -0,0 +1,7 @@ +--- +include: + - local: '/.gitlab-ci-input-template.yml' + inputs: + version: "invalid-version" +stages: + - test diff --git a/tests/test-cases/include-inputs/integration.test.ts b/tests/test-cases/include-inputs/integration.test.ts index eabd4d6e2..c59467356 100644 --- a/tests/test-cases/include-inputs/integration.test.ts +++ b/tests/test-cases/include-inputs/integration.test.ts @@ -358,3 +358,41 @@ scan-website: expect(writeStreams.stdoutLines[0]).toEqual(expected); }); + +test.concurrent("include-inputs regex validation (invalid)", async () => { + try { + const writeStreams = new WriteStreamsMock(); + await handler({ + cwd: "tests/test-cases/include-inputs/input-templates/regex-validation", + preview: true, + }, writeStreams); + } catch (e: any) { + assert(e instanceof AssertionError, "e is not instanceof AssertionError"); + expect(e.message).toContain("This GitLab CI configuration is invalid:"); + expect(e.message).toContain( + chalk`\`{blueBright version}\` input: \`{blueBright invalid-version}\` does not match required regex: {blueBright ^v\\d+\\.\\d+\\.\\d+$}.`, + ); + return; + } + + throw new Error("Error is expected but not thrown/caught"); +}); + +test.concurrent("include-inputs regex validation (valid)", async () => { + const writeStreams = new WriteStreamsMock(); + await handler({ + cwd: "tests/test-cases/include-inputs/input-templates/regex-validation-pass", + preview: true, + }, writeStreams); + + const expected = `--- +stages: + - .pre + - test + - .post +deploy: + script: + - echo v1.2.3`; + + expect(writeStreams.stdoutLines[0]).toEqual(expected); +}); From 5bd9d6509bbb790bd5a6ce7e15ed2d8f71f39a24 Mon Sep 17 00:00:00 2001 From: emxxapo Date: Tue, 26 May 2026 08:40:36 +0000 Subject: [PATCH 2/2] fix: guard against invalid regex patterns in spec:inputs:regex Invalid regex patterns (e.g. '^[unclosed') now produce a clear configuration error instead of crashing with an uncaught SyntaxError. --- src/parser.ts | 8 +++++++- .../.gitlab-ci-input-template.yml | 9 +++++++++ .../.gitlab-ci.yml | 7 +++++++ .../include-inputs/integration.test.ts | 19 +++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/test-cases/include-inputs/input-templates/regex-validation-invalid-pattern/.gitlab-ci-input-template.yml create mode 100644 tests/test-cases/include-inputs/input-templates/regex-validation-invalid-pattern/.gitlab-ci.yml diff --git a/src/parser.ts b/src/parser.ts index 70776f44b..302f2aa89 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -443,7 +443,13 @@ function validateInput (ctx: any) { const regex = inputsSpecification.spec.inputs[interpolationKey]?.regex; if (regex) { - assert(new RegExp(regex).test(String(inputValue)), + let re: RegExp; + try { + re = new RegExp(regex); + } catch { + assert(false, chalk`This GitLab CI configuration is invalid: \`{blueBright ${configFilePath}}\`: \`{blueBright ${interpolationKey}}\` input: regex \`{blueBright ${regex}}\` is not a valid regular expression.`); + } + assert(re.test(String(inputValue)), chalk`This GitLab CI configuration is invalid: \`{blueBright ${configFilePath}}\`: \`{blueBright ${interpolationKey}}\` input: \`{blueBright ${inputValue}}\` does not match required regex: {blueBright ${regex}}.`); } } diff --git a/tests/test-cases/include-inputs/input-templates/regex-validation-invalid-pattern/.gitlab-ci-input-template.yml b/tests/test-cases/include-inputs/input-templates/regex-validation-invalid-pattern/.gitlab-ci-input-template.yml new file mode 100644 index 000000000..20d1cd156 --- /dev/null +++ b/tests/test-cases/include-inputs/input-templates/regex-validation-invalid-pattern/.gitlab-ci-input-template.yml @@ -0,0 +1,9 @@ +--- +spec: + inputs: + version: + regex: ^[unclosed +--- +deploy: + script: + - echo $[[ inputs.version ]] diff --git a/tests/test-cases/include-inputs/input-templates/regex-validation-invalid-pattern/.gitlab-ci.yml b/tests/test-cases/include-inputs/input-templates/regex-validation-invalid-pattern/.gitlab-ci.yml new file mode 100644 index 000000000..74492808e --- /dev/null +++ b/tests/test-cases/include-inputs/input-templates/regex-validation-invalid-pattern/.gitlab-ci.yml @@ -0,0 +1,7 @@ +--- +include: + - local: '/.gitlab-ci-input-template.yml' + inputs: + version: "v1.2.3" +stages: + - test diff --git a/tests/test-cases/include-inputs/integration.test.ts b/tests/test-cases/include-inputs/integration.test.ts index c59467356..79bb8f5bf 100644 --- a/tests/test-cases/include-inputs/integration.test.ts +++ b/tests/test-cases/include-inputs/integration.test.ts @@ -396,3 +396,22 @@ deploy: expect(writeStreams.stdoutLines[0]).toEqual(expected); }); + +test.concurrent("include-inputs regex validation (invalid pattern)", async () => { + try { + const writeStreams = new WriteStreamsMock(); + await handler({ + cwd: "tests/test-cases/include-inputs/input-templates/regex-validation-invalid-pattern", + preview: true, + }, writeStreams); + } catch (e: any) { + assert(e instanceof AssertionError, "e is not instanceof AssertionError"); + expect(e.message).toContain("This GitLab CI configuration is invalid:"); + expect(e.message).toContain( + chalk`\`{blueBright version}\` input: regex \`{blueBright ^[unclosed}\` is not a valid regular expression.`, + ); + return; + } + + throw new Error("Error is expected but not thrown/caught"); +});