From e79e4e18b3fc868a8224b5477ed4f1dbb941cece Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Sun, 14 Jun 2026 10:45:42 -0400 Subject: [PATCH] fix(#1186): guard hotfix version regex against leading zeros (ADR-218) (#1214) Replace `^[0-9]+\.[0-9]+\.[1-9][0-9]*$` with `^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.[1-9][0-9]*$` in the hotfix branch of the validate-version step, consistent with the two sibling patterns already using the strict (0|[1-9][0-9]*) guard. Adds regression assertions to tests/adr-218-release-version-validation.test.cjs that prove `01.2.3` and `1.02.3` are rejected. Co-authored-by: Claude Opus 4.8 (1M context) --- .github/workflows/release.yml | 2 +- ...dr-218-release-version-validation.test.cjs | 21 +++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 841fde9e5..bf3af0b70 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,7 +65,7 @@ jobs: if echo "$VERSION" | grep -qE '^(0|[1-9][0-9]*)\.0\.0$'; then IS_MAJOR="true" fi - elif echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[1-9][0-9]*$'; then + elif echo "$VERSION" | grep -qE '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.[1-9][0-9]*$'; then # Patch / hotfix release (X.Y.Z, Z>0) IS_HOTFIX="true" if [ "$ACTION" = "rc" ]; then diff --git a/tests/adr-218-release-version-validation.test.cjs b/tests/adr-218-release-version-validation.test.cjs index e22236405..ecf670ecc 100644 --- a/tests/adr-218-release-version-validation.test.cjs +++ b/tests/adr-218-release-version-validation.test.cjs @@ -254,12 +254,21 @@ describe('ADR-218 — leading-zero rejection regex (behavioral)', () => { // Patch = 0 must be rejected (that is the minor/major form) assert.equal(re.test('1.2.0'), false, 'Hotfix pattern must not match X.Y.0 (Z must be >0)'); - // NOTE: The hotfix regex in release.yml currently permits leading zeros on - // the major and minor segments (e.g. `1.01.3` and `01.2.3` both pass). - // This is a known gap tracked in issue #1186. The assertions below are - // intentionally absent for those cases: this test documents CURRENT - // behavior, not ideal behavior. Fix #1186 will harden the pattern and - // add leading-zero rejection assertions here. + // ADR-218 / #1186: hotfix pattern must also reject leading zeros on major + // and minor segments. The old `[0-9]+` form allowed e.g. `01.2.3` and + // `1.02.3`. The corrected pattern uses `(0|[1-9][0-9]*)` for both. + const shouldRejectLeadingZero = [ + '01.2.3', // leading zero in major + '1.02.3', // leading zero in minor + ]; + for (const v of shouldRejectLeadingZero) { + assert.equal( + re.test(v), false, + `Hotfix version "${v}" should be REJECTED (leading zero) but was accepted.\n` + + `Pattern: ${hotfixPatterns[0]}\n` + + `ADR-218 / #1186: restore (0|[1-9][0-9]*) on major and minor segments.` + ); + } }); test('extracted patterns use strict leading-zero guard, not the old [0-9]+ form', () => {