Skip to content

Commit

Permalink
feat: verifyAttestations to registry.manifest
Browse files Browse the repository at this point in the history
Add support for verifying sigstore attestations when fetching the registry.manifest.
This will be ased in CLI as part of `audit signatures`.

RFC: npm/rfcs#626

Signed-off-by: Philip Harrison <[email protected]>
Co-authored-by: Brian DeHamer <[email protected]>
Signed-off-by: Philip Harrison <[email protected]>
  • Loading branch information
2 people authored and wraithgar committed Feb 13, 2023
1 parent f0bd19b commit 2916b72
Show file tree
Hide file tree
Showing 11 changed files with 1,730 additions and 3 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@ resolved, and other properties, as they are determined.
integrity signature of a manifest, if present. There must be a
configured `_keys` entry in the config that is scoped to the
registry the manifest is being fetched from.

* `verifyAttestations` A boolean that will make pacote verify Sigstore
attestations, if present. There must be a configured `_keys` entry in the
config that is scoped to the registry the manifest is being fetched from.

### Advanced API

Expand Down
113 changes: 113 additions & 0 deletions lib/registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const rpj = require('read-package-json-fast')
const pickManifest = require('npm-pick-manifest')
const ssri = require('ssri')
const crypto = require('crypto')
const npa = require('npm-package-arg')
const { sigstore } = require('sigstore')

// Corgis are cute. 🐕🐶
const corgiDoc = 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*'
Expand Down Expand Up @@ -203,7 +205,118 @@ class RegistryFetcher extends Fetcher {
mani._signatures = dist.signatures
}
}

if (dist.attestations) {
if (this.opts.verifyAttestations) {
// Always fetch attestations from the current registry host
const attestationsPath = new URL(dist.attestations.url).pathname
const attestationsUrl = removeTrailingSlashes(this.registry) + attestationsPath
const res = await fetch(attestationsUrl, {
...this.opts,
// disable integrity check for attestations json payload, we check the
// integrity in the verification steps below
integrity: null,
})
const { attestations } = await res.json()
const bundles = attestations.map(({ predicateType, bundle }) => {
const statement = JSON.parse(
Buffer.from(bundle.dsseEnvelope.payload, 'base64').toString('utf8')
)
const keyid = bundle.dsseEnvelope.signatures[0].keyid
const signature = bundle.dsseEnvelope.signatures[0].sig

return {
predicateType,
bundle,
statement,
keyid,
signature,
}
})

const attestationKeyIds = bundles.map((b) => b.keyid).filter((k) => !!k)
const attestationRegistryKeys = (this.registryKeys || [])
.filter(key => attestationKeyIds.includes(key.keyid))
if (!attestationRegistryKeys.length) {
throw Object.assign(new Error(
`${mani._id} has attestations but no corresponding public key(s) can be found`
), { code: 'EMISSINGSIGNATUREKEY' })
}

for (const { predicateType, bundle, keyid, signature, statement } of bundles) {
const publicKey = attestationRegistryKeys.find(key => key.keyid === keyid)
// Publish attestations have a keyid set and a valid public key must be found
if (keyid) {
if (!publicKey) {
throw Object.assign(new Error(
`${mani._id} has attestations with keyid: ${keyid} ` +
'but no corresponding public key can be found'
), { code: 'EMISSINGSIGNATUREKEY' })
}

const validPublicKey =
!publicKey.expires || (Date.parse(publicKey.expires) > Date.now())
if (!validPublicKey) {
throw Object.assign(new Error(
`${mani._id} has attestations with keyid: ${keyid} ` +
`but the corresponding public key has expired ${publicKey.expires}`
), { code: 'EEXPIREDSIGNATUREKEY' })
}
}

const subject = {
name: statement.subject[0].name,
sha512: statement.subject[0].digest.sha512,
}

// Only type 'version' can be turned into a PURL
const purl = this.spec.type === 'version' ? npa.toPurl(this.spec) : this.spec
// Verify the statement subject matches the package, version
if (subject.name !== purl) {
throw Object.assign(new Error(
`${mani._id} package name and version (PURL): ${purl} ` +
`doesn't match what was signed: ${subject.name}`
), { code: 'EATTESTATIONSUBJECT' })
}

// Verify the statement subject matches the tarball integrity
const integrityHexDigest = ssri.parse(this.integrity).hexDigest()
if (subject.sha512 !== integrityHexDigest) {
throw Object.assign(new Error(
`${mani._id} package integrity (hex digest): ` +
`${integrityHexDigest} ` +
`doesn't match what was signed: ${subject.sha512}`
), { code: 'EATTESTATIONSUBJECT' })
}

try {
// Provenance attestations are signed with a signing certificate
// (including the key) so we don't need to return a public key.
//
// Publish attestations are signed with a keyid so we need to
// specify a public key from the keys endpoint: `registry-host.tld/-/npm/v1/keys`
const options = { keySelector: publicKey ? () => publicKey.pemkey : undefined }
await sigstore.verify(bundle, null, options)
} catch (e) {
throw Object.assign(new Error(
`${mani._id} failed to verify attestation: ${e.message}`
), {
code: 'EATTESTATIONVERIFY',
predicateType,
keyid,
signature,
resolved: mani._resolved,
integrity: mani._integrity,
})
}
}
mani._attestations = dist.attestations
} else {
mani._attestations = dist.attestations
}
}
}

