diff --git a/scripts/ci_gate.py b/scripts/ci_gate.py index 646672955..77d4c69ea 100644 --- a/scripts/ci_gate.py +++ b/scripts/ci_gate.py @@ -83,6 +83,7 @@ def git_file(root: Path, revision: str, path: str) -> str: def release_metadata_only(root: Path, base: str, head: str, path: str) -> bool: """Recognize literal stable-version edits, never general packaging changes.""" stable = r"(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)" + marker = "" patterns = { "flake.nix": [rf'(?m)^([ \t]*pname = "rustfs";\n[ \t]*version = ")({stable})(";)$'], "helm/rustfs/Chart.yaml": [rf'(?m)^({key}: ")({stable})(")$' for key in ("version", "appVersion")], @@ -99,12 +100,16 @@ def release_metadata_only(root: Path, base: str, head: str, path: str) -> bool: if not re.fullmatch(rf"100644 blob [0-9a-f]{{40}}\t{re.escape(path)}\x00", entry): return False content, values = git_file(root, revision, path), [] + # Existing markers could make edits to distinct fields collapse + # to identical normalized text. + if marker in content: + return False for pattern in patterns[path]: matches = list(re.finditer(pattern, content)) if len(matches) != 1: return False values.append(matches[0][2]) - content = re.sub(pattern, lambda match: match[1] + "" + match[3], content) + content = re.sub(pattern, lambda match: match[1] + marker + match[3], content) if len(set(values)) != 1: return False normalized.append(content) diff --git a/scripts/test_ci_plan.py b/scripts/test_ci_plan.py index acc8d84ad..dbb3927e4 100644 --- a/scripts/test_ci_plan.py +++ b/scripts/test_ci_plan.py @@ -212,6 +212,15 @@ class PlannerTests(unittest.TestCase): self.repo.write(path, content) self.assertTrue(self.repo.plan(self.repo.commit(), base=baseline)['full_validation']) + def test_installation_metadata_rejects_normalization_marker_collisions(self): + _, files = self.release_metadata_base() + old = files['flake.nix'].replace(' clientVersion =', ' second = pkgs.buildRustPackage {\n pname = "rustfs";\n version = "";\n src = ./other;\n };\n clientVersion =') + self.repo.write('flake.nix', old) + baseline = self.repo.commit() + new = old.replace('version = "1.0.4"', 'version = ""').replace('version = "";\n src = ./other;', 'version = "1.0.5";\n src = ./other;') + self.repo.write('flake.nix', new) + self.assertTrue(self.repo.plan(self.repo.commit(), base=baseline)['full_validation']) + def test_installation_metadata_rejects_missing_files_symlinks_and_mode_changes(self): baseline, files = self.release_metadata_base() for path in files: