diff --git a/Makefile b/Makefile index 7811eac..7751725 100644 --- a/Makefile +++ b/Makefile @@ -28,8 +28,6 @@ fuzz: go test -fuzz=FuzzRemoveEntry -fuzztime=$(FUZZTIME) ./manifest/ go test -fuzz=FuzzRead -fuzztime=$(FUZZTIME) ./lock/ go test -fuzz=FuzzFormat -fuzztime=$(FUZZTIME) ./sniff/ - go test -fuzz=FuzzParseSRI -fuzztime=$(FUZZTIME) ./integrity/ - go test -fuzz=FuzzRoundTrip -fuzztime=$(FUZZTIME) ./integrity/ go test -fuzz=FuzzIsSticky -fuzztime=$(FUZZTIME) ./source/npm/ go test -fuzz=FuzzFindSignature -fuzztime=$(FUZZTIME) ./source/npm/ go test -fuzz=FuzzSafeOut -fuzztime=$(FUZZTIME) . diff --git a/README.md b/README.md index a408f44..d5e7282 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,7 @@ assets: ## Lockfile -`pin.lock` is a valid CycloneDX 1.6 SBOM. Each package becomes a `library` component with the registry tarball hash; each vendored file becomes a nested `file` component with its own SHA-384, the CDN URL, and pin-specific metadata under a `pin:` property namespace. Any CycloneDX consumer (Dependency-Track, GUAC, OSV-scanner, `git-pkgs sbom`) reads it directly. `serialNumber` and `metadata.timestamp` are deliberately omitted so re-runs are byte-stable and parallel branches don't conflict on the file. +`pin.lock` is a valid CycloneDX 1.6 SBOM. Each package becomes a `library` component with the registry tarball hashes; each vendored file becomes a nested `file` component with its integrity hashes, the CDN URL, and pin-specific metadata under a `pin:` property namespace. New file entries use SHA-384. Any CycloneDX consumer (Dependency-Track, GUAC, OSV-scanner, `git-pkgs sbom`) reads it directly. `serialNumber` and `metadata.timestamp` are deliberately omitted so re-runs are byte-stable and parallel branches don't conflict on the file. The schema is in [docs/SPEC.md](docs/SPEC.md), the defences in [docs/SECURITY.md](docs/SECURITY.md), and the adversary-by-asset model in [docs/THREAT_MODEL.md](docs/THREAT_MODEL.md). @@ -215,7 +215,7 @@ Source resolvers are pluggable by purl type. Register a new resolver for any pre c.RegisterResolver("ipfs", myIPFSResolver{}) ``` -The full Client surface: `Sync`, `Verify`, `Outdated`, `Add`, `Remove`, plus the package-level `List`, `Path`, `Init`, `SBOM`, `EncodeLock`. The `manifest`, `lock`, `pinfs`, `integrity`, `cdn`, `sniff`, `source` (with `source/npm`, `source/forge`, `source/rawurl`), and `assets` sub-packages are all public. +The full Client surface: `Sync`, `Verify`, `Outdated`, `Add`, `Remove`, plus the package-level `List`, `Path`, `Init`, `SBOM`, `EncodeLock`. The `manifest`, `lock`, `pinfs`, `cdn`, `sniff`, `source` (with `source/npm`, `source/forge`, `source/rawurl`), and `assets` sub-packages are all public. `SyncOptions.FS` redirects pin's outputs (vendored files + `pin.lock`) into anything that implements `pinfs.Writer`. The default writes to local paths under `SyncOptions.Dir`; `pinfs.NewMemory()` keeps everything in process, and a custom implementation can pipe writes into a tarball, an archive, or an in-memory build artefact. diff --git a/docs/SPEC.md b/docs/SPEC.md index ce4221e..f68066f 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -96,12 +96,14 @@ order is stable and a writer MUST produce it; a reader MAY rely on it. - `bom-ref` equals `purl`. Both fields exist for CycloneDX consumers that key by either. -- `hashes[0]` is the package-level integrity anchor. Encoding depends - on the source kind, summarised below: +- `hashes[]` contains the package-level integrity anchors. npm metadata may + contain several supported SRI digests; pin preserves each SHA-256, SHA-384, + and SHA-512 entry in source order. Other source kinds use one entry. Encoding + depends on the source kind, summarised below: - | Source | purl prefix | `hashes[0].alg` | `hashes[0].content` | + | Source | purl prefix | `hashes[].alg` | `hashes[].content` | |-------------------|-----------------|--------------------------|------------------------------------------------| - | npm | `pkg:npm/` | `SHA-512` (or the algorithm in `dist.integrity`) | hex of the registry tarball | + | npm | `pkg:npm/` | each supported algorithm in `dist.integrity` | hex of the registry tarball | | github | `pkg:github/` | `SHA-1` | hex of the resolved commit SHA | | url (TOFU) | `pkg:generic/` | `SHA-384` | hex of the single fetched file | @@ -145,11 +147,11 @@ commit SHA; writers MUST write both. identifying the file inside the package. - `name` is the file's path inside the package (the source-of-record path, not the on-disk output path). -- `hashes[0]` is the Subresource Integrity hash of the file's bytes, - encoded as hex per CycloneDX convention. SHA-384 is the default - algorithm chosen because it's what browsers accept in - `