@pnpm/lockfile.utils 1100.0.8 → 1100.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,33 @@
1
1
  import url from 'node:url';
2
2
  import * as dp from '@pnpm/deps.path';
3
+ import { PnpmError } from '@pnpm/error';
3
4
  import getNpmTarballUrl from 'get-npm-tarball-url';
4
5
  import { nameVerFromPkgSnapshot } from './nameVerFromPkgSnapshot.js';
6
+ import { isGitHostedTarballUrl } from './toLockfileResolution.js';
5
7
  export function pkgSnapshotToResolution(depPath, pkgSnapshot, registries) {
6
- if (Boolean(pkgSnapshot.resolution.type) ||
7
- pkgSnapshot.resolution.tarball?.startsWith('file:') ||
8
- pkgSnapshot.resolution.gitHosted === true) {
8
+ const resolution = pkgSnapshot.resolution;
9
+ // Tarball-shaped resolutions (no `type` field) must carry `integrity`,
10
+ // except where the URL itself anchors the bytes:
11
+ // - `file:` tarballs (local file on the user's machine; integrity
12
+ // adds nothing the user doesn't already control).
13
+ // - Git-hosted tarballs (URL contains the commit SHA; git's content-
14
+ // addressed model binds the bytes to the commit). The `gitHosted`
15
+ // flag may be absent on legacy lockfiles, so fall back to a URL
16
+ // match — same logic as `toLockfileResolution`.
17
+ // For any other tarball entry a missing integrity is what a tampered
18
+ // lockfile looks like: the worker would mint a fresh integrity from
19
+ // whatever bytes the URL returned, so we fail closed here. Pacquet
20
+ // enforces the same invariant via
21
+ // `pacquet_package_manager::missing_tarball_integrity`.
22
+ if (resolution.type == null &&
23
+ resolution.integrity == null &&
24
+ !resolution.tarball?.startsWith('file:') &&
25
+ !(resolution.gitHosted === true || (resolution.tarball != null && isGitHostedTarballUrl(resolution.tarball)))) {
26
+ throw new PnpmError('MISSING_TARBALL_INTEGRITY', `Cannot install package "${depPath}": its lockfile entry has no "integrity" field, so pnpm cannot verify the downloaded tarball.`, { hint: 'The lockfile may be corrupted or have been tampered with. Restore it from a trusted source, or delete it and re-run installation without --frozen-lockfile to regenerate.' });
27
+ }
28
+ if (Boolean(resolution.type) ||
29
+ resolution.tarball?.startsWith('file:') ||
30
+ resolution.gitHosted === true) {
9
31
  return pkgSnapshot.resolution;
10
32
  }
11
33
  // Recover the tarball field for `file:` snapshots whose resolution lost
@@ -4,3 +4,4 @@ export declare function toLockfileResolution(pkg: {
4
4
  name: string;
5
5
  version: string;
6
6
  }, resolution: Resolution, registry: string, lockfileIncludeTarballUrl?: boolean): LockfileResolution;
7
+ export declare function isGitHostedTarballUrl(url: string): boolean;
@@ -58,7 +58,7 @@ function preservingGitHosted(resolution, gitHosted) {
58
58
  // Inlined to avoid pulling @pnpm/fetching.pick-fetcher into the lockfile-utils
59
59
  // dep graph. Used as a fallback when callers haven't pre-set the
60
60
  // `gitHosted` field on TarballResolution.
61
- function isGitHostedTarballUrl(url) {
61
+ export function isGitHostedTarballUrl(url) {
62
62
  return (url.startsWith('https://codeload.github.com/') ||
63
63
  url.startsWith('https://bitbucket.org/') ||
64
64
  url.startsWith('https://gitlab.com/')) && url.includes('tar.gz');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/lockfile.utils",
3
- "version": "1100.0.8",
3
+ "version": "1100.0.10",
4
4
  "description": "Utils for dealing with pnpm-lock.yaml",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -28,12 +28,12 @@
28
28
  "dependencies": {
29
29
  "get-npm-tarball-url": "^2.1.0",
30
30
  "ramda": "npm:@pnpm/ramda@0.28.1",
31
- "@pnpm/deps.path": "1100.0.3",
32
- "@pnpm/lockfile.types": "1100.0.6",
33
- "@pnpm/resolving.resolver-base": "1100.2.0",
34
- "@pnpm/types": "1101.1.0",
35
- "@pnpm/error": "1100.0.0",
36
- "@pnpm/hooks.types": "1100.0.7"
31
+ "@pnpm/deps.path": "1100.0.5",
32
+ "@pnpm/lockfile.types": "1100.0.8",
33
+ "@pnpm/hooks.types": "1100.0.9",
34
+ "@pnpm/types": "1101.2.0",
35
+ "@pnpm/resolving.resolver-base": "1100.3.1",
36
+ "@pnpm/error": "1100.0.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@jest/globals": "30.3.0",
@@ -41,7 +41,7 @@
41
41
  "tempy": "3.0.0",
42
42
  "write-yaml-file": "^6.0.0",
43
43
  "yaml-tag": "1.1.0",
44
- "@pnpm/lockfile.utils": "1100.0.8"
44
+ "@pnpm/lockfile.utils": "1100.0.10"
45
45
  },
46
46
  "engines": {
47
47
  "node": ">=22.13"