From 53c375987ca0e9339242843b1a9a3f4c93cd16e7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 3 Sep 2026 13:10:44 +0900 Subject: [PATCH 01/18] test(ci): require accounting docs exact-head acceptance --- tests/test_ci_documentation_acceptance.py | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/test_ci_documentation_acceptance.py diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py new file mode 100644 index 00000000..e7ae45ef --- /dev/null +++ b/tests/test_ci_documentation_acceptance.py @@ -0,0 +1,32 @@ +"""Regression contract for authority-bearing documentation acceptance in CI.""" + +from __future__ import annotations + +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +class AccountingDocumentationCiAcceptanceTests(unittest.TestCase): + """Keep documentation changes inside exact-head and integrated-head acceptance.""" + + def test_accounting_ci_does_not_ignore_documentation_changes(self) -> None: + """Docs and Markdown changes must not bypass repository accounting validation.""" + workflow = (ROOT / ".github" / "workflows" / "ci.yml").read_text( + encoding="utf-8" + ) + pull_request_block = workflow.split(" pull_request:", 1)[1].split( + " push:", 1 + )[0] + push_block = workflow.split(" push:", 1)[1].split("\npermissions:", 1)[0] + + for trigger_block in (pull_request_block, push_block): + self.assertNotIn("paths-ignore:", trigger_block) + self.assertNotIn("docs/**", trigger_block) + self.assertNotIn("*.md", trigger_block) + + +if __name__ == "__main__": + unittest.main() From 8ffd39ce1794dc0a018cd8f0434fbd4dead9bd25 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 3 Sep 2026 13:11:04 +0900 Subject: [PATCH 02/18] fix(ci): restore documentation acceptance evidence --- .github/workflows/ci.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cd54bdd3..559934e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,16 +2,10 @@ name: Accounting Foundation CI on: pull_request: - paths-ignore: - - "docs/**" - - "*.md" push: branches: - develop - main - paths-ignore: - - "docs/**" - - "*.md" permissions: contents: read From 2dfd761852256ca70674380e13606342719daf2b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 02:13:09 +0900 Subject: [PATCH 03/18] test(ci): reject all accounting path filters --- tests/test_ci_documentation_acceptance.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index e7ae45ef..84b40602 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -2,6 +2,7 @@ from __future__ import annotations +import re import unittest from pathlib import Path @@ -21,11 +22,15 @@ def test_accounting_ci_does_not_ignore_documentation_changes(self) -> None: " push:", 1 )[0] push_block = workflow.split(" push:", 1)[1].split("\npermissions:", 1)[0] + path_filter = re.compile(r"(?m)^\s+paths(?:-ignore)?:\s*$") for trigger_block in (pull_request_block, push_block): - self.assertNotIn("paths-ignore:", trigger_block) - self.assertNotIn("docs/**", trigger_block) - self.assertNotIn("*.md", trigger_block) + self.assertIsNone( + path_filter.search(trigger_block), + "Accounting Foundation CI pull_request/push triggers must not define " + "paths or paths-ignore filters; authority-bearing documentation must " + "receive the same exact-head acceptance as source changes.", + ) if __name__ == "__main__": From 1055e6397a28a28fedc1756a2ef9d9b9a89e15ee Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 03:02:51 +0900 Subject: [PATCH 04/18] test(ci): reproduce inline path-filter escape --- tests/test_ci_documentation_acceptance.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index 84b40602..6f341662 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -8,11 +8,25 @@ ROOT = Path(__file__).resolve().parents[1] +PATH_FILTER = re.compile(r"(?m)^\s+paths(?:-ignore)?:\s*$") class AccountingDocumentationCiAcceptanceTests(unittest.TestCase): """Keep documentation changes inside exact-head and integrated-head acceptance.""" + def test_path_filter_detection_rejects_inline_yaml_values(self) -> None: + """Inline path filters must be detected as strongly as block-style filters.""" + for trigger_block in ( + " paths: ['src/**']\n", + " paths-ignore: ['docs/**', '*.md']\n", + ): + with self.subTest(trigger_block=trigger_block): + self.assertIsNotNone( + PATH_FILTER.search(trigger_block), + "inline YAML path filters would let documentation bypass Accounting " + "Foundation CI acceptance", + ) + def test_accounting_ci_does_not_ignore_documentation_changes(self) -> None: """Docs and Markdown changes must not bypass repository accounting validation.""" workflow = (ROOT / ".github" / "workflows" / "ci.yml").read_text( @@ -22,11 +36,10 @@ def test_accounting_ci_does_not_ignore_documentation_changes(self) -> None: " push:", 1 )[0] push_block = workflow.split(" push:", 1)[1].split("\npermissions:", 1)[0] - path_filter = re.compile(r"(?m)^\s+paths(?:-ignore)?:\s*$") for trigger_block in (pull_request_block, push_block): self.assertIsNone( - path_filter.search(trigger_block), + PATH_FILTER.search(trigger_block), "Accounting Foundation CI pull_request/push triggers must not define " "paths or paths-ignore filters; authority-bearing documentation must " "receive the same exact-head acceptance as source changes.", From 8835a86790be9f4ac4157659e90b32e3cf67661a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 03:03:17 +0900 Subject: [PATCH 05/18] test(ci): catch inline YAML path filters --- tests/test_ci_documentation_acceptance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index 6f341662..94d59d43 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -8,7 +8,7 @@ ROOT = Path(__file__).resolve().parents[1] -PATH_FILTER = re.compile(r"(?m)^\s+paths(?:-ignore)?:\s*$") +PATH_FILTER = re.compile(r"(?m)^[ \t]+paths(?:-ignore)?:[ \t]*[^\r\n]*$") class AccountingDocumentationCiAcceptanceTests(unittest.TestCase): From 3d15ce19765c42414933093899d3ab59f271a36f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 04:02:38 +0900 Subject: [PATCH 06/18] test(ci): reject flow-style path filters --- tests/test_ci_documentation_acceptance.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index 94d59d43..207834cc 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -27,6 +27,19 @@ def test_path_filter_detection_rejects_inline_yaml_values(self) -> None: "Foundation CI acceptance", ) + def test_path_filter_detection_rejects_flow_style_event_mappings(self) -> None: + """Flow-style event mappings cannot hide paths or paths-ignore filters.""" + for trigger_block in ( + " pull_request: {paths: ['src/**']}\n", + " push: {paths-ignore: ['docs/**', '*.md']}\n", + ): + with self.subTest(trigger_block=trigger_block): + self.assertIsNotNone( + PATH_FILTER.search(trigger_block), + "flow-style YAML path filters would let documentation bypass Accounting " + "Foundation CI acceptance", + ) + def test_accounting_ci_does_not_ignore_documentation_changes(self) -> None: """Docs and Markdown changes must not bypass repository accounting validation.""" workflow = (ROOT / ".github" / "workflows" / "ci.yml").read_text( From 94fba278dcc650948aaddf16e9f0989b1a936cc3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 04:03:10 +0900 Subject: [PATCH 07/18] fix(ci): detect flow-style path filters --- tests/test_ci_documentation_acceptance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index 207834cc..783c1089 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -8,7 +8,7 @@ ROOT = Path(__file__).resolve().parents[1] -PATH_FILTER = re.compile(r"(?m)^[ \t]+paths(?:-ignore)?:[ \t]*[^\r\n]*$") +PATH_FILTER = re.compile(r"(?m)(?:^[ \t]+|[{,][ \t]*)paths(?:-ignore)?[ \t]*:") class AccountingDocumentationCiAcceptanceTests(unittest.TestCase): From b3e0acefb79e5bdbf337cde34d5a706fa7a6f101 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 06:01:49 +0900 Subject: [PATCH 08/18] test(ci): reject quoted path-filter keys --- tests/test_ci_documentation_acceptance.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index 783c1089..88ca5ed2 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -40,6 +40,21 @@ def test_path_filter_detection_rejects_flow_style_event_mappings(self) -> None: "Foundation CI acceptance", ) + def test_path_filter_detection_rejects_quoted_yaml_keys(self) -> None: + """Quoted YAML mapping keys cannot hide paths or paths-ignore filters.""" + for trigger_block in ( + ' "paths": ["src/**"]\n', + " 'paths-ignore': ['docs/**', '*.md']\n", + ' pull_request: {"paths": ["src/**"]}\n', + " push: {'paths-ignore': ['docs/**', '*.md']}\n", + ): + with self.subTest(trigger_block=trigger_block): + self.assertIsNotNone( + PATH_FILTER.search(trigger_block), + "quoted YAML path-filter keys would let documentation bypass Accounting " + "Foundation CI acceptance", + ) + def test_accounting_ci_does_not_ignore_documentation_changes(self) -> None: """Docs and Markdown changes must not bypass repository accounting validation.""" workflow = (ROOT / ".github" / "workflows" / "ci.yml").read_text( From fe8045c70827a1456d5929c416faa653d4e5a5c8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 06:02:25 +0900 Subject: [PATCH 09/18] fix(ci): detect quoted path-filter keys --- tests/test_ci_documentation_acceptance.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index 88ca5ed2..32ecaead 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -8,7 +8,9 @@ ROOT = Path(__file__).resolve().parents[1] -PATH_FILTER = re.compile(r"(?m)(?:^[ \t]+|[{,][ \t]*)paths(?:-ignore)?[ \t]*:") +PATH_FILTER = re.compile( + r"(?m)(?:^[ \t]+|[{,][ \t]*)(?:(?P[\"'])paths(?:-ignore)?(?P=quote)|paths(?:-ignore)?)[ \t]*:" +) class AccountingDocumentationCiAcceptanceTests(unittest.TestCase): From 6771069db55d2b19b49e8bbeab2846461c458047 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 14:06:06 +0900 Subject: [PATCH 10/18] test(ci): cover escaped YAML path-filter keys --- tests/test_ci_documentation_acceptance.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index 32ecaead..0b9f6295 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -57,6 +57,21 @@ def test_path_filter_detection_rejects_quoted_yaml_keys(self) -> None: "Foundation CI acceptance", ) + def test_path_filter_detection_rejects_escaped_quoted_yaml_keys(self) -> None: + """YAML escapes that decode to path-filter keys cannot bypass acceptance.""" + for trigger_block in ( + ' "pa\\u0074hs": ["src/**"]\n', + ' "paths\\x2dignore": ["docs/**"]\n', + ' pull_request: {"pa\\u0074hs": ["src/**"]}\n', + ' push: {"paths\\x2dignore": ["docs/**"]}\n', + ): + with self.subTest(trigger_block=trigger_block): + self.assertIsNotNone( + PATH_FILTER.search(trigger_block), + "escaped quoted YAML path-filter keys would let documentation bypass " + "Accounting Foundation CI acceptance", + ) + def test_accounting_ci_does_not_ignore_documentation_changes(self) -> None: """Docs and Markdown changes must not bypass repository accounting validation.""" workflow = (ROOT / ".github" / "workflows" / "ci.yml").read_text( From 3c9109ccefc869845e139132d511a7df0db5c5b1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 14:07:09 +0900 Subject: [PATCH 11/18] fix(ci): decode escaped YAML path-filter keys --- tests/test_ci_documentation_acceptance.py | 95 ++++++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index 0b9f6295..e21ce7f6 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -8,9 +8,100 @@ ROOT = Path(__file__).resolve().parents[1] -PATH_FILTER = re.compile( - r"(?m)(?:^[ \t]+|[{,][ \t]*)(?:(?P[\"'])paths(?:-ignore)?(?P=quote)|paths(?:-ignore)?)[ \t]*:" +_MAPPING_KEY_PATTERN = re.compile( + r"""(?mx) + (?:^[ \t]+|[{,][ \t]*) + (?P + "(?:\\.|[^"\\])*" + | + '(?:''|[^'])*' + | + [A-Za-z_][A-Za-z0-9_-]* + ) + [ \t]*: + """ ) +_SIMPLE_YAML_ESCAPES = { + "0": "\0", + "a": "\a", + "b": "\b", + "t": "\t", + "n": "\n", + "v": "\v", + "f": "\f", + "r": "\r", + "e": "\x1b", + " ": " ", + '"': '"', + "/": "/", + "\\": "\\", + "N": "\u0085", + "_": "\u00a0", + "L": "\u2028", + "P": "\u2029", +} + + +def _decode_double_quoted_yaml_key(raw_key: str) -> str: + """Decode YAML escapes needed to compare one double-quoted mapping key.""" + encoded_key = raw_key[1:-1] + decoded_key: list[str] = [] + index = 0 + while index < len(encoded_key): + character = encoded_key[index] + if character != "\\": + decoded_key.append(character) + index += 1 + continue + if index + 1 >= len(encoded_key): + return raw_key + escape_code = encoded_key[index + 1] + if escape_code in {"x", "u", "U"}: + width = {"x": 2, "u": 4, "U": 8}[escape_code] + digits_start = index + 2 + digits_end = digits_start + width + digits = encoded_key[digits_start:digits_end] + if len(digits) != width or re.fullmatch(r"[0-9A-Fa-f]+", digits) is None: + return raw_key + try: + decoded_key.append(chr(int(digits, 16))) + except ValueError: + return raw_key + index = digits_end + continue + replacement = _SIMPLE_YAML_ESCAPES.get(escape_code) + if replacement is None: + return raw_key + decoded_key.append(replacement) + index += 2 + return "".join(decoded_key) + + +def _decode_yaml_mapping_key(raw_key: str) -> str: + """Return the semantic key represented by one YAML mapping-key token.""" + if raw_key.startswith('"'): + return _decode_double_quoted_yaml_key(raw_key) + if raw_key.startswith("'"): + return raw_key[1:-1].replace("''", "'") + return raw_key + + +class _PathFilterDetector: + """Find semantic paths/paths-ignore YAML keys without a YAML dependency.""" + + @staticmethod + def search(trigger_block: str) -> re.Match[str] | None: + """Return the first mapping key that semantically names a path filter.""" + for match in _MAPPING_KEY_PATTERN.finditer(trigger_block): + if _decode_yaml_mapping_key(match.group("key")) in { + "paths", + "paths-ignore", + }: + return match + return None + + +PATH_FILTER = _PathFilterDetector() class AccountingDocumentationCiAcceptanceTests(unittest.TestCase): From a75512e846ca9a1c75c401c45ba2e8cc8eb615d8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 15:02:53 +0900 Subject: [PATCH 12/18] test(ci): reject explicit YAML path filter keys --- tests/test_ci_documentation_acceptance.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index e21ce7f6..c094ab2c 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -163,6 +163,20 @@ def test_path_filter_detection_rejects_escaped_quoted_yaml_keys(self) -> None: "Accounting Foundation CI acceptance", ) + def test_path_filter_detection_rejects_explicit_mapping_keys(self) -> None: + """Explicit YAML mapping-key syntax cannot hide path-filter keys.""" + for trigger_block in ( + " ? paths\n : ['src/**']\n", + " ? 'paths-ignore'\n : ['docs/**', '*.md']\n", + ' ? "pa\\u0074hs"\n : ["src/**"]\n', + ): + with self.subTest(trigger_block=trigger_block): + self.assertIsNotNone( + PATH_FILTER.search(trigger_block), + "explicit YAML mapping keys would let documentation bypass Accounting " + "Foundation CI acceptance", + ) + def test_accounting_ci_does_not_ignore_documentation_changes(self) -> None: """Docs and Markdown changes must not bypass repository accounting validation.""" workflow = (ROOT / ".github" / "workflows" / "ci.yml").read_text( From a5b895f84141710f02d979804d5ca797cb81a38b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 15:03:39 +0900 Subject: [PATCH 13/18] fix(ci): detect explicit YAML path filter keys --- tests/test_ci_documentation_acceptance.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index c094ab2c..7607ad31 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -10,7 +10,7 @@ ROOT = Path(__file__).resolve().parents[1] _MAPPING_KEY_PATTERN = re.compile( r"""(?mx) - (?:^[ \t]+|[{,][ \t]*) + (?:^[ \t]+(?:\?[ \t]+)?|[{,][ \t]*(?:\?[ \t]+)?) (?P "(?:\\.|[^"\\])*" | @@ -18,7 +18,11 @@ | [A-Za-z_][A-Za-z0-9_-]* ) - [ \t]*: + (?: + [ \t]*: + | + [ \t]*\n[ \t]*: + ) """ ) _SIMPLE_YAML_ESCAPES = { @@ -105,7 +109,7 @@ def search(trigger_block: str) -> re.Match[str] | None: class AccountingDocumentationCiAcceptanceTests(unittest.TestCase): - """Keep documentation changes inside exact-head and integrated-head acceptance.""" + """Keep documentation changes inside exact-head and integrated-head acceptance."" def test_path_filter_detection_rejects_inline_yaml_values(self) -> None: """Inline path filters must be detected as strongly as block-style filters.""" From 66106fd10cf2138c6de7434e3e3dadb8e5db8b19 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 18:03:00 +0900 Subject: [PATCH 14/18] test(ci): cover anchored path-filter keys --- tests/test_ci_documentation_acceptance.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index 7607ad31..5f071cf8 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -109,7 +109,7 @@ def search(trigger_block: str) -> re.Match[str] | None: class AccountingDocumentationCiAcceptanceTests(unittest.TestCase): - """Keep documentation changes inside exact-head and integrated-head acceptance."" + """Keep documentation changes inside exact-head and integrated-head acceptance.""" def test_path_filter_detection_rejects_inline_yaml_values(self) -> None: """Inline path filters must be detected as strongly as block-style filters.""" @@ -181,6 +181,20 @@ def test_path_filter_detection_rejects_explicit_mapping_keys(self) -> None: "Foundation CI acceptance", ) + def test_path_filter_detection_rejects_anchored_mapping_keys(self) -> None: + """YAML node anchors cannot hide a semantic paths or paths-ignore key.""" + for trigger_block in ( + " &path_filter paths: ['src/**']\n", + " &path_filter 'paths-ignore': ['docs/**', '*.md']\n", + ' &path_filter "pa\\u0074hs": ["src/**"]\n', + ): + with self.subTest(trigger_block=trigger_block): + self.assertIsNotNone( + PATH_FILTER.search(trigger_block), + "anchored YAML path-filter keys would let documentation bypass Accounting " + "Foundation CI acceptance", + ) + def test_accounting_ci_does_not_ignore_documentation_changes(self) -> None: """Docs and Markdown changes must not bypass repository accounting validation.""" workflow = (ROOT / ".github" / "workflows" / "ci.yml").read_text( From 3c388f0a7b637b41cc5ff93678f8f6a2880ce8f1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 18:03:41 +0900 Subject: [PATCH 15/18] fix(ci): detect anchored path-filter keys --- tests/test_ci_documentation_acceptance.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index 5f071cf8..148973c1 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -11,6 +11,7 @@ _MAPPING_KEY_PATTERN = re.compile( r"""(?mx) (?:^[ \t]+(?:\?[ \t]+)?|[{,][ \t]*(?:\?[ \t]+)?) + (?:&[^ \t\r\n]+[ \t]+)? (?P "(?:\\.|[^"\\])*" | From 65b7976d798fc786b8d036d00efeb5795b9dc92c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 23:07:36 +0900 Subject: [PATCH 16/18] test(ci): reject aliased event path-filter indirection --- tests/test_ci_documentation_acceptance.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index 148973c1..858b663a 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -196,6 +196,19 @@ def test_path_filter_detection_rejects_anchored_mapping_keys(self) -> None: "Foundation CI acceptance", ) + def test_path_filter_detection_rejects_event_aliases(self) -> None: + """An event alias cannot hide an anchored mapping that carries path filters.""" + for trigger_block in ( + " *path_filter\n", + " *docs_filter # anchor may be defined outside the event block\n", + ): + with self.subTest(trigger_block=trigger_block): + self.assertIsNotNone( + PATH_FILTER.search(trigger_block), + "an aliased event mapping could hide paths or paths-ignore outside the " + "trigger block and bypass Accounting Foundation CI acceptance", + ) + def test_accounting_ci_does_not_ignore_documentation_changes(self) -> None: """Docs and Markdown changes must not bypass repository accounting validation.""" workflow = (ROOT / ".github" / "workflows" / "ci.yml").read_text( From 69b0bb1a43e05ea13ab62341ae4a27aabb085421 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 23:09:36 +0900 Subject: [PATCH 17/18] fix(ci): fail closed on aliased event trigger mappings --- tests/test_ci_documentation_acceptance.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index 858b663a..2a0e0ec1 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -26,6 +26,9 @@ ) """ ) +_EVENT_ALIAS_PATTERN = re.compile( + r"(?m)^[ \t]*\*(?P[A-Za-z0-9_-]+)(?=[ \t]*(?:#.*)?$)" +) _SIMPLE_YAML_ESCAPES = { "0": "\0", "a": "\a", @@ -92,11 +95,14 @@ def _decode_yaml_mapping_key(raw_key: str) -> str: class _PathFilterDetector: - """Find semantic paths/paths-ignore YAML keys without a YAML dependency.""" + """Find path filters or event aliases that can hide them without a YAML dependency.""" @staticmethod def search(trigger_block: str) -> re.Match[str] | None: - """Return the first mapping key that semantically names a path filter.""" + """Return the first path-filter key or fail-closed event alias.""" + alias_match = _EVENT_ALIAS_PATTERN.search(trigger_block) + if alias_match is not None: + return alias_match for match in _MAPPING_KEY_PATTERN.finditer(trigger_block): if _decode_yaml_mapping_key(match.group("key")) in { "paths", @@ -223,8 +229,8 @@ def test_accounting_ci_does_not_ignore_documentation_changes(self) -> None: self.assertIsNone( PATH_FILTER.search(trigger_block), "Accounting Foundation CI pull_request/push triggers must not define " - "paths or paths-ignore filters; authority-bearing documentation must " - "receive the same exact-head acceptance as source changes.", + "paths or paths-ignore filters or opaque event aliases; authority-bearing " + "documentation must receive the same exact-head acceptance as source changes.", ) From 065f9ab7038bf35db4ef129827de6ab8ee6a1038 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 00:41:45 +0900 Subject: [PATCH 18/18] ci(actions): scope superseded PR cancellation Signed-off-by: Seongho Bae --- .github/workflows/ci.yml | 4 ++-- tests/test_ci_documentation_acceptance.py | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 559934e8..157eca84 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,8 @@ permissions: contents: read concurrency: - group: accounting-foundation-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.repository }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: exact-head-sast: diff --git a/tests/test_ci_documentation_acceptance.py b/tests/test_ci_documentation_acceptance.py index 2a0e0ec1..e174ed21 100644 --- a/tests/test_ci_documentation_acceptance.py +++ b/tests/test_ci_documentation_acceptance.py @@ -233,6 +233,22 @@ def test_accounting_ci_does_not_ignore_documentation_changes(self) -> None: "documentation must receive the same exact-head acceptance as source changes.", ) + def test_accounting_ci_only_cancels_superseded_pr_heads(self) -> None: + """PR runs share one scoped group while non-PR runs remain isolated.""" + workflow = (ROOT / ".github" / "workflows" / "ci.yml").read_text( + encoding="utf-8" + ) + + self.assertIn( + "group: ${{ github.workflow }}-${{ github.repository }}-" + "${{ github.event.pull_request.number || github.run_id }}", + workflow, + ) + self.assertIn( + "cancel-in-progress: ${{ github.event_name == 'pull_request' }}", + workflow, + ) + if __name__ == "__main__": unittest.main()