@pnpm/installing.env-installer 1101.1.8 → 1102.0.1

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.
@@ -0,0 +1 @@
1
+ export declare function assertValidConfigDepVersion(name: string, version: string): void;
@@ -0,0 +1,11 @@
1
+ import { PnpmError } from '@pnpm/error';
2
+ import semver from 'semver';
3
+ // A config-dep version becomes a store path segment (`<name>/<version>/<hash>`),
4
+ // so reject non-semver values to keep a traversal-shaped version from escaping
5
+ // the store root.
6
+ export function assertValidConfigDepVersion(name, version) {
7
+ if (semver.valid(version) == null) {
8
+ throw new PnpmError('INVALID_CONFIG_DEP_VERSION', `The config dependency "${name}" has an invalid version "${version}"`, { hint: 'A config dependency version must be an exact semver version.' });
9
+ }
10
+ }
11
+ //# sourceMappingURL=assertValidConfigDepVersion.js.map
package/lib/index.d.ts CHANGED
@@ -2,3 +2,4 @@ export { installConfigDeps, type InstallConfigDepsOpts } from './installConfigDe
2
2
  export { resolveAndInstallConfigDeps, type ResolveAndInstallConfigDepsOpts } from './resolveAndInstallConfigDeps.js';
3
3
  export { resolveConfigDeps, type ResolveConfigDepsOpts } from './resolveConfigDeps.js';
4
4
  export { isPackageManagerResolved, resolvePackageManagerIntegrities, type ResolvePackageManagerIntegritiesOpts } from './resolvePackageManagerIntegrities.js';
5
+ export { verifyEnvLockfile } from './verifyEnvLockfile.js';
package/lib/index.js CHANGED
@@ -2,4 +2,5 @@ export { installConfigDeps } from './installConfigDeps.js';
2
2
  export { resolveAndInstallConfigDeps } from './resolveAndInstallConfigDeps.js';
3
3
  export { resolveConfigDeps } from './resolveConfigDeps.js';
4
4
  export { isPackageManagerResolved, resolvePackageManagerIntegrities } from './resolvePackageManagerIntegrities.js';
5
+ export { verifyEnvLockfile } from './verifyEnvLockfile.js';
5
6
  //# sourceMappingURL=index.js.map
@@ -11,6 +11,7 @@ import { rimraf } from '@zkochan/rimraf';
11
11
  import getNpmTarballUrl from 'get-npm-tarball-url';
12
12
  import { symlinkDir } from 'symlink-dir';
13
13
  import { migrateConfigDepsToLockfile } from './migrateConfigDeps.js';
14
+ import { verifyEnvLockfile } from './verifyEnvLockfile.js';
14
15
  /**
15
16
  * Install config dependencies using the env lockfile.
16
17
  * Accepts either a EnvLockfile directly (from resolveConfigDeps) or
@@ -109,12 +110,14 @@ export async function installConfigDeps(configDepsOrLockfile, opts) {
109
110
  async function normalizeForInstall(configDepsOrLockfile, opts) {
110
111
  // If it's a EnvLockfile object (has lockfileVersion), use it directly
111
112
  if (isEnvLockfile(configDepsOrLockfile)) {
113
+ verifyEnvLockfile(configDepsOrLockfile);
112
114
  return normalizeFromLockfile(configDepsOrLockfile, opts.registries);
113
115
  }
114
116
  // It's ConfigDependencies from workspace manifest.
115
117
  // Try to read the env lockfile first.
116
118
  const envLockfile = await readEnvLockfile(opts.rootDir);
117
119
  if (envLockfile) {
120
+ verifyEnvLockfile(envLockfile);
118
121
  return normalizeFromLockfile(envLockfile, opts.registries);
119
122
  }
120
123
  // No env lockfile yet — migrate from old inline integrity format
@@ -1,10 +1,11 @@
1
1
  import { pickRegistryForPackage } from '@pnpm/config.pick-registry-for-package';
2
2
  import { writeSettings } from '@pnpm/config.writer';
3
3
  import { PnpmError } from '@pnpm/error';
4
- import { createEnvLockfile, writeEnvLockfile } from '@pnpm/lockfile.fs';
4
+ import { createEnvLockfile } from '@pnpm/lockfile.fs';
5
5
  import { toLockfileResolution } from '@pnpm/lockfile.utils';
6
6
  import getNpmTarballUrl from 'get-npm-tarball-url';
7
7
  import { parseIntegrity } from './parseIntegrity.js';
8
+ import { writeVerifiedEnvLockfile } from './writeVerifiedEnvLockfile.js';
8
9
  /**
9
10
  * Migrates old-format configDependencies (with inline integrity in pnpm-workspace.yaml)
10
11
  * to the new pnpm-lock.yaml format.
@@ -14,6 +15,9 @@ import { parseIntegrity } from './parseIntegrity.js';
14
15
  */
15
16
  export async function migrateConfigDepsToLockfile(configDeps, opts) {
16
17
  const envLockfile = createEnvLockfile();
18
+ // Null-prototype so a `__proto__` name lands as an own key verifyEnvLockfile
19
+ // sees, not a silent prototype mutation.
20
+ envLockfile.importers['.'].configDependencies = Object.create(null);
17
21
  const cleanSpecifiers = {};
18
22
  const normalizedDeps = {};
19
23
  for (const [pkgName, pkgSpec] of Object.entries(configDeps)) {
@@ -64,17 +68,14 @@ export async function migrateConfigDepsToLockfile(configDeps, opts) {
64
68
  };
65
69
  }
66
70
  }
67
- // Write the new env lockfile and clean up workspace manifest
68
- await Promise.all([
69
- writeEnvLockfile(opts.rootDir, envLockfile),
70
- writeSettings({
71
- rootProjectManifestDir: opts.rootDir,
72
- workspaceDir: opts.rootDir,
73
- updatedSettings: {
74
- configDependencies: cleanSpecifiers,
75
- },
76
- }),
77
- ]);
71
+ await writeVerifiedEnvLockfile(opts.rootDir, envLockfile);
72
+ await writeSettings({
73
+ rootProjectManifestDir: opts.rootDir,
74
+ workspaceDir: opts.rootDir,
75
+ updatedSettings: {
76
+ configDependencies: cleanSpecifiers,
77
+ },
78
+ });
78
79
  return normalizedDeps;
79
80
  }
80
81
  //# sourceMappingURL=migrateConfigDeps.js.map
@@ -1,6 +1,6 @@
1
1
  import { pickRegistryForPackage } from '@pnpm/config.pick-registry-for-package';
2
2
  import { PnpmError } from '@pnpm/error';
3
- import { createEnvLockfile, readEnvLockfile, writeEnvLockfile, } from '@pnpm/lockfile.fs';
3
+ import { createEnvLockfile, readEnvLockfile, } from '@pnpm/lockfile.fs';
4
4
  import { toLockfileResolution } from '@pnpm/lockfile.utils';
5
5
  import { createGetAuthHeaderByURI } from '@pnpm/network.auth-header';
6
6
  import { createFetchFromRegistry } from '@pnpm/network.fetch';
@@ -10,6 +10,7 @@ import { installConfigDeps } from './installConfigDeps.js';
10
10
  import { parseIntegrity } from './parseIntegrity.js';
11
11
  import { pruneEnvLockfile } from './pruneEnvLockfile.js';
12
12
  import { resolveOptionalSubdeps } from './resolveOptionalSubdeps.js';
13
+ import { writeVerifiedEnvLockfile } from './writeVerifiedEnvLockfile.js';
13
14
  /**
14
15
  * Resolves any config dependencies that are missing from the env lockfile,
15
16
  * then installs all config dependencies.
@@ -71,7 +72,7 @@ export async function resolveAndInstallConfigDeps(configDeps, opts) {
71
72
  }
72
73
  if (depsToResolve.length === 0) {
73
74
  if (lockfileChanged) {
74
- await writeEnvLockfile(opts.rootDir, envLockfile);
75
+ await writeVerifiedEnvLockfile(opts.rootDir, envLockfile);
75
76
  }
76
77
  await installConfigDeps(envLockfile, opts);
77
78
  return;
@@ -111,7 +112,7 @@ export async function resolveAndInstallConfigDeps(configDeps, opts) {
111
112
  envLockfile.snapshots[pkgKey] = optionalSubdeps ? { optionalDependencies: optionalSubdeps } : {};
112
113
  }));
113
114
  pruneEnvLockfile(envLockfile);
114
- await writeEnvLockfile(opts.rootDir, envLockfile);
115
+ await writeVerifiedEnvLockfile(opts.rootDir, envLockfile);
115
116
  await installConfigDeps(envLockfile, opts);
116
117
  }
117
118
  //# sourceMappingURL=resolveAndInstallConfigDeps.js.map
@@ -1,7 +1,7 @@
1
1
  import { pickRegistryForPackage } from '@pnpm/config.pick-registry-for-package';
2
2
  import { writeSettings } from '@pnpm/config.writer';
3
3
  import { PnpmError } from '@pnpm/error';
4
- import { createEnvLockfile, readEnvLockfile, writeEnvLockfile, } from '@pnpm/lockfile.fs';
4
+ import { createEnvLockfile, readEnvLockfile, } from '@pnpm/lockfile.fs';
5
5
  import { toLockfileResolution } from '@pnpm/lockfile.utils';
6
6
  import { createGetAuthHeaderByURI } from '@pnpm/network.auth-header';
7
7
  import { createFetchFromRegistry } from '@pnpm/network.fetch';
@@ -10,6 +10,7 @@ import { parseWantedDependency } from '@pnpm/resolving.parse-wanted-dependency';
10
10
  import { installConfigDeps } from './installConfigDeps.js';
11
11
  import { pruneEnvLockfile } from './pruneEnvLockfile.js';
12
12
  import { resolveOptionalSubdeps } from './resolveOptionalSubdeps.js';
13
+ import { writeVerifiedEnvLockfile } from './writeVerifiedEnvLockfile.js';
13
14
  export async function resolveConfigDeps(configDeps, opts) {
14
15
  if (opts.frozenLockfile) {
15
16
  throw new PnpmError('FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE', 'Cannot resolve configDependencies with "frozen-lockfile" because the lockfile is not up to date');
@@ -56,17 +57,15 @@ export async function resolveConfigDeps(configDeps, opts) {
56
57
  envLockfile.snapshots[pkgKey] = optionalSubdeps ? { optionalDependencies: optionalSubdeps } : {};
57
58
  }));
58
59
  pruneEnvLockfile(envLockfile);
59
- await Promise.all([
60
- writeSettings({
61
- ...opts,
62
- rootProjectManifestDir: opts.rootDir,
63
- workspaceDir: opts.rootDir,
64
- updatedSettings: {
65
- configDependencies: configDependencySpecifiers,
66
- },
67
- }),
68
- writeEnvLockfile(opts.rootDir, envLockfile),
69
- ]);
60
+ await writeVerifiedEnvLockfile(opts.rootDir, envLockfile);
61
+ await writeSettings({
62
+ ...opts,
63
+ rootProjectManifestDir: opts.rootDir,
64
+ workspaceDir: opts.rootDir,
65
+ updatedSettings: {
66
+ configDependencies: configDependencySpecifiers,
67
+ },
68
+ });
70
69
  await installConfigDeps(envLockfile, opts);
71
70
  }
72
71
  /**
@@ -1,7 +1,8 @@
1
- import { convertToLockfileFile, createEnvLockfile, readEnvLockfile, writeEnvLockfile } from '@pnpm/lockfile.fs';
1
+ import { convertToLockfileFile, createEnvLockfile, readEnvLockfile } from '@pnpm/lockfile.fs';
2
2
  import { pruneSharedLockfile } from '@pnpm/lockfile.pruner';
3
3
  import { convertToLockfileEnvObject } from './pruneEnvLockfile.js';
4
4
  import { resolveManifestDependencies } from './resolveManifestDependencies.js';
5
+ import { writeVerifiedEnvLockfile } from './writeVerifiedEnvLockfile.js';
5
6
  /**
6
7
  * Checks if the wanted pnpm version integrities are already fully resolved in the env lockfile.
7
8
  */
