mirror of
https://github.com/pnpm/pnpm.git
synced 2026-06-29 18:35:18 -04:00
fix: skip lockfile minimumReleaseAge/trustPOlicy verification for non-registry tarball (#12122)
This commit is contained in:
6
.changeset/short-lamps-relax.md
Normal file
6
.changeset/short-lamps-relax.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/resolving.npm-resolver": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Skip lockfile `minimumReleaseAge`/`trustPolicy` verification for non-registry tarball protocols (for example `file:`), so local tarball dependencies are not incorrectly checked against npm registry metadata.
|
||||
@@ -757,6 +757,12 @@ fn npm_registry_tarball(resolution: &LockfileResolution) -> Option<Option<&str>>
|
||||
if t.git_hosted.unwrap_or(false) {
|
||||
return None;
|
||||
}
|
||||
if let Ok(parsed) = reqwest::Url::parse(&t.tarball) {
|
||||
let scheme = parsed.scheme();
|
||||
if scheme != "http" && scheme != "https" {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(Some(t.tarball.as_str()))
|
||||
}
|
||||
LockfileResolution::Directory(_)
|
||||
|
||||
@@ -237,6 +237,24 @@ async fn verify_short_circuits_non_semver_version() {
|
||||
assert_eq!(result, ResolutionVerification::Ok);
|
||||
}
|
||||
|
||||
/// `file:` tarball resolutions are local artifacts, not registry
|
||||
/// entries, so the verifier must skip minimumReleaseAge/trust checks.
|
||||
#[tokio::test]
|
||||
async fn verify_short_circuits_file_tarball_resolution() {
|
||||
let mut opts = default_opts("http://nonexistent.example.invalid/");
|
||||
opts.minimum_release_age = Some(60 * 24 * 365);
|
||||
let verifier = create_npm_resolution_verifier(opts).expect("verifier");
|
||||
let resolution = LockfileResolution::Tarball(TarballResolution {
|
||||
tarball: "file:vendor/types__my-cool-lib-v1.0.0.tgz".to_string(),
|
||||
integrity: Some(fake_integrity()),
|
||||
git_hosted: None,
|
||||
path: None,
|
||||
});
|
||||
let name: PkgName = "@types/my-cool-lib".parse().expect("parse");
|
||||
let result = verifier.verify(&resolution, ctx(&name, "1.0.0")).await;
|
||||
assert_eq!(result, ResolutionVerification::Ok);
|
||||
}
|
||||
|
||||
/// When the exclude policy covers the package, age check skips —
|
||||
/// the version is treated as opted out regardless of its publish
|
||||
/// timestamp.
|
||||
|
||||
@@ -830,5 +830,12 @@ function isNpmRegistryResolution (resolution: Resolution | unknown): boolean {
|
||||
// Git-hosted tarballs (codeload/gitlab/bitbucket) are special-cased in
|
||||
// the resolver and aren't subject to release-age policy.
|
||||
if ('gitHosted' in resolution && (resolution as { gitHosted?: boolean }).gitHosted) return false
|
||||
const tarball = (resolution as { tarball?: unknown }).tarball
|
||||
if (typeof tarball === 'string') {
|
||||
// Local/non-registry tarballs (for example `file:`) have no packument
|
||||
// metadata, so minimumReleaseAge/trustPolicy verification cannot apply.
|
||||
const protocol = tryParseUrl(tarball)?.protocol
|
||||
if (protocol != null && protocol !== 'http:' && protocol !== 'https:') return false
|
||||
}
|
||||
return 'tarball' in resolution || 'integrity' in resolution
|
||||
}
|
||||
|
||||
@@ -221,6 +221,20 @@ test('createNpmResolutionVerifier() ignoreMissingTimeField passes the entry when
|
||||
expect(result).toEqual({ ok: true })
|
||||
})
|
||||
|
||||
test('createNpmResolutionVerifier() skips file: tarball resolutions', async () => {
|
||||
const verifier = createNpmResolutionVerifier(makeVerifierOpts({
|
||||
minimumReleaseAge: 1440,
|
||||
}))!
|
||||
const result = await verifier.verify(
|
||||
{
|
||||
integrity: 'sha512-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==',
|
||||
tarball: 'file:vendor/types__my-cool-lib-v1.0.0.tgz',
|
||||
} as unknown as Resolution,
|
||||
{ name: '@types/my-cool-lib', version: '1.0.0' }
|
||||
)
|
||||
expect(result).toEqual({ ok: true })
|
||||
})
|
||||
|
||||
test('createNpmResolutionVerifier() canTrustPastCheck rejects when the trust-exclude list shrinks', () => {
|
||||
const verifier = createNpmResolutionVerifier(makeVerifierOpts({
|
||||
trustPolicy: 'no-downgrade',
|
||||
|
||||
Reference in New Issue
Block a user