|
13 | 13 | load_policy, |
14 | 14 | ) |
15 | 15 | from services.evidence.store import EvidenceStore |
16 | | -from evidence.packager import _collect_files |
| 16 | +from evidence.packager import _collect_files, create_bundle |
17 | 17 |
|
18 | 18 |
|
19 | 19 | def _write_json(path: Path, payload: dict) -> Path: |
@@ -190,6 +190,63 @@ def test_evaluate_policy_warn_and_fail() -> None: |
190 | 190 | assert evaluations["checks"]["provenance_attestations"]["status"] == "fail" |
191 | 191 |
|
192 | 192 |
|
| 193 | +def test_create_bundle_with_namespaced_tag(tmp_path: Path) -> None: |
| 194 | + tag = "namespace/repo:v1.0.0" |
| 195 | + normalized = _write_json( |
| 196 | + tmp_path / "artifacts/sbom/normalized.json", {"components": []} |
| 197 | + ) |
| 198 | + quality_json = _write_json( |
| 199 | + tmp_path / "analysis/sbom_quality_report.json", |
| 200 | + {"metrics": {"coverage_percent": 95.0, "license_coverage_percent": 90.0}}, |
| 201 | + ) |
| 202 | + quality_html = tmp_path / "reports/sbom_quality_report.html" |
| 203 | + quality_html.parent.mkdir(parents=True, exist_ok=True) |
| 204 | + quality_html.write_text("<html>quality</html>", encoding="utf-8") |
| 205 | + risk_report = _write_json( |
| 206 | + tmp_path / "artifacts/risk.json", |
| 207 | + {"summary": {"component_count": 2, "cve_count": 1, "max_risk_score": 60.0}}, |
| 208 | + ) |
| 209 | + provenance_dir = tmp_path / "artifacts/attestations" |
| 210 | + provenance_dir.mkdir(parents=True, exist_ok=True) |
| 211 | + (provenance_dir / "build.json").write_text("{}", encoding="utf-8") |
| 212 | + repro_attestation = _write_json( |
| 213 | + tmp_path / "artifacts/repro/attestations" / f"{tag.replace('/', '_').replace(':', '_')}.json", |
| 214 | + {"match": True}, |
| 215 | + ) |
| 216 | + |
| 217 | + inputs = BundleInputs( |
| 218 | + tag=tag, |
| 219 | + normalized_sbom=normalized, |
| 220 | + sbom_quality_json=quality_json, |
| 221 | + sbom_quality_html=quality_html, |
| 222 | + risk_report=risk_report, |
| 223 | + provenance_dir=provenance_dir, |
| 224 | + repro_attestation=repro_attestation, |
| 225 | + output_dir=tmp_path / "evidence", |
| 226 | + ) |
| 227 | + manifest = create_bundle(inputs) |
| 228 | + |
| 229 | + # Verify the bundle and manifest are created in the namespace directories |
| 230 | + bundle_path = Path(manifest["bundle_path"]) |
| 231 | + manifest_path = Path(manifest["manifest_path"]) |
| 232 | + |
| 233 | + # Check that the paths preserve the namespace structure |
| 234 | + assert bundle_path.parent.name == "repo" |
| 235 | + assert bundle_path.parent.parent.name == "namespace" |
| 236 | + assert manifest_path.parent.name == "repo" |
| 237 | + assert manifest_path.parent.parent.name == "namespace" |
| 238 | + |
| 239 | + # Check that the files exist |
| 240 | + assert bundle_path.is_file() |
| 241 | + assert manifest_path.is_file() |
| 242 | + |
| 243 | + # Verify manifest contains the full tag |
| 244 | + import yaml |
| 245 | + with manifest_path.open("r", encoding="utf-8") as f: |
| 246 | + manifest_data = yaml.safe_load(f) |
| 247 | + assert manifest_data["tag"] == tag |
| 248 | + |
| 249 | + |
193 | 250 | def test_collect_files_handles_nested_directories(tmp_path: Path) -> None: |
194 | 251 | extras = tmp_path / "extras" |
195 | 252 | extras.mkdir() |
|
0 commit comments