From 9a9e17aa2bdf3b035f2e00481ec859b13cc83714 Mon Sep 17 00:00:00 2001 From: Nishieee Date: Sat, 30 May 2026 20:11:27 -0400 Subject: [PATCH 1/2] Add --list-categories flag to validator --- .../src/skill_and_tool_validator/__init__.py | 26 +++++++++++++++++++ .../tests/test_validator.py | 11 ++++++++ 2 files changed, 37 insertions(+) diff --git a/tools/skill-and-tool-validator/src/skill_and_tool_validator/__init__.py b/tools/skill-and-tool-validator/src/skill_and_tool_validator/__init__.py index 802a63ff..f992504f 100644 --- a/tools/skill-and-tool-validator/src/skill_and_tool_validator/__init__.py +++ b/tools/skill-and-tool-validator/src/skill_and_tool_validator/__init__.py @@ -245,6 +245,21 @@ def _read_mode_table() -> dict[str, str]: LOWERCASE_F_FIELD_CATEGORY, } ) +ALL_CATEGORIES: frozenset[str] = frozenset( + { + TOOL_README_CATEGORY, + TOOL_CAPABILITY_CATEGORY, + CAPABILITY_SYNC_CATEGORY, + PRINCIPLE_CATEGORY, + TRIGGER_PRESERVATION_CATEGORY, + INJECTION_GUARD_CATEGORY, + INJECTION_GUARD_TODO_CATEGORY, + GH_LIST_CATEGORY, + SECURITY_PATTERN_CATEGORY, + PRIVACY_CATEGORY, + LOWERCASE_F_FIELD_CATEGORY, + } +) # --------------------------------------------------------------------------- # Injection-guard constants (Pattern 4) @@ -1648,8 +1663,19 @@ def main(argv: list[str] | None = None) -> int: action="store_true", help="Promote SOFT categories (advisory) to hard failures.", ) + parser.add_argument( + "--list-categories", + action="store_true", + help="Print every violation category name (SOFT ones marked) and exit.", + ) args = parser.parse_args(argv) + if args.list_categories: + for category in sorted(ALL_CATEGORIES): + suffix = " (advisory)" if category in SOFT_CATEGORIES else "" + print(f"{category}{suffix}") + return 0 + skip = {c.strip() for c in args.skip_categories.split(",") if c.strip()} violations = run_validation() filtered = [v for v in violations if v.category not in skip] diff --git a/tools/skill-and-tool-validator/tests/test_validator.py b/tools/skill-and-tool-validator/tests/test_validator.py index 4998f415..640972f2 100644 --- a/tools/skill-and-tool-validator/tests/test_validator.py +++ b/tools/skill-and-tool-validator/tests/test_validator.py @@ -28,6 +28,7 @@ _MODE_TAXONOMY, _OFF_MODES, _PRIVACY_EXTERNAL_CONTENT_MODES, + ALL_CATEGORIES, ALLOWED_MODES, FORBIDDEN_PATTERNS, GH_LIST_CATEGORY, @@ -1879,6 +1880,16 @@ def _make_valid_skill(root: Path, name: str) -> Path: class TestMain: + def test_list_categories(self, capsys: pytest.CaptureFixture[str]) -> None: + rc = main(["--list-categories"]) + assert rc == 0 + out = capsys.readouterr().out + expected = [ + f"{c} (advisory)" if c in SOFT_CATEGORIES else c + for c in sorted(ALL_CATEGORIES) + ] + assert out.strip().splitlines() == expected + def test_returns_0_when_no_violations(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: root = _skill_root(tmp_path) _make_valid_skill(root, "my-skill") From 3a8fce777777b5d463131e75d0109032ddbb476c Mon Sep 17 00:00:00 2001 From: Nishieee Date: Sun, 31 May 2026 11:12:58 -0400 Subject: [PATCH 2/2] Derive ALL_CATEGORIES from HARD | SOFT union (#377) --- .../src/skill_and_tool_validator/__init__.py | 10 ++-------- tools/skill-and-tool-validator/tests/test_validator.py | 10 ++++++---- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/tools/skill-and-tool-validator/src/skill_and_tool_validator/__init__.py b/tools/skill-and-tool-validator/src/skill_and_tool_validator/__init__.py index f992504f..2c8d7c52 100644 --- a/tools/skill-and-tool-validator/src/skill_and_tool_validator/__init__.py +++ b/tools/skill-and-tool-validator/src/skill_and_tool_validator/__init__.py @@ -245,21 +245,15 @@ def _read_mode_table() -> dict[str, str]: LOWERCASE_F_FIELD_CATEGORY, } ) -ALL_CATEGORIES: frozenset[str] = frozenset( +HARD_CATEGORIES: frozenset[str] = frozenset( { TOOL_README_CATEGORY, TOOL_CAPABILITY_CATEGORY, CAPABILITY_SYNC_CATEGORY, - PRINCIPLE_CATEGORY, - TRIGGER_PRESERVATION_CATEGORY, INJECTION_GUARD_CATEGORY, - INJECTION_GUARD_TODO_CATEGORY, - GH_LIST_CATEGORY, - SECURITY_PATTERN_CATEGORY, - PRIVACY_CATEGORY, - LOWERCASE_F_FIELD_CATEGORY, } ) +ALL_CATEGORIES = HARD_CATEGORIES | SOFT_CATEGORIES # --------------------------------------------------------------------------- # Injection-guard constants (Pattern 4) diff --git a/tools/skill-and-tool-validator/tests/test_validator.py b/tools/skill-and-tool-validator/tests/test_validator.py index 640972f2..62325119 100644 --- a/tools/skill-and-tool-validator/tests/test_validator.py +++ b/tools/skill-and-tool-validator/tests/test_validator.py @@ -32,6 +32,7 @@ ALLOWED_MODES, FORBIDDEN_PATTERNS, GH_LIST_CATEGORY, + HARD_CATEGORIES, INJECTION_GUARD_CALLOUT_SENTINEL, INJECTION_GUARD_CATEGORY, INJECTION_GUARD_TODO_CATEGORY, @@ -1392,6 +1393,10 @@ def test_lowercase_f_field_in_soft_categories(self) -> None: class TestSoftCategories: + def test_all_categories_is_union_of_hard_and_soft(self) -> None: + assert ALL_CATEGORIES == HARD_CATEGORIES | SOFT_CATEGORIES + assert HARD_CATEGORIES.isdisjoint(SOFT_CATEGORIES) + def test_soft_categories_set(self) -> None: assert PRINCIPLE_CATEGORY in SOFT_CATEGORIES assert TRIGGER_PRESERVATION_CATEGORY in SOFT_CATEGORIES @@ -1884,10 +1889,7 @@ def test_list_categories(self, capsys: pytest.CaptureFixture[str]) -> None: rc = main(["--list-categories"]) assert rc == 0 out = capsys.readouterr().out - expected = [ - f"{c} (advisory)" if c in SOFT_CATEGORIES else c - for c in sorted(ALL_CATEGORIES) - ] + expected = [f"{c} (advisory)" if c in SOFT_CATEGORIES else c for c in sorted(ALL_CATEGORIES)] assert out.strip().splitlines() == expected def test_returns_0_when_no_violations(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: