From d6008688b4bba5d0c0a4a8a5baa7642d6ebe0398 Mon Sep 17 00:00:00 2001 From: Dr Alexander Mikhalev Date: Tue, 13 Oct 2026 22:00:25 +0100 Subject: [PATCH 1/2] fix(ci): classify isolated extension release writers Refs #3488 --- .../workflows/release-manifest-contract.yml | 14 +++ ...workflow_release_recovery_contract_test.py | 95 ++++++++++++++++++- 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-manifest-contract.yml b/.github/workflows/release-manifest-contract.yml index 80025dbfa..a9129b6bb 100644 --- a/.github/workflows/release-manifest-contract.yml +++ b/.github/workflows/release-manifest-contract.yml @@ -12,6 +12,13 @@ on: - ".github/workflows/publish-bun.yml" - ".github/workflows/publish-tauri.yml" - ".github/workflows/release-sign.yml" + - ".github/workflows/continue-integration.yml" + - ".github/workflows/vscode-release.yml" + - "integrations/continue/verify_source.py" + - "integrations/continue/integration.json" + - "vs-code-terraphim-it/package.json" + - "vs-code-terraphim-it/scripts/publish_release.py" + - "vs-code-terraphim-it/scripts/verify_vsix.py" - ".github/scripts/release/**" - ".release/release-manifest.schema.json" - "scripts/requirements-release-manifest.in" @@ -44,6 +51,13 @@ on: - ".github/workflows/publish-bun.yml" - ".github/workflows/publish-tauri.yml" - ".github/workflows/release-sign.yml" + - ".github/workflows/continue-integration.yml" + - ".github/workflows/vscode-release.yml" + - "integrations/continue/verify_source.py" + - "integrations/continue/integration.json" + - "vs-code-terraphim-it/package.json" + - "vs-code-terraphim-it/scripts/publish_release.py" + - "vs-code-terraphim-it/scripts/verify_vsix.py" - ".github/scripts/release/**" - ".release/release-manifest.schema.json" - "scripts/requirements-release-manifest.in" diff --git a/tests/workflow_release_recovery_contract_test.py b/tests/workflow_release_recovery_contract_test.py index 5f3818c4f..cbfc8b0f6 100644 --- a/tests/workflow_release_recovery_contract_test.py +++ b/tests/workflow_release_recovery_contract_test.py @@ -20,6 +20,8 @@ NPM_WORKFLOW = ROOT / ".github/workflows/publish-npm.yml" BUN_WORKFLOW = ROOT / ".github/workflows/publish-bun.yml" TAURI_WORKFLOW = ROOT / ".github/workflows/publish-tauri.yml" +CONTINUE_WORKFLOW = ROOT / ".github/workflows/continue-integration.yml" +VSCODE_WORKFLOW = ROOT / ".github/workflows/vscode-release.yml" CONTRACT_WORKFLOW = ROOT / ".github/workflows/release-manifest-contract.yml" AGENT_EVAL_WORKFLOW = ROOT / ".github/workflows/agent-eval.yml" WORKFLOW_DIR = ROOT / ".github/workflows" @@ -29,7 +31,8 @@ r"uses:\s*[\"']actions/create-release\b|" r"softprops/action-gh-release|gh release (?:create|edit|upload)|" r"repos\.(?:create|update)Release|createRelease|updateRelease|" - r"github-publish-release\.sh", + r"github-publish-release\.sh|" + r"\bpython[0-9.]*\s+[\"']?(?:[\w./-]+/)?publish_release\.py\b", re.IGNORECASE, ) @@ -226,6 +229,8 @@ def setUpClass(cls) -> None: cls.npm_text = NPM_WORKFLOW.read_text(encoding="utf-8") cls.bun_text = BUN_WORKFLOW.read_text(encoding="utf-8") cls.tauri_text = TAURI_WORKFLOW.read_text(encoding="utf-8") + cls.continue_text = CONTINUE_WORKFLOW.read_text(encoding="utf-8") + cls.vscode_text = VSCODE_WORKFLOW.read_text(encoding="utf-8") cls.contract_text = CONTRACT_WORKFLOW.read_text(encoding="utf-8") def test_exhaustive_github_release_writer_inventory_is_single_publisher_safe( @@ -245,6 +250,8 @@ def test_exhaustive_github_release_writer_inventory_is_single_publisher_safe( "publish-tauri.yml", "release-comprehensive.yml", "release-coordinator.yml", + "continue-integration.yml", + "vscode-release.yml", }, "every workflow that writes GitHub releases must be classified", ) @@ -288,6 +295,84 @@ def test_exhaustive_github_release_writer_inventory_is_single_publisher_safe( self.assertIn("refs/tags/app-v", tauri_release) self.assertIn("refs/tags/desktop-v", tauri_release) + def test_extension_writers_retain_component_source_and_qualification_gates(self) -> None: + continuation = job_block(self.continue_text, "attach-to-published-release") + self.assertIn("if: startsWith(github.ref, 'refs/tags/terraphim_continue-v')", continuation) + self.assertTrue(has_need(continuation, "verify-and-package")) + self.assertIn("environment: continue-releases", continuation) + self.assertIn('test "$RELEASE_TAG" = "$expected"', continuation) + self.assertIn("verify_source.py --tag", continuation) + # Every literal release write retains the immediate live-source check. + mutation_lines = continuation.splitlines() + for index, line in enumerate(mutation_lines): + if re.search(r"gh release (?:create|upload|edit)\b", line): + self.assertEqual(mutation_lines[index - 1].strip(), "qualify_source") + + self.assertTrue(has_need(job_block(self.vscode_text, "release"), "qualify")) + self.assertTrue(has_need(job_block(self.vscode_text, "qualify"), "source")) + source = job_block(self.vscode_text, "source") + self.assertIn('test "$REF_TYPE" = tag', source) + self.assertIn("check_tag(os.environ['REF_NAME']", source) + self.assertIn("git merge-base --is-ancestor HEAD origin/main", source) + release = job_block(self.vscode_text, "release") + self.assertIn("environment: extension-releases", release) + self.assertIn("python3 scripts/publish_release.py", release) + self.assertIn('TAG: ${{ github.ref_name }}', release) + self.assertIn("check_native(", release) + + def test_actual_extension_tag_guards_reject_standard_and_other_component_tags(self) -> None: + # Execute the literal pre-mutation guard, not a reimplementation or publisher mock. + continue_step = step_run_block( + job_block(self.continue_text, "attach-to-published-release"), + "Attach separately downloadable integration", + ) + continue_script = textwrap.dedent(continue_step.split("run: |\n", 1)[1]) + self.assertIn("\ncd integration\n", continue_script) + continue_guard = continue_script.split("\ncd integration\n", 1)[0] + vscode_step = step_run_block( + job_block(self.vscode_text, "source"), + "Require an immutable version tag on the reviewed main history", + ) + vscode_script = textwrap.dedent(vscode_step.split("run: |\n", 1)[1]) + self.assertIn("\ngit merge-base --is-ancestor", vscode_script) + vscode_guard = vscode_script.split("\ngit merge-base --is-ancestor", 1)[0] + manifest = json.loads((ROOT / "integrations/continue/integration.json").read_text()) + self.assertEqual(manifest["tagPrefix"], "terraphim_continue-v") + continue_tag = manifest["tagPrefix"] + manifest["version"] + vscode_version = json.loads((ROOT / "vs-code-terraphim-it/package.json").read_text())["version"] + vscode_tag = "terraphim_vscode-v" + vscode_version + candidates = [continue_tag, vscode_tag, "v1.21.20", "main", "python-v1.0.0", + "terraphim_continue-v999.0.0", "terraphim_vscode-v999.0.0", + continue_tag + ";echo unexpected", vscode_tag + "-rc.1"] + for expected, script in [(continue_tag, continue_guard), (vscode_tag, vscode_guard)]: + for tag in candidates: + with self.subTest(writer=expected, tag=tag): + result = subprocess.run( + ["bash", "-euo", "pipefail", "-c", script], cwd=ROOT, + env=dict(os.environ, RELEASE_TAG=tag, REF_TYPE="tag", REF_NAME=tag), + capture_output=True, text=True, timeout=20, + ) + self.assertEqual(result.returncode == 0, tag == expected, result.stderr) + branch = subprocess.run( + ["bash", "-euo", "pipefail", "-c", vscode_guard], cwd=ROOT, + env=dict(os.environ, REF_TYPE="branch", REF_NAME=vscode_tag), + capture_output=True, text=True, timeout=20, + ) + self.assertNotEqual(branch.returncode, 0) + + def test_extension_writer_changes_trigger_contract_on_pr_and_push(self) -> None: + for event in ("pull_request", "push"): + paths = section(section(self.contract_text, "on"), event) + for path in (".github/workflows/continue-integration.yml", + ".github/workflows/vscode-release.yml", + "integrations/continue/verify_source.py", + "integrations/continue/integration.json", + "vs-code-terraphim-it/package.json", + "vs-code-terraphim-it/scripts/publish_release.py", + "vs-code-terraphim-it/scripts/verify_vsix.py"): + with self.subTest(event=event, path=path): + self.assertIn(path, paths) + def test_release_writer_detector_accepts_quoted_and_unquoted_action_syntax( self, ) -> None: @@ -301,6 +386,14 @@ def test_release_writer_detector_accepts_quoted_and_unquoted_action_syntax( with self.subTest(syntax=syntax): self.assertRegex(syntax, GITHUB_RELEASE_WRITER_PATTERN) + def test_release_writer_detector_includes_python_publication_helper(self) -> None: + for syntax in ("python3 scripts/publish_release.py --tag x", + 'python "vs-code-terraphim-it/scripts/publish_release.py"', + "python3.12 './scripts/publish_release.py' --repo org/repo"): + with self.subTest(syntax=syntax): + self.assertRegex(syntax, GITHUB_RELEASE_WRITER_PATTERN) + self.assertNotRegex("python3 scripts/verify_registry.py", GITHUB_RELEASE_WRITER_PATTERN) + def test_bun_release_writer_allows_only_component_tag_and_non_dry_dispatch( self, ) -> None: From d1b816d37177991c69eb6fca3b4f2ebf0b33e93c Mon Sep 17 00:00:00 2001 From: Dr Alexander Mikhalev Date: Tue, 13 Oct 2026 22:02:24 +0100 Subject: [PATCH 2/2] test(ci): report malformed extension manifests explicitly Refs #3488 --- tests/workflow_release_recovery_contract_test.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/workflow_release_recovery_contract_test.py b/tests/workflow_release_recovery_contract_test.py index cbfc8b0f6..657b8c56a 100644 --- a/tests/workflow_release_recovery_contract_test.py +++ b/tests/workflow_release_recovery_contract_test.py @@ -336,10 +336,13 @@ def test_actual_extension_tag_guards_reject_standard_and_other_component_tags(se vscode_script = textwrap.dedent(vscode_step.split("run: |\n", 1)[1]) self.assertIn("\ngit merge-base --is-ancestor", vscode_script) vscode_guard = vscode_script.split("\ngit merge-base --is-ancestor", 1)[0] - manifest = json.loads((ROOT / "integrations/continue/integration.json").read_text()) + try: + manifest = json.loads((ROOT / "integrations/continue/integration.json").read_text()) + vscode_version = json.loads((ROOT / "vs-code-terraphim-it/package.json").read_text())["version"] + except json.JSONDecodeError as error: + self.fail(f"Invalid checked-in extension release manifest: {error}") self.assertEqual(manifest["tagPrefix"], "terraphim_continue-v") continue_tag = manifest["tagPrefix"] + manifest["version"] - vscode_version = json.loads((ROOT / "vs-code-terraphim-it/package.json").read_text())["version"] vscode_tag = "terraphim_vscode-v" + vscode_version candidates = [continue_tag, vscode_tag, "v1.21.20", "main", "python-v1.0.0", "terraphim_continue-v999.0.0", "terraphim_vscode-v999.0.0", @@ -350,13 +353,13 @@ def test_actual_extension_tag_guards_reject_standard_and_other_component_tags(se result = subprocess.run( ["bash", "-euo", "pipefail", "-c", script], cwd=ROOT, env=dict(os.environ, RELEASE_TAG=tag, REF_TYPE="tag", REF_NAME=tag), - capture_output=True, text=True, timeout=20, + check=False, capture_output=True, text=True, timeout=20, ) self.assertEqual(result.returncode == 0, tag == expected, result.stderr) branch = subprocess.run( ["bash", "-euo", "pipefail", "-c", vscode_guard], cwd=ROOT, env=dict(os.environ, REF_TYPE="branch", REF_NAME=vscode_tag), - capture_output=True, text=True, timeout=20, + check=False, capture_output=True, text=True, timeout=20, ) self.assertNotEqual(branch.returncode, 0)