Skip to content

Commit 0fc70ab

Browse files
committed
feat: reshape fossa-sbom.json to 5-key attribution top-level
Replaces the 2-key {project, dependencies} shape with the real FOSSA attribution shape: copyrightsByLicense, deepDependencies, directDependencies, licenses, project. The SBOM project field is now the 2-key {name, revision} subset rather than the 6-key analyze project shape. _partition_dependencies is a stub returning ([], []) until Tasks 7-9 fill in per-dependency entries.
1 parent b546f07 commit 0fc70ab

2 files changed

Lines changed: 52 additions & 20 deletions

File tree

socketsecurity/fossa_compat.py

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -362,26 +362,28 @@ def build_fossa_report_payload(diff_report: Diff, config: CliConfig) -> dict[str
362362
}
363363

364364

365-
def build_fossa_attribution_payload(diff_report: Diff, config: CliConfig) -> dict[str, Any]:
366-
project = _build_project_metadata(diff_report, config)
367-
packages = getattr(diff_report, "packages", {}) or {}
368-
package_entries = []
369-
370-
for package in packages.values():
371-
package_entries.append({
372-
"id": package.id,
373-
"name": package.name,
374-
"version": package.version,
375-
"ecosystem": _ecosystem_to_package_manager(package.type),
376-
"direct": bool(getattr(package, "direct", False)),
377-
"url": package.url,
378-
"purl": package.purl,
379-
"declaredLicense": package.license,
380-
"licenseDetails": package.licenseDetails or [],
381-
"licenseAttrib": package.licenseAttrib or [],
382-
})
365+
def _build_attribution_project(diff_report: Diff, config: CliConfig) -> dict[str, Any]:
366+
repo = getattr(config, "repo", None) or "socket-default-repo"
367+
revision = (
368+
getattr(diff_report, "id", None)
369+
or getattr(diff_report, "new_scan_id", None)
370+
or "unknown-revision"
371+
)
372+
return {"name": repo, "revision": revision}
373+
383374

375+
def _partition_dependencies(packages: list[Package]) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
376+
"""Stub: filled in by Tasks 7-9. Returns (direct, deep) lists of Dependency dicts."""
377+
return ([], [])
378+
379+
380+
def build_fossa_attribution_payload(diff_report: Diff, config: CliConfig) -> dict[str, Any]:
381+
packages = list((getattr(diff_report, "packages", {}) or {}).values())
382+
direct, deep = _partition_dependencies(packages)
384383
return {
385-
"project": project,
386-
"dependencies": package_entries,
384+
"copyrightsByLicense": {},
385+
"deepDependencies": deep,
386+
"directDependencies": direct,
387+
"licenses": {},
388+
"project": _build_attribution_project(diff_report, config),
387389
}

tests/unit/test_fossa_compat.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,36 @@ def test_vulnerability_gap_fields_emit_known_defaults():
278278
assert proj_entry["firstFoundAt"] is None
279279

280280

281+
def test_attribution_payload_top_level_is_5_keys():
282+
"""fossa-sbom.json has exactly the 5 keys from `fossa report --json attribution`."""
283+
config = CliConfig.from_args(["--api-token", "test", "--legal-format", "fossa"])
284+
payload = build_fossa_attribution_payload(Diff(), config)
285+
assert set(payload.keys()) == {
286+
"copyrightsByLicense",
287+
"deepDependencies",
288+
"directDependencies",
289+
"licenses",
290+
"project",
291+
}
292+
293+
294+
def test_attribution_project_has_only_name_and_revision():
295+
"""SBOM `project` is the 2-key subset, not the 6-key analyze project."""
296+
config = CliConfig.from_args(["--api-token", "test", "--legal-format", "fossa", "--repo", "acme/widgets"])
297+
diff = Diff(id="rev-x")
298+
payload = build_fossa_attribution_payload(diff, config)
299+
assert payload["project"] == {"name": "acme/widgets", "revision": "rev-x"}
300+
301+
302+
def test_attribution_empty_diff_yields_empty_collections():
303+
config = CliConfig.from_args(["--api-token", "test", "--legal-format", "fossa"])
304+
payload = build_fossa_attribution_payload(Diff(), config)
305+
assert payload["copyrightsByLicense"] == {}
306+
assert payload["licenses"] == {}
307+
assert payload["directDependencies"] == []
308+
assert payload["deepDependencies"] == []
309+
310+
281311
def test_vulnerability_version_ranges_sourced_from_socket_fields():
282312
"""affectedVersionRanges/patchedVersionRanges come from Socket's singular fields, wrapped."""
283313
from socketsecurity.fossa_compat import _build_vulnerability_entry

0 commit comments

Comments
 (0)