this.package = mani
return this.package
}
Expand Down
98 changes: 98 additions & 0 deletions test/fixtures/sigstore/invalid-attestations.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{
"attestations": [
{
"predicateType": "https://slsa.dev/provenance/v0.2",
"bundle": {
"mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.1",
"verificationMaterial": {
"x509CertificateChain": {
"certificates": [
{
"rawBytes": "MIIDnDCCAyKgAwIBAgIUEg2LbBC+v12QtPBt2jawiYrF33UwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjMwMTExMTczMTUyWhcNMjMwMTExMTc0MTUyWjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEscmo8xVdr+olWHVVpTlLdKdTwTDvNpINwLXi6W2OlPwTkMbJj0zCpO99heNH4ZxF1+NmO6NyjcbynKjf/GPUV6OCAkEwggI9MA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUdsZZ492PIgVwGjT/q8AwgHhDkj4wHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4YZD8wZAYDVR0RAQH/BFowWIZWaHR0cHM6Ly9naXRodWIuY29tL3NpZ3N0b3JlL3NpZ3N0b3JlLWpzLy5naXRodWIvd29ya2Zsb3dzL3B1Ymxpc2gueW1sQHJlZnMvdGFncy92MC40LjAwOQYKKwYBBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50LmNvbTAVBgorBgEEAYO/MAECBAdyZWxlYXNlMDYGCisGAQQBg78wAQMEKDhhMmVlMmZkMjBkZGE1OGZmYTRhOGQ4MDhhNjVjYjFlMDQ3MTFjMDMwFQYKKwYBBAGDvzABBAQHcHVibGlzaDAiBgorBgEEAYO/MAEFBBRzaWdzdG9yZS9zaWdzdG9yZS1qczAeBgorBgEEAYO/MAEGBBByZWZzL3RhZ3MvdjAuNC4wMIGKBgorBgEEAdZ5AgQCBHwEegB4AHYA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGFoeNlfwAABAMARzBFAiBqYOxNKEMS4gXVBqU3Mr/w+yYXYtZDYa6daYOZJZB++wIhANat2b2mVTeHERPyhATU/Z8HOfC6iqY/IwiXnwWKsp9xMAoGCCqGSM49BAMDA2gAMGUCMQD5OzgtStQId/HNXGwVM1Ydjux8x2d4cr7tzWreGSbMUJhRuVlJliOdJKsu8ufHQfYCMC8M76uThWeCI2A5GndGj0TTaI1Cq92T8oXm5iHHFPxmvZtjXtnwCuGzLAKHILlmlg=="
},
{
"rawBytes": "MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV77LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZIzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJRnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsPmygUY7Ii2zbdCdliiow="
},
{
"rawBytes": "MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxexX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92jYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRYwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCMWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ"
}
]
},
"tlogEntries": [
{
"logIndex": "10960845",
"logId": {
"keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="
},
"kindVersion": {
"kind": "intoto",
"version": "0.0.2"
},
"integratedTime": "1673458312",
"inclusionPromise": {
"signedEntryTimestamp": "MEYCIQDzgIQqH7VfIGmZ3wQ7WQ5wnGnhZrv6/3Q90rOK2vsWrgIhAJUvX2WQ/BDp4oti3LEdFzG8KpJIU7sMfSRehK8BRQ+r"
},
"inclusionProof": null,
"canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjIiLCJraW5kIjoiaW50b3RvIiwic3BlYyI6eyJjb250ZW50Ijp7ImVudmVsb3BlIjp7InBheWxvYWRUeXBlIjoiYXBwbGljYXRpb24vdm5kLmluLXRvdG8ranNvbiIsInNpZ25hdHVyZXMiOlt7InB1YmxpY0tleSI6IkxTMHRMUzFDUlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJ1UkVORFFYbExaMEYzU1VKQlowbFZSV2N5VEdKQ1F5dDJNVEpSZEZCQ2RESnFZWGRwV1hKR016TlZkME5uV1VsTGIxcEplbW93UlVGM1RYY0tUbnBGVmsxQ1RVZEJNVlZGUTJoTlRXTXliRzVqTTFKMlkyMVZkVnBIVmpKTlVqUjNTRUZaUkZaUlVVUkZlRlo2WVZka2VtUkhPWGxhVXpGd1ltNVNiQXBqYlRGc1drZHNhR1JIVlhkSWFHTk9UV3BOZDAxVVJYaE5WR042VFZSVmVWZG9ZMDVOYWsxM1RWUkZlRTFVWXpCTlZGVjVWMnBCUVUxR2EzZEZkMWxJQ2t0dldrbDZhakJEUVZGWlNVdHZXa2w2YWpCRVFWRmpSRkZuUVVWelkyMXZPSGhXWkhJcmIyeFhTRlpXY0ZSc1RHUkxaRlIzVkVSMlRuQkpUbmRNV0drS05sY3lUMnhRZDFSclRXSkthakI2UTNCUE9UbG9aVTVJTkZwNFJqRXJUbTFQTms1NWFtTmllVzVMYW1ZdlIxQlZWalpQUTBGclJYZG5aMGs1VFVFMFJ3cEJNVlZrUkhkRlFpOTNVVVZCZDBsSVowUkJWRUpuVGxaSVUxVkZSRVJCUzBKblozSkNaMFZHUWxGalJFRjZRV1JDWjA1V1NGRTBSVVpuVVZWa2MxcGFDalE1TWxCSloxWjNSMnBVTDNFNFFYZG5TR2hFYTJvMGQwaDNXVVJXVWpCcVFrSm5kMFp2UVZVek9WQndlakZaYTBWYVlqVnhUbXB3UzBaWGFYaHBORmtLV2tRNGQxcEJXVVJXVWpCU1FWRklMMEpHYjNkWFNWcFhZVWhTTUdOSVRUWk1lVGx1WVZoU2IyUlhTWFZaTWpsMFRETk9jRm96VGpCaU0wcHNURE5PY0FwYU0wNHdZak5LYkV4WGNIcE1lVFZ1WVZoU2IyUlhTWFprTWpsNVlUSmFjMkl6WkhwTU0wSXhXVzE0Y0dNeVozVmxWekZ6VVVoS2JGcHVUWFprUjBadUNtTjVPVEpOUXpRd1RHcEJkMDlSV1V0TGQxbENRa0ZIUkhaNlFVSkJVVkZ5WVVoU01HTklUVFpNZVRrd1lqSjBiR0pwTldoWk0xSndZakkxZWt4dFpIQUtaRWRvTVZsdVZucGFXRXBxWWpJMU1GcFhOVEJNYlU1MllsUkJWa0puYjNKQ1owVkZRVmxQTDAxQlJVTkNRV1I1V2xkNGJGbFlUbXhOUkZsSFEybHpSd3BCVVZGQ1p6YzRkMEZSVFVWTFJHaG9UVzFXYkUxdFdtdE5ha0pyV2tkRk1VOUhXbTFaVkZKb1QwZFJORTFFYUdoT2FsWnFXV3BHYkUxRVVUTk5WRVpxQ2sxRVRYZEdVVmxMUzNkWlFrSkJSMFIyZWtGQ1FrRlJTR05JVm1saVIyeDZZVVJCYVVKbmIzSkNaMFZGUVZsUEwwMUJSVVpDUWxKNllWZGtlbVJIT1hrS1dsTTVlbUZYWkhwa1J6bDVXbE14Y1dONlFXVkNaMjl5UW1kRlJVRlpUeTlOUVVWSFFrSkNlVnBYV25wTU0xSm9Xak5OZG1ScVFYVk9RelIzVFVsSFN3cENaMjl5UW1kRlJVRmtXalZCWjFGRFFraDNSV1ZuUWpSQlNGbEJNMVF3ZDJGellraEZWRXBxUjFJMFkyMVhZek5CY1VwTFdISnFaVkJMTXk5b05IQjVDbWRET0hBM2J6UkJRVUZIUm05bFRteG1kMEZCUWtGTlFWSjZRa1pCYVVKeFdVOTRUa3RGVFZNMFoxaFdRbkZWTTAxeUwzY3JlVmxZV1hSYVJGbGhObVFLWVZsUFdrcGFRaXNyZDBsb1FVNWhkREppTW0xV1ZHVklSVkpRZVdoQlZGVXZXamhJVDJaRE5tbHhXUzlKZDJsWWJuZFhTM053T1hoTlFXOUhRME54UndwVFRUUTVRa0ZOUkVFeVowRk5SMVZEVFZGRU5VOTZaM1JUZEZGSlpDOUlUbGhIZDFaTk1WbGthblY0T0hneVpEUmpjamQwZWxkeVpVZFRZazFWU21oU0NuVldiRXBzYVU5a1NrdHpkVGgxWmtoUlpsbERUVU00VFRjMmRWUm9WMlZEU1RKQk5VZHVaRWRxTUZSVVlVa3hRM0U1TWxRNGIxaHROV2xJU0VaUWVHMEtkbHAwYWxoMGJuZERkVWQ2VEVGTFNFbE1iRzFzWnowOUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyIsInNpZyI6IlRVVlJRMGxDYXpobFl6SXZSMjB5ZGxOSllWbHVWelZaZFdKc1RIaE1ZM1J4UmxkRWExVldRbWhSU0doWlltdFFRV2xDWWpGWE1Hd3ZVM2xvUkV3NGFGSnBZbUZrT1VNM1pqaHFkM2R3T1dkU1lVdDVZV2xZWkROQlNEaHZVVDA5In1dfSwiaGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6IjI1NTdhZGNjYjFiZGYxNjA2NzExYjkwM2UxYmRiOGMwMmFhNjE2MzM4YzY0NjM2NTdiYmQwM2ViYjRmNzQyMTEifSwicGF5bG9hZEhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI1NjM0MjMyZmU2MTg4NWM0OTAyNGJmMWExMGJmZDNmYjljYzZhNmFjM2U5OTE1OGYxMjgzYmM0Yzk3MzEzYTAzIn19fX0="
}
],
"timestampVerificationData": {
"rfc3161Timestamps": []
}
},
"dsseEnvelope": {
"payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInN1YmplY3QiOlt7Im5hbWUiOiJwa2c6bnBtL3NpZ3N0b3JlQDAuNC4wIiwiZGlnZXN0Ijp7InNoYTUxMiI6IjI4MmMwYzVmYTkzNmQyNjQzMjE2NDM1ODFiNjVkM2RlNWMwYWY2ZWQ0ZmRmYWMxMmY1ODUxMTE1ZGYzOWNjMjVjZmFmMGFkMjJkOTA4NDg3YmZlZjMwMTE0ZDYxYzI1NzQ2MjA2ZDE4MzRiZTRmOGZkMTY1OTE3OGY3N2NjMDA0In19XSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vc2xzYS5kZXYvcHJvdmVuYW5jZS92MC4yIiwicHJlZGljYXRlIjp7ImJ1aWxkVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9ucG0vY2xpL2doYUB2MCIsImJ1aWxkZXIiOnsiaWQiOiJodHRwczovL2dpdGh1Yi5jb20vbnBtL2NsaUA5LjIuMCJ9LCJpbnZvY2F0aW9uIjp7ImNvbmZpZ1NvdXJjZSI6eyJ1cmkiOiJnaXQraHR0cHM6Ly9naXRodWIuY29tL3NpZ3N0b3JlL3NpZ3N0b3JlLWpzQHJlZnMvdGFncy92MC40LjAiLCJkaWdlc3QiOnsic2hhMSI6IjhhMmVlMmZkMjBkZGE1OGZmYTRhOGQ4MDhhNjVjYjFlMDQ3MTFjMDMifSwiZW50cnlQb2ludCI6InNpZ3N0b3JlL3NpZ3N0b3JlLWpzLy5naXRodWIvd29ya2Zsb3dzL3B1Ymxpc2gueW1sQHJlZnMvdGFncy92MC40LjAifSwicGFyYW1ldGVycyI6e30sImVudmlyb25tZW50Ijp7IkdJVEhVQl9BQ1RPUl9JRCI6IjM5ODAyNyIsIkdJVEhVQl9FVkVOVF9OQU1FIjoicmVsZWFzZSIsIkdJVEhVQl9KT0IiOiJwdWJsaXNoIiwiR0lUSFVCX1JFRiI6InJlZnMvdGFncy92MC40LjAiLCJHSVRIVUJfUkVGX1RZUEUiOiJ0YWciLCJHSVRIVUJfUkVQT1NJVE9SWSI6InNpZ3N0b3JlL3NpZ3N0b3JlLWpzIiwiR0lUSFVCX1JFUE9TSVRPUllfSUQiOiI0OTU1NzQ1NTUiLCJHSVRIVUJfUkVQT1NJVE9SWV9PV05FUl9JRCI6IjcxMDk2MzUzIiwiR0lUSFVCX1JVTl9BVFRFTVBUIjoiMSIsIkdJVEhVQl9SVU5fSUQiOiIzODk1MTk3NzI1IiwiR0lUSFVCX1JVTl9OVU1CRVIiOiI3IiwiR0lUSFVCX1NIQSI6IjhhMmVlMmZkMjBkZGE1OGZmYTRhOGQ4MDhhNjVjYjFlMDQ3MTFjMDMiLCJHSVRIVUJfV09SS0ZMT1ciOiJwdWJsaXNoIiwiR0lUSFVCX1dPUktGTE9XX1JFRiI6InNpZ3N0b3JlL3NpZ3N0b3JlLWpzLy5naXRodWIvd29ya2Zsb3dzL3B1Ymxpc2gueW1sQHJlZnMvdGFncy92MC40LjAiLCJHSVRIVUJfV09SS0ZMT1dfU0hBIjoiOGEyZWUyZmQyMGRkYTU4ZmZhNGE4ZDgwOGE2NWNiMWUwNDcxMWMwMyIsIklNQUdFX09TIjoidWJ1bnR1MjIiLCJJTUFHRV9WRVJTSU9OIjoiMjAyMjEyMTIuMSIsIlJVTk5FUl9BUkNIIjoiWDY0IiwiUlVOTkVSX05BTUUiOiJIb3N0ZWQgQWdlbnQiLCJSVU5ORVJfT1MiOiJMaW51eCJ9fSwibWV0YWRhdGEiOnsiYnVpbGRJbnZvY2F0aW9uSWQiOiIzODk1MTk3NzI1LTEiLCJjb21wbGV0ZW5lc3MiOnsicGFyYW1ldGVycyI6ZmFsc2UsImVudmlyb25tZW50IjpmYWxzZSwibWF0ZXJpYWxzIjpmYWxzZX0sInJlcHJvZHVjaWJsZSI6ZmFsc2V9LCJtYXRlcmlhbHMiOlt7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vc2lnc3RvcmUvc2lnc3RvcmUtanMiLCJkaWdlc3QiOnsic2hhMSI6IjhhMmVlMmZkMjBkZGE1OGZmYTRhOGQ4MDhhNjVjYjFlMDQ3MTFjMDMifX1dfX0=",
"payloadType": "application/vnd.in-toto+json",
"signatures": [
{
"sig": "MEQCIBk8ec2/Gm2vSIaYnW5YublLxLctqFWDkUVBhQHhYbkPAiBb1W0l/SyhDL8hRibad9C7f8jwwp9gRaKyaiXd3AH8oQ==",
"keyid": ""
}
]
}
}
},
{
"predicateType": "https://github.com/npm/attestation/tree/main/specs/publish/v0.1",
"bundle": {
"mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.1",
"verificationMaterial": {
"publicKey": {
"hint": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"
},
"tlogEntries": [
{
"logIndex": "10960848",
"logId": {
"keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="
},
"kindVersion": {
"kind": "intoto",
"version": "0.0.2"
},
"integratedTime": "1673458314",
"inclusionPromise": {
"signedEntryTimestamp": "MEQCIEEIjIhzK2F4a9yt9peEarFYCBQETNkLAvHh4Q+suCbvAiAMOAoaKdW/+cU07wHSiG//gSJTeFDB30dl0dSx9dRG4g=="
},
"inclusionProof": null,
"canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjIiLCJraW5kIjoiaW50b3RvIiwic3BlYyI6eyJjb250ZW50Ijp7ImVudmVsb3BlIjp7InBheWxvYWRUeXBlIjoiYXBwbGljYXRpb24vdm5kLmluLXRvdG8ranNvbiIsInNpZ25hdHVyZXMiOlt7ImtleWlkIjoiU0hBMjU2OmpsM2J3c3d1ODBQampva0NnaDBvMnc1YzJVNExoUUFFNTdnajljejFrekEiLCJwdWJsaWNLZXkiOiJMUzB0TFMxQ1JVZEpUaUJRVlVKTVNVTWdTMFZaTFMwdExTMEtUVVpyZDBWM1dVaExiMXBKZW1vd1EwRlJXVWxMYjFwSmVtb3dSRUZSWTBSUlowRkZNVTlzWWpONlRVRkdSbmhZUzBocFNXdFJUelZqU2pOWmFHdzFhVFpWVUhBclNXaDFkR1ZDU21KMVNHTkJOVlZ2WjB0dk1FVlhkR3hYZDFjMlMxTmhTMjlVVGtWWlREZEtiRU5SYVZadWEyaENhM1JWWjJjOVBRb3RMUzB0TFVWT1JDQlFWVUpNU1VNZ1MwVlpMUzB0TFMwPSIsInNpZyI6IlRVVlZRMGxSUXk4elpVdHVjRVpwY1dkMlZGbElORmxDUlhZMU5sQnlXa2NyV1ZGcE5VaGFXVlZMWVZCamFUVXlTRUZKWjFwMU16QkxjRk4zUWxWTGFWcENTemc0TjNOUlFVcEdRV1pyZUVKQmVXWklURUZNU2psR05sb3diREE5In1dfSwiaGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6IjE0MzQ3ZjQxMjYwMTRiOTE3NDNkNjU5ZGNmY2ZkNmZiNjU4YTBmOWYzZDMxMGM1MDdmNWUzNWM3MGYwMGRjZGQifSwicGF5bG9hZEhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI2NWE5MDU3MmQ3ZjUwODYyZDE4ZjdkYzljYjRlNTY2N2M4ZTMwYjZiN2VlZDk1MDVhYzMxZmE5NzIxOGMwYjA1In19fX0="
}
],
"timestampVerificationData": {
"rfc3161Timestamps": []
}
},
"dsseEnvelope": {
"payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInN1YmplY3QiOlt7Im5hbWUiOiJwa2c6bnBtL3NpZ3N0b3JlQDAuNC4wIiwiZGlnZXN0Ijp7InNoYTUxMiI6IjI4MmMwYzVmYTkzNmQyNjQzMjE2NDM1ODFiNjVkM2RlNWMwYWY2ZWQ0ZmRmYWMxMmY1ODUxMTE1ZGYzOWNjMjVjZmFmMGFkMjJkOTA4NDg3YmZlZjMwMTE0ZDYxYzI1NzQ2MjA2ZDE4MzRiZTRmOGZkMTY1OTE3OGY3N2NjMDA0In19XSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9ucG0vYXR0ZXN0YXRpb24vdHJlZS9tYWluL3NwZWNzL3B1Ymxpc2gvdjAuMSIsInByZWRpY2F0ZSI6eyJuYW1lIjoic2lnc3RvcmUiLCJ2ZXJzaW9uIjoiMC40LjAiLCJyZWdpc3RyeSI6Imh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnIn19",
"payloadType": "application/vnd.in-toto+json",
"signatures": [
{
"sig": "invalid-signature",
"keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"
}
]
}
}
}
]
}
Loading

0 comments on commit 2916b72

Please sign in to comment.