mirror of
https://github.com/pnpm/pnpm.git
synced 2026-05-29 19:20:04 -04:00
fix: require provenance for trusted publisher evidence
This commit is contained in:
committed by
Zoltan Kochan
parent
494cdcaa01
commit
fea5fd41da
5
.changeset/tidy-trust-publishers.md
Normal file
5
.changeset/tidy-trust-publishers.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/resolving.npm-resolver": patch
|
||||
---
|
||||
|
||||
Require provenance before treating trusted publisher metadata as the strongest trust evidence.
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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': {
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user