66 lines
2.1 KiB
Python
66 lines
2.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Complete duplicate npm lock entries from an identical verified artifact."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
|
|
|
|
def complete_lock(path: Path) -> int:
|
|
"""Fill missing SRI only from the same resolved URL; return change count."""
|
|
data = json.loads(path.read_text(encoding="utf-8"))
|
|
packages = data.get("packages", {})
|
|
integrity_by_url: dict[str, str] = {}
|
|
for package in packages.values():
|
|
resolved = package.get("resolved")
|
|
integrity = package.get("integrity")
|
|
if not isinstance(resolved, str) or not resolved.startswith(
|
|
("http://", "https://"),
|
|
):
|
|
continue
|
|
if not isinstance(integrity, str) or not integrity.startswith("sha512-"):
|
|
continue
|
|
prior = integrity_by_url.setdefault(resolved, integrity)
|
|
if prior != integrity:
|
|
raise ValueError(f"conflicting integrity values for {resolved}")
|
|
|
|
changed = 0
|
|
missing: list[str] = []
|
|
for package_path, package in packages.items():
|
|
resolved = package.get("resolved")
|
|
if not isinstance(resolved, str) or not resolved.startswith(
|
|
("http://", "https://"),
|
|
):
|
|
continue
|
|
integrity = package.get("integrity")
|
|
if isinstance(integrity, str) and integrity.startswith("sha512-"):
|
|
continue
|
|
known = integrity_by_url.get(resolved)
|
|
if known is None:
|
|
missing.append(package_path)
|
|
continue
|
|
package["integrity"] = known
|
|
changed += 1
|
|
if missing:
|
|
joined = ", ".join(missing)
|
|
raise ValueError(f"no verified duplicate artifact for: {joined}")
|
|
if changed:
|
|
path.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
|
|
return changed
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("locks", nargs="+", type=Path)
|
|
args = parser.parse_args()
|
|
for path in args.locks:
|
|
changed = complete_lock(path)
|
|
print(f"{path}: completed {changed} duplicate integrity entries")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|