@@ -58,7 +59,7 @@ export async function resolvePackageManagerIntegrities(pnpmVersion, opts) {
58
59
  envLockfile.packages = prunedFile.packages ?? {};
59
60
  envLockfile.snapshots = prunedFile.snapshots ?? {};
60
61
  if (save) {
61
- await writeEnvLockfile(opts.rootDir, envLockfile);
62
+ await writeVerifiedEnvLockfile(opts.rootDir, envLockfile);
62
63
  }
63
64
  }
64
65
  return envLockfile;
@@ -0,0 +1,2 @@
1
+ import type { EnvLockfile } from '@pnpm/lockfile.fs';
2
+ export declare function verifyEnvLockfile(envLockfile: EnvLockfile): void;
@@ -0,0 +1,24 @@
1
+ import { assertValidDependencyAliases } from '@pnpm/installing.deps-resolver';
2
+ import { assertValidConfigDepVersion } from './assertValidConfigDepVersion.js';
3
+ // Offline structural gate for the env lockfile, mirroring the alias/shape
4
+ // checks `verifyLockfileResolutions` runs over the main lockfile. Config
5
+ // dependency and optional-subdependency names and versions become store path
6
+ // segments, so reject any that isn't a valid npm name / exact semver before a
7
+ // path is built from them.
8
+ export function verifyEnvLockfile(envLockfile) {
9
+ const configDeps = envLockfile.importers['.']?.configDependencies;
10
+ assertValidDependencyAliases(configDeps, 'The configDependencies in pnpm-lock.yaml');
11
+ if (configDeps == null)
12
+ return;
13
+ for (const [name, { version }] of Object.entries(configDeps)) {
14
+ assertValidConfigDepVersion(name, version);
15
+ const optionalDeps = envLockfile.snapshots[`${name}@${version}`]?.optionalDependencies;
16
+ if (optionalDeps == null)
17
+ continue;
18
+ assertValidDependencyAliases(optionalDeps, `The optionalDependencies of config dependency "${name}" in pnpm-lock.yaml`);
19
+ for (const [subdepName, subdepVersion] of Object.entries(optionalDeps)) {
20
+ assertValidConfigDepVersion(subdepName, subdepVersion);
21
+ }
22
+ }
23
+ }
24
+ //# sourceMappingURL=verifyEnvLockfile.js.map
@@ -0,0 +1,2 @@
1
+ import { type EnvLockfile } from '@pnpm/lockfile.fs';
2
+ export declare function writeVerifiedEnvLockfile(rootDir: string, envLockfile: EnvLockfile): Promise<void>;
@@ -0,0 +1,9 @@
1
+ import { writeEnvLockfile } from '@pnpm/lockfile.fs';
2
+ import { verifyEnvLockfile } from './verifyEnvLockfile.js';
3
+ // Persist an env lockfile only after verifying it, so no code path can write
4
+ // one carrying an invalid config-dependency name or version.
5
+ export async function writeVerifiedEnvLockfile(rootDir, envLockfile) {
6
+ verifyEnvLockfile(envLockfile);
7
+ await writeEnvLockfile(rootDir, envLockfile);
8
+ }
9
+ //# sourceMappingURL=writeVerifiedEnvLockfile.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/installing.env-installer",
3
- "version": "1101.1.8",
3
+ "version": "1102.0.1",
4
4
  "description": "Installer for configurational dependencies",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -30,43 +30,43 @@
