fix: require provenance for trusted publisher evidence

This commit is contained in:
mehmet turac
2026-05-24 22:35:09 +03:00
committed by Zoltan Kochan
parent 494cdcaa01
commit fea5fd41da
5 changed files with 37 additions and 8 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/resolving.npm-resolver": patch
---
Require provenance before treating trusted publisher metadata as the strongest trust evidence.

View File

@@ -329,8 +329,8 @@ async function runAgeCheck (
* attestation endpoint is cheaper than the packument: presence of
* provenance on the current version is not sufficient to clear a
* downgrade. A package could have shipped earlier versions under a
* `trustedPublisher` (the higher-rank evidence) and then dropped
* back to plain provenance for the version we're verifying —
* `trustedPublisher` with provenance (the higher-rank evidence) and
* then dropped back to plain provenance for the version we're verifying —
* `failIfTrustDowngraded` correctly flags that, and a "has any
* attestation → pass" shortcut would silently miss it.
*/

View File

@@ -117,7 +117,7 @@ function detectStrongestTrustEvidenceBeforeDate (
}
export function getTrustEvidence (manifest: PackageInRegistry): TrustEvidence | undefined {
if (manifest._npmUser?.trustedPublisher) {
if (manifest._npmUser?.trustedPublisher && manifest.dist?.attestations?.provenance) {
return 'trustedPublisher'
}
if (manifest.dist?.attestations?.provenance) {

View File

@@ -50,7 +50,7 @@ test('createNpmResolutionVerifier() returns undefined when no policy is active',
})
test('createNpmResolutionVerifier() flags a trustedPublisher → provenance downgrade', async () => {
// 0.0.1 was published by a trustedPublisher → rank 2.
// 0.0.1 was published by a trustedPublisher with provenance → rank 2.
// 0.0.2 is provenance-only (rank 1, weaker) → downgrade vs 0.0.1.
// This is exactly the case the resolver-time trustChecks unit tests
// cover, but routed through the lockfile verifier. The verifier must
@@ -62,7 +62,11 @@ test('createNpmResolutionVerifier() flags a trustedPublisher → provenance down
'0.0.1': {
name: 'demo',
version: '0.0.1',
dist: { tarball: 'https://registry.npmjs.org/demo/-/demo-0.0.1.tgz', shasum: 'aa' },
dist: {
tarball: 'https://registry.npmjs.org/demo/-/demo-0.0.1.tgz',
shasum: 'aa',
attestations: { provenance: { url: 'https://example.org/p' } },
},
_npmUser: { trustedPublisher: { id: 'gha', oidcConfigId: 'cfg' } },
},
'0.0.2': {

View File

@@ -5,7 +5,7 @@ import type { PackageInRegistry, PackageMetaWithTime } from '@pnpm/resolving.reg
import { failIfTrustDowngraded, getTrustEvidence } from '../src/trustChecks.js'
describe('getTrustEvidence', () => {
test('returns "trustedPublisher" when _npmUser.trustedPublisher exists', () => {
test('returns undefined when _npmUser.trustedPublisher exists without provenance', () => {
const manifest: PackageInRegistry = {
name: 'foo',
version: '1.0.0',
@@ -22,10 +22,10 @@ describe('getTrustEvidence', () => {
tarball: 'https://registry.example.com/foo/-/foo-1.0.0.tgz',
},
}
expect(getTrustEvidence(manifest)).toBe('trustedPublisher')
expect(getTrustEvidence(manifest)).toBeUndefined()
})
test('returns "trustedPublisher" even when attestations.provenance exists', () => {
test('returns "trustedPublisher" when attestations.provenance also exists', () => {
const manifest: PackageInRegistry = {
name: 'foo',
version: '1.0.0',
@@ -285,6 +285,11 @@ describe('failIfTrustDowngraded', () => {
dist: {
shasum: 'def456',
tarball: 'https://registry.example.com/foo/-/foo-2.0.0.tgz',
attestations: {
provenance: {
predicateType: 'https://slsa.dev/provenance/v1',
},
},
},
},
'3.0.0': {
@@ -339,6 +344,11 @@ describe('failIfTrustDowngraded', () => {
dist: {
shasum: 'def456',
tarball: 'https://registry.example.com/foo/-/foo-2.0.0.tgz',
attestations: {
provenance: {
predicateType: 'https://slsa.dev/provenance/v1',
},
},
},
},
'3.0.0': {
@@ -388,6 +398,11 @@ describe('failIfTrustDowngraded', () => {
dist: {
shasum: 'def456',
tarball: 'https://registry.example.com/foo/-/foo-2.0.0.tgz',
attestations: {
provenance: {
predicateType: 'https://slsa.dev/provenance/v1',
},
},
},
},
'3.0.0': {
@@ -404,6 +419,11 @@ describe('failIfTrustDowngraded', () => {
dist: {
shasum: 'ghi789',
tarball: 'https://registry.example.com/foo/-/foo-3.0.0.tgz',
attestations: {
provenance: {
predicateType: 'https://slsa.dev/provenance/v1',
},
},
},
},
},