github-advanced-security[bot] commented on code in PR #336: URL: https://github.com/apache/airflow-steward/pull/336#discussion_r3308685672
########## tools/spec-validator/tests/test_spec_validator.py: ########## @@ -0,0 +1,417 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Tests for the spec validator.""" + +from __future__ import annotations + +import textwrap +from pathlib import Path + +import pytest + +from spec_validator import ( + ALLOWED_KIND, + ALLOWED_MODE, + ALLOWED_STATUS, + REQUIRED_FRONTMATTER_KEYS, + REQUIRED_SECTIONS, + extract_section_headings, + get_section_body, + has_acceptance_items, + main, + parse_frontmatter, + run_validation, + validate_body, + validate_file, + validate_frontmatter, + validation_has_code_block, +) Review Comment: ## CodeQL / Unused import Import of 'REQUIRED_FRONTMATTER_KEYS' is not used. Import of 'validate_file' is not used. [Show more details](https://github.com/apache/airflow-steward/security/code-scanning/13) ########## tools/spec-validator/tests/test_spec_validator.py: ########## @@ -0,0 +1,417 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Tests for the spec validator.""" + +from __future__ import annotations + +import textwrap +from pathlib import Path + +import pytest + +from spec_validator import ( + ALLOWED_KIND, + ALLOWED_MODE, + ALLOWED_STATUS, + REQUIRED_FRONTMATTER_KEYS, + REQUIRED_SECTIONS, + extract_section_headings, + get_section_body, + has_acceptance_items, + main, + parse_frontmatter, + run_validation, + validate_body, + validate_file, + validate_frontmatter, + validation_has_code_block, +) + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +_VALID_SPEC = textwrap.dedent("""\ + <!-- SPDX-License-Identifier: Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0 --> + + --- + title: Example spec + status: stable + kind: feature + mode: Triage + source: MISSION.md ยง some section + acceptance: + - At least one criterion is met. + --- + + # Example spec + + ## What it does + + A brief description. + + ## Where it lives + + - `tools/example/` + + ## Behaviour & contract + + The contract. + + ## Out of scope + + Nothing. + + ## Acceptance criteria + + 1. Criterion one. + + ## Validation + + ```bash + uv run --project tools/example --group dev pytest + ``` + """) + + +def _make_spec(*, status: str = "stable", **overrides: str) -> str: + """Build a minimal valid spec, replacing frontmatter values as needed.""" + defaults = { + "title": "Test spec", + "kind": "feature", + "mode": "Triage", + "source": "MISSION.md", + "acceptance_items": " - One criterion.", + } + defaults.update(overrides) + acceptance_items = defaults.pop("acceptance_items") + fm_lines = [ + f"title: {defaults['title']}", + f"status: {status}", + f"kind: {defaults['kind']}", + f"mode: {defaults['mode']}", + f"source: {defaults['source']}", + "acceptance:", + acceptance_items, + ] + body_sections = "\n\n".join( + f"## {s}\n\nContent." for s in REQUIRED_SECTIONS + ) + # Replace Validation section with one that has a code block + body_sections = body_sections.replace( + "## Validation\n\nContent.", + "## Validation\n\n```bash\npytest\n```", + ) + fm = "\n".join(fm_lines) + return f"---\n{fm}\n---\n\n# Test spec\n\n{body_sections}\n" + + +# --------------------------------------------------------------------------- +# Frontmatter parsing +# --------------------------------------------------------------------------- + + +class TestParseFrontmatter: + def test_valid_frontmatter(self) -> None: + fm = parse_frontmatter(_VALID_SPEC) + assert fm is not None + assert fm["title"] == "Example spec" + assert fm["status"] == "stable" + + def test_no_frontmatter_returns_none(self) -> None: + assert parse_frontmatter("# Just a heading\n\nNo frontmatter.") is None + + def test_html_comment_prefix_allowed(self) -> None: + text = "<!-- SPDX-License-Identifier: Apache-2.0 -->\n---\ntitle: foo\n---\n" + fm = parse_frontmatter(text) + assert fm is not None + assert fm["title"] == "foo" + + def test_non_comment_prefix_returns_none(self) -> None: + text = "Some prose\n---\ntitle: foo\n---\n" + assert parse_frontmatter(text) is None + + def test_folded_block_scalar(self) -> None: + text = "---\nsource: >\n line one\n line two\n---\n" + fm = parse_frontmatter(text) + assert fm is not None + assert "line one" in fm["source"] + + def test_multiline_value(self) -> None: + text = "---\ntitle: My\n continuation\n---\n" + fm = parse_frontmatter(text) + assert fm is not None + assert "My" in fm["title"] + + +class TestHasAcceptanceItems: + def test_has_items(self) -> None: + text = "---\nacceptance:\n - item one\n - item two\n---\n" + assert has_acceptance_items(text) is True + + def test_no_items(self) -> None: + text = "---\nacceptance:\n---\n" + assert has_acceptance_items(text) is False + + def test_no_frontmatter(self) -> None: + assert has_acceptance_items("# no frontmatter") is False + + +# --------------------------------------------------------------------------- +# Body section extraction +# --------------------------------------------------------------------------- + + +class TestExtractSectionHeadings: + def test_extracts_h2_headings(self) -> None: + headings = extract_section_headings(_VALID_SPEC) + assert "What it does" in headings + assert "Validation" in headings + + def test_ignores_h1(self) -> None: + headings = extract_section_headings(_VALID_SPEC) + assert "Example spec" not in headings + + def test_no_frontmatter_still_works(self) -> None: + text = "# Title\n\n## Section A\n\ncontent\n" + headings = extract_section_headings(text) + assert "Section A" in headings + + +class TestGetSectionBody: + def test_returns_section_content(self) -> None: + body = get_section_body(_VALID_SPEC, "What it does") + assert body is not None + assert "A brief description" in body + + def test_returns_none_for_missing_section(self) -> None: + assert get_section_body(_VALID_SPEC, "Nonexistent") is None + + def test_stops_at_next_section(self) -> None: + body = get_section_body(_VALID_SPEC, "What it does") + assert body is not None + assert "Where it lives" not in body + + +class TestValidationHasCodeBlock: + def test_valid_spec_has_code_block(self) -> None: + assert validation_has_code_block(_VALID_SPEC) is True + + def test_missing_code_block(self) -> None: + text = _VALID_SPEC.replace("```bash\n uv run --project tools/example --group dev pytest\n ```", "Run pytest.") Review Comment: ## CodeQL / Unused local variable Variable text is not used. [Show more details](https://github.com/apache/airflow-steward/security/code-scanning/12) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
