generated from coulomb/repo-seed
Add extension profile schema validation
This commit is contained in:
@@ -8,6 +8,7 @@ from tempfile import TemporaryDirectory
|
||||
from pathlib import Path
|
||||
|
||||
from guide_board.discovery import discover_extensions
|
||||
from guide_board.errors import ValidationError
|
||||
from guide_board.execution import run_assessment
|
||||
from guide_board.gates import evaluate_trend_gates
|
||||
from guide_board.io import load_json
|
||||
@@ -143,6 +144,55 @@ class CoreArchitectureTests(unittest.TestCase):
|
||||
self.assertEqual(plan["extension_snapshots"][0]["path"], str(extension_dir))
|
||||
self.assertEqual([item["result"] for item in evidence], ["skipped", "manual"])
|
||||
|
||||
def test_applies_external_extension_profile_schemas(self) -> None:
|
||||
with TemporaryDirectory() as temporary_directory:
|
||||
temp_root = Path(temporary_directory)
|
||||
extension_dir = temp_root / "schema-noop"
|
||||
_write_schema_extension(extension_dir)
|
||||
extensions = discover_extensions(ROOT, [extension_dir])
|
||||
target_path = temp_root / "target.json"
|
||||
assessment_path = temp_root / "assessment.json"
|
||||
_write_schema_target(target_path, endpoints=[{
|
||||
"id": "api",
|
||||
"url": "http://127.0.0.1:8080",
|
||||
"binding": "example",
|
||||
}])
|
||||
_write_schema_assessment(assessment_path, runtime_policy={"offline": True})
|
||||
|
||||
target = validate_target_profile(target_path, extensions)
|
||||
assessment = validate_assessment_profile(assessment_path, extensions)
|
||||
plan = build_run_plan(ROOT, target_path, assessment_path, [extension_dir])
|
||||
|
||||
self.assertEqual(target["subject_type"], "schema-subject")
|
||||
self.assertEqual(assessment["runtime_policy"], {"offline": True})
|
||||
self.assertEqual(plan["extension_snapshots"][0]["id"], "schema-noop")
|
||||
|
||||
_write_schema_target(target_path, endpoints=[])
|
||||
with self.assertRaisesRegex(
|
||||
ValidationError,
|
||||
"schema-noop:schema-target profile schema validation failed",
|
||||
):
|
||||
validate_target_profile(target_path, extensions)
|
||||
|
||||
def test_rejects_extension_profile_schema_paths_outside_extension_root(self) -> None:
|
||||
with TemporaryDirectory() as temporary_directory:
|
||||
temp_root = Path(temporary_directory)
|
||||
extension_dir = temp_root / "schema-noop"
|
||||
_write_schema_extension(extension_dir, target_schema_path="../outside.schema.json")
|
||||
target_path = temp_root / "target.json"
|
||||
_write_schema_target(target_path, endpoints=[{
|
||||
"id": "api",
|
||||
"url": "http://127.0.0.1:8080",
|
||||
"binding": "example",
|
||||
}])
|
||||
|
||||
extensions = discover_extensions(ROOT, [extension_dir])
|
||||
with self.assertRaisesRegex(
|
||||
ValidationError,
|
||||
"profile schema path escapes extension root",
|
||||
):
|
||||
validate_target_profile(target_path, extensions)
|
||||
|
||||
def test_runs_sample_noop_assessment(self) -> None:
|
||||
with TemporaryDirectory() as temporary_directory:
|
||||
result = run_assessment(
|
||||
@@ -460,5 +510,135 @@ def _write_external_extension(extension_dir: Path) -> None:
|
||||
)
|
||||
|
||||
|
||||
def _write_schema_extension(
|
||||
extension_dir: Path,
|
||||
target_schema_path: str = "schemas/schema-target.schema.json",
|
||||
) -> None:
|
||||
extension_dir.mkdir(parents=True, exist_ok=True)
|
||||
schema_dir = extension_dir / "schemas"
|
||||
schema_dir.mkdir()
|
||||
(schema_dir / "schema-target.schema.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["subject_type", "endpoints"],
|
||||
"properties": {
|
||||
"subject_type": {"enum": ["schema-subject"]},
|
||||
"endpoints": {"type": "array", "minItems": 1},
|
||||
},
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
(schema_dir / "schema-assessment.schema.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["runtime_policy"],
|
||||
"properties": {
|
||||
"runtime_policy": {
|
||||
"type": "object",
|
||||
"required": ["offline"],
|
||||
"properties": {"offline": {"type": "boolean"}},
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
(extension_dir / "extension.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"id": "schema-noop",
|
||||
"name": "Schema No-op",
|
||||
"version": "0.1.0",
|
||||
"extension_type": "repository_quality",
|
||||
"lifecycle_status": "incubating",
|
||||
"supported_frameworks": ["schema.readiness.v1"],
|
||||
"authorities": [],
|
||||
"profile_schemas": [
|
||||
"target-profile",
|
||||
"assessment-profile",
|
||||
{
|
||||
"id": "schema-target",
|
||||
"profile_kind": "target",
|
||||
"path": target_schema_path,
|
||||
"subject_type": "schema-subject",
|
||||
},
|
||||
{
|
||||
"id": "schema-assessment",
|
||||
"profile_kind": "assessment",
|
||||
"path": "schemas/schema-assessment.schema.json",
|
||||
},
|
||||
],
|
||||
"check_groups": [
|
||||
{
|
||||
"id": "shape",
|
||||
"name": "Shape",
|
||||
"check_type": "repository_quality",
|
||||
"requirement_refs": ["schema.shape"],
|
||||
"runner_ref": None,
|
||||
}
|
||||
],
|
||||
"preflight_runner": None,
|
||||
"runner_entrypoints": [],
|
||||
"normalizers": [],
|
||||
"mappings": [],
|
||||
"report_fragments": [],
|
||||
"dependencies": [],
|
||||
"restricted_assets": [],
|
||||
"certification_boundary": "Test fixture only.",
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
|
||||
def _write_schema_target(path: Path, endpoints: list[dict[str, str]]) -> None:
|
||||
path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"id": "schema-target",
|
||||
"subject_type": "schema-subject",
|
||||
"subject_name": "Schema Target",
|
||||
"environment": "test",
|
||||
"scope": ["schema"],
|
||||
"endpoints": endpoints,
|
||||
"artifacts": [],
|
||||
"credentials_ref": None,
|
||||
"declared_capabilities": [],
|
||||
"known_gaps": [],
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
|
||||
def _write_schema_assessment(path: Path, runtime_policy: dict[str, object]) -> None:
|
||||
path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"id": "schema-assessment",
|
||||
"framework_refs": ["schema.readiness.v1"],
|
||||
"extension_refs": ["schema-noop"],
|
||||
"target_profile_ref": "schema-target",
|
||||
"selected_check_groups": {"schema-noop": ["shape"]},
|
||||
"expectations_ref": None,
|
||||
"waivers_ref": None,
|
||||
"output_policy": {
|
||||
"report_formats": ["json", "markdown"],
|
||||
"artifact_retention": "summary-only",
|
||||
},
|
||||
"retention_policy": {
|
||||
"summary_days": 365,
|
||||
"raw_artifact_days": 0,
|
||||
},
|
||||
"runtime_policy": runtime_policy,
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user