@@ -9,6 +9,13 @@ const CI_WORKFLOW_URL = new URL("ci.yml", WORKFLOWS_URL);
99const COVERAGE_WORKFLOW_URL = new URL ( "coverage.yml" , WORKFLOWS_URL ) ;
1010const RELEASE_WORKFLOW_URL = new URL ( "release.yml" , WORKFLOWS_URL ) ;
1111const FALLOW_CONFIG_URL = new URL ( ".fallowrc.json" , ROOT_URL ) ;
12+ const WASM_PACK_INSTALL_ACTION = "taiki-e/install-action@15449e3094499af05d8d964a1c884208e4b8b595" ;
13+ const WASM_PACK_WORKFLOWS = new Map ( [
14+ [ "bench.yml" , " if: matrix.kind == 'node'\n" ] ,
15+ [ "ci.yml" , "" ] ,
16+ [ "coverage.yml" , "" ] ,
17+ [ "release.yml" , "" ] ,
18+ ] ) ;
1219
1320const trackedPackageLocks = async ( ) => {
1421 const tracked = execFileSync ( "git" , [ "ls-files" , "--" , ":(glob)**/package-lock.json" ] , {
@@ -104,6 +111,52 @@ describe("Checkout credential policy", () => {
104111 }
105112 }
106113 } ) ;
114+
115+ it ( "uses a step-scoped token and explicit authenticated remote for badge pushes" , async ( ) => {
116+ const workflow = await readFile ( COVERAGE_WORKFLOW_URL , "utf8" ) ;
117+ const job = workflowJob ( workflow , "coverage" ) ;
118+ const badgeStep = job . slice ( job . indexOf ( " - name: Update coverage badges" ) ) ;
119+
120+ assert . match ( badgeStep , / ^ e n v : \n G H _ T O K E N : \$ \{ \{ g i t h u b \. t o k e n \} \} $ / m) ;
121+ assert . doesNotMatch ( job , / ^ e n v : \n (?: .* \n ) * G H _ T O K E N : / m) ;
122+ assert . doesNotMatch ( badgeStep , / g i t p u s h o r i g i n b a d g e s / ) ;
123+ const authenticatedPushes = badgeStep . match (
124+ / g i t p u s h " h t t p s : \/ \/ x - a c c e s s - t o k e n : \$ \{ G H _ T O K E N \} @ g i t h u b \. c o m \/ \$ \{ G I T H U B _ R E P O S I T O R Y \} \. g i t " b a d g e s / g,
125+ ) ;
126+ assert . equal ( authenticatedPushes ?. length , 2 ) ;
127+ } ) ;
128+ } ) ;
129+
130+ describe ( "Pinned wasm-pack installation policy" , ( ) => {
131+ it ( "uses only the pinned install action for wasm-pack in every workflow" , async ( ) => {
132+ for ( const entry of await workflowFiles ( ) ) {
133+ const workflow = await readFile ( new URL ( entry . name , WORKFLOWS_URL ) , "utf8" ) ;
134+
135+ assert . doesNotMatch ( workflow , / r u s t w a s m \. g i t h u b \. i o \/ w a s m - p a c k / , entry . name ) ;
136+ assert . doesNotMatch ( workflow , / c u r l [ ^ \n | ] * \| \s * s h / , entry . name ) ;
137+
138+ const condition = WASM_PACK_WORKFLOWS . get ( entry . name ) ;
139+ if ( condition !== undefined ) {
140+ const install = [
141+ " - name: Install wasm-pack" ,
142+ condition . trimEnd ( ) ,
143+ ` uses: ${ WASM_PACK_INSTALL_ACTION } # v2.81.11` ,
144+ " with:" ,
145+ " tool: wasm-pack@0.13.1" ,
146+ ]
147+ . filter ( Boolean )
148+ . join ( "\n" ) ;
149+ assert . ok ( workflow . includes ( install ) , `${ entry . name } : missing pinned wasm-pack installer` ) ;
150+ }
151+
152+ if ( / \b w a s m - p a c k (?: b u i l d | t e s t ) \b / . test ( workflow ) ) {
153+ assert . ok (
154+ WASM_PACK_WORKFLOWS . has ( entry . name ) ,
155+ `${ entry . name } : wasm-pack use is missing from the pinned installer policy` ,
156+ ) ;
157+ }
158+ }
159+ } ) ;
107160} ) ;
108161
109162describe ( "Rust feature coverage" , ( ) => {
@@ -145,6 +198,17 @@ describe("Release supply-chain policy", () => {
145198 assert . doesNotMatch ( workflow , / \b n p m i n s t a l l \b / ) ;
146199 } ) ;
147200
201+ it ( "requires provenance for every npm publish attempt" , async ( ) => {
202+ const workflow = await readFile ( RELEASE_WORKFLOW_URL , "utf8" ) ;
203+ const publishes = workflow . split ( "\n" ) . filter ( ( line ) => / \b n p m p u b l i s h \b / . test ( line ) ) ;
204+
205+ assert . ok ( publishes . length > 0 , "release workflow must publish npm packages" ) ;
206+ for ( const publish of publishes ) {
207+ assert . match ( publish , / - - p r o v e n a n c e \b / , publish . trim ( ) ) ;
208+ }
209+ assert . doesNotMatch ( workflow , / r e t r y i n g w i t h o u t p r o v e n a n c e / i) ;
210+ } ) ;
211+
148212 it ( "uses ordered frozen tooling for both NAPI package builds" , async ( ) => {
149213 const workflow = await readFile ( RELEASE_WORKFLOW_URL , "utf8" ) ;
150214 const buildJob = workflowJob ( workflow , "build-napi" ) ;
0 commit comments