1616
1717import { beforeAll , describe , expect , it , test } from 'vitest' ;
1818import fs from 'fs' ;
19+ import os from 'os' ;
1920import * as path from 'path' ;
2021
2122import { Buildx } from '../../src/buildx/buildx.js' ;
2223import { Build } from '../../src/buildx/build.js' ;
24+ import { Cosign } from '../../src/cosign/cosign.js' ;
2325import { Install as CosignInstall } from '../../src/cosign/install.js' ;
2426import { Docker } from '../../src/docker/docker.js' ;
2527import { Exec } from '../../src/exec.js' ;
@@ -33,73 +35,106 @@ const runTest = process.env.GITHUB_ACTIONS && process.env.GITHUB_ACTIONS === 'tr
3335const maybe = runTest ? describe : describe . skip ;
3436const maybeIdToken = runTest && process . env . ACTIONS_ID_TOKEN_REQUEST_URL ? describe : describe . skip ;
3537
36- beforeAll ( async ( ) => {
37- const cosignInstall = new CosignInstall ( ) ;
38- const cosignBinPath = await cosignInstall . download ( {
39- version : 'v3.0.6'
38+ const imageName = 'ghcr.io/docker/actions-toolkit/test' ;
39+ const currentCosignVersion = 'v3.0.6' ;
40+ const signAttestationCosignVersions = [ 'v3.0.2' , currentCosignVersion ] as const ;
41+ const installedCosign = new Map < string , Promise < string > > ( ) ;
42+
43+ async function installCosign ( version : string ) : Promise < string > {
44+ let installedPath = installedCosign . get ( version ) ;
45+ if ( ! installedPath ) {
46+ installedPath = ( async ( ) => {
47+ const cosignInstall = new CosignInstall ( ) ;
48+ const cosignBinPath = await cosignInstall . download ( {
49+ version
50+ } ) ;
51+ const installDir = fs . mkdtempSync ( path . join ( process . env . RUNNER_TEMP || os . tmpdir ( ) , `sigstore-cosign-${ version . replace ( / [ ^ a - z A - Z 0 - 9 ] + / g, '-' ) } -` ) ) ;
52+ return await cosignInstall . install ( cosignBinPath , installDir ) ;
53+ } ) ( ) ;
54+ installedCosign . set ( version , installedPath ) ;
55+ }
56+ return await installedPath ;
57+ }
58+
59+ for ( const cosignVersion of signAttestationCosignVersions ) {
60+ maybeIdToken ( `signAttestationManifests with cosign ${ cosignVersion } ` , ( ) => {
61+ let sigstore : Sigstore ;
62+
63+ beforeAll ( async ( ) => {
64+ sigstore = new Sigstore ( {
65+ cosign : new Cosign ( {
66+ binPath : await installCosign ( cosignVersion )
67+ } )
68+ } ) ;
69+ } , 100000 ) ;
70+
71+ it ( 'build, sign and verify' , async ( ) => {
72+ const buildx = new Buildx ( ) ;
73+ const build = new Build ( { buildx : buildx } ) ;
74+ const versionTag = cosignVersion . replace ( / ^ v / , '' ) . replace ( / \. / g, '-' ) ;
75+
76+ await expect (
77+ ( async ( ) => {
78+ await Docker . getExecOutput ( [ 'login' , '--password-stdin' , '--username' , process . env . GITHUB_REPOSITORY_OWNER || 'docker' , 'ghcr.io' ] , {
79+ input : Buffer . from ( process . env . GITHUB_TOKEN || '' )
80+ } ) ;
81+ } ) ( )
82+ ) . resolves . not . toThrow ( ) ;
83+
84+ await expect (
85+ ( async ( ) => {
86+ // prettier-ignore
87+ const buildCmd = await buildx . getCommand ( [
88+ '--builder' , process . env . CTN_BUILDER_NAME ?? 'default' ,
89+ 'build' ,
90+ '-f' , path . join ( fixturesDir , 'hello.Dockerfile' ) ,
91+ '--provenance=mode=max' ,
92+ '--tag' , `${ imageName } :sigstore-itg-cosign-${ versionTag } ` ,
93+ '--platform' , 'linux/amd64,linux/arm64' ,
94+ '--push' ,
95+ '--metadata-file' , build . getMetadataFilePath ( ) ,
96+ fixturesDir
97+ ] ) ;
98+ await Exec . exec ( buildCmd . command , buildCmd . args ) ;
99+ } ) ( )
100+ ) . resolves . not . toThrow ( ) ;
101+
102+ const metadata = build . resolveMetadata ( ) ;
103+ expect ( metadata ) . toBeDefined ( ) ;
104+ const buildDigest = build . resolveDigest ( metadata ) ;
105+ expect ( buildDigest ) . toBeDefined ( ) ;
106+
107+ const signResults = await sigstore . signAttestationManifests ( {
108+ imageNames : [ imageName ] ,
109+ imageDigest : buildDigest !
110+ } ) ;
111+ expect ( Object . keys ( signResults ) . length ) . toEqual ( 2 ) ;
112+
113+ const verifyResults = await sigstore . verifySignedManifests ( signResults , {
114+ certificateIdentityRegexp : `^https://github.com/docker/actions-toolkit/.github/workflows/test.yml.*$`
115+ } ) ;
116+ expect ( Object . keys ( verifyResults ) . length ) . toEqual ( 2 ) ;
117+ } , 200000 ) ;
40118 } ) ;
41- await cosignInstall . install ( cosignBinPath ) ;
42- } , 100000 ) ;
43-
44- maybeIdToken ( 'signAttestationManifests' , ( ) => {
45- it ( 'build, sign and verify' , async ( ) => {
46- const buildx = new Buildx ( ) ;
47- const build = new Build ( { buildx : buildx } ) ;
48- const imageName = 'ghcr.io/docker/actions-toolkit/test' ;
49-
50- await expect (
51- ( async ( ) => {
52- await Docker . getExecOutput ( [ 'login' , '--password-stdin' , '--username' , process . env . GITHUB_REPOSITORY_OWNER || 'docker' , 'ghcr.io' ] , {
53- input : Buffer . from ( process . env . GITHUB_TOKEN || '' )
54- } ) ;
55- } ) ( )
56- ) . resolves . not . toThrow ( ) ;
57-
58- await expect (
59- ( async ( ) => {
60- // prettier-ignore
61- const buildCmd = await buildx . getCommand ( [
62- '--builder' , process . env . CTN_BUILDER_NAME ?? 'default' ,
63- 'build' ,
64- '-f' , path . join ( fixturesDir , 'hello.Dockerfile' ) ,
65- '--provenance=mode=max' ,
66- '--tag' , `${ imageName } :sigstore-itg` ,
67- '--platform' , 'linux/amd64,linux/arm64' ,
68- '--push' ,
69- '--metadata-file' , build . getMetadataFilePath ( ) ,
70- fixturesDir
71- ] ) ;
72- await Exec . exec ( buildCmd . command , buildCmd . args ) ;
73- } ) ( )
74- ) . resolves . not . toThrow ( ) ;
75-
76- const metadata = build . resolveMetadata ( ) ;
77- expect ( metadata ) . toBeDefined ( ) ;
78- const buildDigest = build . resolveDigest ( metadata ) ;
79- expect ( buildDigest ) . toBeDefined ( ) ;
119+ }
80120
81- const sigstore = new Sigstore ( ) ;
82- const signResults = await sigstore . signAttestationManifests ( {
83- imageNames : [ imageName ] ,
84- imageDigest : buildDigest !
85- } ) ;
86- expect ( Object . keys ( signResults ) . length ) . toEqual ( 2 ) ;
121+ maybe ( 'verifyImageAttestations' , ( ) => {
122+ let sigstore : Sigstore ;
87123
88- const verifyResults = await sigstore . verifySignedManifests ( signResults , {
89- certificateIdentityRegexp : `^https://github.com/docker/actions-toolkit/.github/workflows/test.yml.*$`
124+ beforeAll ( async ( ) => {
125+ sigstore = new Sigstore ( {
126+ cosign : new Cosign ( {
127+ binPath : await installCosign ( currentCosignVersion )
128+ } )
90129 } ) ;
91- expect ( Object . keys ( verifyResults ) . length ) . toEqual ( 2 ) ;
92130 } , 100000 ) ;
93- } ) ;
94131
95- maybe ( 'verifyImageAttestations' , ( ) => {
96132 test . each ( [
97133 [ 'moby/buildkit:master@sha256:84014da3581b2ff2c14cb4f60029cf9caa272b79e58f2e89c651ea6966d7a505' , `^https://github.com/docker/github-builder-experimental/.github/workflows/bake.yml.*$` ] ,
98134 [ 'docker/dockerfile-upstream:master@sha256:3e8cd5ebf48acd1a1939649ad1c62ca44c029852b22493c16a9307b654334958' , `^https://github.com/docker/github-builder-experimental/.github/workflows/bake.yml.*$` ]
99135 ] ) (
100136 'given %p' ,
101137 async ( image , certificateIdentityRegexp ) => {
102- const sigstore = new Sigstore ( ) ;
103138 const verifyResults = await sigstore . verifyImageAttestations ( image , {
104139 certificateIdentityRegexp : certificateIdentityRegexp
105140 } ) ;
@@ -114,7 +149,6 @@ maybe('verifyImageAttestations', () => {
114149 ) ;
115150
116151 it ( 'default platform' , async ( ) => {
117- const sigstore = new Sigstore ( ) ;
118152 const verifyResults = await sigstore . verifyImageAttestations ( 'moby/buildkit:master@sha256:84014da3581b2ff2c14cb4f60029cf9caa272b79e58f2e89c651ea6966d7a505' , {
119153 certificateIdentityRegexp : `^https://github.com/docker/github-builder-experimental/.github/workflows/bake.yml.*$` ,
120154 platform : OCI . defaultPlatform ( )
@@ -161,8 +195,17 @@ maybeIdToken('signProvenanceBlobs', () => {
161195} ) ;
162196
163197maybeIdToken ( 'verifySignedArtifacts' , ( ) => {
198+ let sigstore : Sigstore ;
199+
200+ beforeAll ( async ( ) => {
201+ sigstore = new Sigstore ( {
202+ cosign : new Cosign ( {
203+ binPath : await installCosign ( currentCosignVersion )
204+ } )
205+ } ) ;
206+ } , 100000 ) ;
207+
164208 it ( 'sign and verify' , async ( ) => {
165- const sigstore = new Sigstore ( ) ;
166209 const signResults = await sigstore . signProvenanceBlobs ( {
167210 localExportDir : path . join ( fixturesDir , 'sigstore' , 'multi' )
168211 } ) ;
0 commit comments