30
30
  "dependencies": {
31
31
  "@zkochan/rimraf": "^4.0.0",
32
32
  "get-npm-tarball-url": "^2.1.0",
33
- "semver": "^7.8.1",
33
+ "semver": "^7.8.4",
34
34
  "symlink-dir": "^10.0.1",
35
+ "@pnpm/config.package-is-installable": "1100.0.11",
36
+ "@pnpm/config.writer": "1100.0.13",
35
37
  "@pnpm/constants": "1100.0.0",
36
- "@pnpm/config.writer": "1100.0.12",
37
- "@pnpm/core-loggers": "1100.2.0",
38
- "@pnpm/error": "1100.0.0",
39
- "@pnpm/installing.deps-resolver": "1100.2.2",
38
+ "@pnpm/core-loggers": "1100.2.1",
39
+ "@pnpm/deps.graph-hasher": "1100.2.5",
40
40
  "@pnpm/fs.read-modules-dir": "1100.0.1",
41
- "@pnpm/lockfile.fs": "1100.1.4",
42
- "@pnpm/config.pick-registry-for-package": "1100.0.8",
43
- "@pnpm/network.auth-header": "1101.1.1",
44
- "@pnpm/lockfile.utils": "1100.0.12",
45
- "@pnpm/lockfile.pruner": "1100.0.10",
46
- "@pnpm/config.package-is-installable": "1100.0.10",
47
- "@pnpm/lockfile.types": "1100.0.10",
41
+ "@pnpm/installing.deps-resolver": "1100.2.4",
42
+ "@pnpm/lockfile.fs": "1100.1.6",
43
+ "@pnpm/lockfile.pruner": "1100.0.11",
44
+ "@pnpm/lockfile.utils": "1100.0.13",
45
+ "@pnpm/lockfile.types": "1100.0.11",
46
+ "@pnpm/network.auth-header": "1101.1.2",
47
+ "@pnpm/pkg-manifest.reader": "1100.0.8",
48
+ "@pnpm/resolving.npm-resolver": "1102.0.1",
49
+ "@pnpm/network.fetch": "1100.1.3",
48
50
  "@pnpm/resolving.parse-wanted-dependency": "1100.0.1",
49
- "@pnpm/pkg-manifest.reader": "1100.0.7",
50
- "@pnpm/store.controller-types": "1100.1.4",
51
- "@pnpm/types": "1101.3.1",
52
- "@pnpm/store.controller": "1101.0.13",
53
- "@pnpm/network.fetch": "1100.1.2",
54
- "@pnpm/deps.graph-hasher": "1100.2.4",
55
- "@pnpm/resolving.npm-resolver": "1101.5.2"
51
+ "@pnpm/store.controller-types": "1100.1.5",
52
+ "@pnpm/types": "1101.3.2",
53
+ "@pnpm/store.controller": "1102.0.1",
54
+ "@pnpm/error": "1100.0.0",
55
+ "@pnpm/config.pick-registry-for-package": "1100.0.9"
56
56
  },
57
57
  "peerDependencies": {
58
- "@pnpm/logger": "^1001.0.1",
59
- "@pnpm/worker": "^1100.1.11"
58
+ "@pnpm/logger": "^1100.0.0",
59
+ "@pnpm/worker": "^1100.2.1"
60
60
  },
61
61
  "devDependencies": {
62
- "@jest/globals": "30.3.0",
62
+ "@jest/globals": "30.4.1",
63
63
  "@types/semver": "7.7.1",
64
64
  "load-json-file": "^7.0.1",
65
65
  "read-yaml-file": "^3.0.0",
66
- "@pnpm/installing.env-installer": "1101.1.8",
67
- "@pnpm/prepare": "1100.0.15",
68
- "@pnpm/testing.temp-store": "1100.1.8",
69
- "@pnpm/testing.registry-mock": "1100.0.5"
66
+ "@pnpm/installing.env-installer": "1102.0.1",
67
+ "@pnpm/prepare": "1100.0.16",
68
+ "@pnpm/testing.temp-store": "1100.1.10",
69
+ "@pnpm/testing.registry-mock": "1100.0.6"
70
70
  },
71
71
  "engines": {
72
72
  "node": ">=22.13"