import pytest from ops_mason.plan import ConstructionPlan, PlanError def _write(tmp_path, frontmatter: str, body: str = "\n# Plan\n") -> str: p = tmp_path / "plan.md" p.write_text(f"---\n{frontmatter}\n---\n{body}") return str(p) def test_load_parses_frontmatter(tmp_path) -> None: path = _write( tmp_path, "id: test-plan\nstatus: draft\ndemand_source: x\nconsumer_repo: y\ncredential_type: openbao-approle-kv", ) plan = ConstructionPlan.load(path) assert plan.id == "test-plan" assert plan.status == "draft" assert plan.consumer_repo == "y" def test_is_approved_false_when_draft(tmp_path) -> None: path = _write(tmp_path, "id: p\nstatus: draft") assert ConstructionPlan.load(path).is_approved() is False def test_is_approved_false_when_approved_but_missing_approver(tmp_path) -> None: path = _write(tmp_path, "id: p\nstatus: approved") assert ConstructionPlan.load(path).is_approved() is False def test_is_approved_true_when_fully_approved(tmp_path) -> None: path = _write( tmp_path, 'id: p\nstatus: approved\napproved_by: "bernd"\napproved_at: "2026-07-27"', ) assert ConstructionPlan.load(path).is_approved() is True def test_missing_frontmatter_raises(tmp_path) -> None: p = tmp_path / "plan.md" p.write_text("# no frontmatter here\n") with pytest.raises(PlanError, match="missing YAML frontmatter"): ConstructionPlan.load(str(p)) def test_missing_required_field_raises(tmp_path) -> None: path = _write(tmp_path, "id: p\n# status omitted") with pytest.raises(PlanError, match="missing field"): ConstructionPlan.load(path) @pytest.mark.parametrize("frontmatter", [ "id: p\nstatus: reviewed\nstatus: approved", "id: p\nstatus: approved\nbuild_spec:\n token_num_uses: 8\n token_num_uses: 0", "- not-a-mapping", ]) def test_ambiguous_or_malformed_approval_document_refused(tmp_path, frontmatter): with pytest.raises(PlanError): ConstructionPlan.load(_write(tmp_path, frontmatter)) @pytest.mark.parametrize("approver", ['" "', "true", "[bernd]"]) def test_non_string_or_blank_approval_marker_is_not_approval(tmp_path, approver): path = _write(tmp_path, f'id: p\nstatus: approved\napproved_by: {approver}\napproved_at: "2026-09-28"') assert not ConstructionPlan.load(path).is_approved() def test_triple_dash_inside_specification_is_not_frontmatter_delimiter(tmp_path): path = _write(tmp_path, 'id: p\nstatus: draft\nbuild_spec:\n policy_name: "lane---example"') assert ConstructionPlan.load(path).build_spec["policy_name"] == "lane---example"