@@ -23,11 +23,12 @@ assert.match(workflow, /output_projections:/)
2323assert . match ( workflow , / v e r i f i c a t i o n _ c o m m a n d s : / )
2424assert . match ( workflow , / d r i f t _ c h e c k s : / )
2525assert . match ( workflow , / a c c e s s _ t o k e n _ r e p o s : / )
26- assert . match ( workflow , / r e q u i r e _ a c c e s s _ t o k e n : / )
26+ assert . doesNotMatch ( publicWorkflowSurface , / r e q u i r e _ a c c e s s _ t o k e n : / )
2727assert . match ( workflow , / p r o j e c t e d _ o u t p u t s _ j s o n : / )
2828assert . match ( workflow , / A C C E S S _ T O K E N : / )
2929assert . match ( workflow , / G I T H U B _ T O K E N : \$ \{ \{ s e c r e t s \. A C C E S S _ T O K E N \| \| g i t h u b \. t o k e n \} \} / )
30- assert . match ( workflow , / A C C E S S _ T O K E N _ C O N F I G U R E D : \$ \{ \{ s e c r e t s \. A C C E S S _ T O K E N ! = ' ' \} \} / )
30+ assert . match ( workflow , / C A L L E R _ R E P O : \$ \{ \{ g i t h u b \. r e p o s i t o r y \} \} / )
31+ assert . match ( workflow , / E X P L I C I T _ A C C E S S _ T O K E N _ C O N F I G U R E D : \$ \{ \{ s e c r e t s \. A C C E S S _ T O K E N ! = ' ' \} \} / )
3132assert . doesNotMatch ( workflow , / h o m e b o y | r e q u i r e _ a p p _ t o k e n | r e q u i r e _ h o m e b o y _ a p p _ t o k e n | R E Q U I R E _ H O M E B O Y _ A P P _ T O K E N | E x t r a - C h i l l \/ h o m e b o y - a c t i o n | a g e n t - t a s k r u n - p l a n / i)
3233assert . doesNotMatch ( workflow , / d o c s - a g e n t | w p - c o d e b o x \/ d o c s - a g e n t - r u n n e r - r e c i p e \/ v 1 | r e c i p e _ p a t h | r e c i p e _ j s o n | w p _ c o d e b o x _ r e f / i)
3334assert . doesNotMatch ( workflow , / d a t a m a c h i n e - a g e n t - c i | r u n t i m e - a g e n t - f u l l - r u n | E x t r a - C h i l l \/ h o m e b o y - e x t e n s i o n s / )
@@ -50,8 +51,8 @@ assert.doesNotMatch(workflow, new RegExp(foreignCallerSha))
5051assert . match ( workflow , / V a l i d a t e p i n n e d W P C o d e b o x h e l p e r r e v i s i o n / )
5152
5253const requiredHelperFiles = {
53- ".github/scripts/run-agent-task/build-codebox-task-request.mjs" : "a0b9052bf63b0d5b096568c21a1e7333b7474b35834ffd1bc0d748fb0cfd0859 " ,
54- ".github/scripts/run-agent-task/execute-native-agent-task.mjs" : "b67910e538c6fb231c25dee43d0ff2e06e521e08108f8570e0389b022f9f8ccc " ,
54+ ".github/scripts/run-agent-task/build-codebox-task-request.mjs" : "ed1fbc144428bfbf222810a8a467390e8cd5b45daa0f3e64e03162949d6c84df " ,
55+ ".github/scripts/run-agent-task/execute-native-agent-task.mjs" : "324c6d12dd01880bc9e4cd880ea6c713cb1bfd630b4925c53d78af7283e4a459 " ,
5556 ".github/scripts/run-agent-task/prepare-agent-task-upload.mjs" : "93511e4174e705f55ff014ba68ac52fdaca771ce3f19f3921cceb661e69569da" ,
5657}
5758for ( const [ path , digest ] of Object . entries ( requiredHelperFiles ) ) {
@@ -70,7 +71,8 @@ assert.match(docs, /Automattic\/wp-codebox\/.github\/workflows\/run-agent-task.y
7071assert . match ( docs , / e x t e r n a l _ p a c k a g e _ s o u r c e / )
7172assert . match ( docs , / r u n n e r _ w o r k s p a c e / )
7273assert . match ( docs , / a c c e s s _ t o k e n _ r e p o s / )
73- assert . match ( docs , / r e q u i r e _ a c c e s s _ t o k e n / )
74+ assert . match ( docs , / b u i l t - i n ` g i t h u b \. t o k e n ` a s ` G I T H U B _ T O K E N ` / )
75+ assert . match ( docs , / t a r g e t i n a n o t h e r \n r e p o s i t o r y , ` A C C E S S _ T O K E N ` i s r e q u i r e d e x p l i c i t l y / )
7476assert . match ( docs , / s u c c e s s _ r e q u i r e s _ p r / )
7577assert . match ( docs , / i n t e n t i o n a l e x p o s e d - w o r k f l o w b r e a k i n g c h a n g e / )
7678assert . match ( docs , / w p - c o d e b o x \/ r e u s a b l e - w o r k f l o w - i n t e r f a c e \/ v 1 / )
@@ -110,6 +112,7 @@ await execFileAsync("node", [new URL("../.github/scripts/run-agent-task/build-co
110112 WORKLOAD_LABEL : "Run example maintenance" ,
111113 COMPONENT_ID : "example-ci-driver" ,
112114 TARGET_REPO : "Automattic/example-target" ,
115+ CALLER_REPO : "Automattic/example-target" ,
113116 PROMPT : "Update the configured surface." ,
114117 WRITABLE_PATHS : "README.md,docs/**" ,
115118 PROVIDER : "openai" ,
@@ -120,7 +123,6 @@ await execFileAsync("node", [new URL("../.github/scripts/run-agent-task/build-co
120123 DRIFT_CHECKS : "[]" ,
121124 SUCCESS_REQUIRES_PR : "false" ,
122125 ACCESS_TOKEN_REPOS : "Automattic/example-target" ,
123- REQUIRE_ACCESS_TOKEN : "false" ,
124126 ALLOWED_REPOS : '["Automattic/example-target"]' ,
125127 MAX_TURNS : "12" ,
126128 TIME_BUDGET_MS : "600000" ,
@@ -152,6 +154,7 @@ await execFileAsync("node", [new URL("../.github/scripts/run-agent-task/execute-
152154 AGENT_TASK_REQUEST_PATH : requestPath ,
153155 AGENT_TASK_WORKSPACE : tmp ,
154156 WP_CODEBOX_WORKFLOW_ROOT : new URL ( ".." , import . meta. url ) . pathname ,
157+ GITHUB_TOKEN : "test-caller-token" ,
155158 EXTERNAL_PACKAGE_SOURCE_POLICY : '{"version":1,"repositories":{"automattic/example-agent-packages":["packages/example-agent.agent.json"]}}' ,
156159 } ,
157160} )
@@ -164,6 +167,55 @@ assert.equal(result.runtime_input_path, ".codebox/native-agent-task-input.json")
164167assert . deepEqual ( result . verification , [ ] )
165168assert . doesNotMatch ( JSON . stringify ( result ) , / h o m e b o y | a g e n t - t a s k - p l a n | r u n - p l a n / i)
166169
170+ const executeNativeAgentTask = new URL ( "../.github/scripts/run-agent-task/execute-native-agent-task.mjs" , import . meta. url ) . pathname
171+ const executeAccessCase = async ( candidate : Record < string , unknown > , environment : Record < string , string > ) => {
172+ await writeFile ( requestPath , `${ JSON . stringify ( candidate , null , 2 ) } \n` )
173+ return execFileAsync ( "node" , [ executeNativeAgentTask ] , {
174+ cwd : tmp ,
175+ env : {
176+ ...process . env ,
177+ GITHUB_OUTPUT : outputPath ,
178+ AGENT_TASK_REQUEST_PATH : requestPath ,
179+ AGENT_TASK_WORKSPACE : tmp ,
180+ WP_CODEBOX_WORKFLOW_ROOT : new URL ( ".." , import . meta. url ) . pathname ,
181+ EXTERNAL_PACKAGE_SOURCE_POLICY : '{"version":1,"repositories":{"automattic/example-agent-packages":["packages/example-agent.agent.json"]}}' ,
182+ ...environment ,
183+ } ,
184+ } )
185+ }
186+
187+ // Hosted run 29293335972 supplied github.token with write permissions but no
188+ // named ACCESS_TOKEN. This is the exact same-repository environment.
189+ const callerToken = "caller-token-from-run-29293335972"
190+ await executeAccessCase ( request , { GITHUB_TOKEN : callerToken , EXPLICIT_ACCESS_TOKEN_CONFIGURED : "false" } )
191+ const sameRepositoryResult = JSON . parse ( await readFile ( resultPath , "utf8" ) )
192+ assert . equal ( sameRepositoryResult . access . authorized , true )
193+ assert . doesNotMatch ( JSON . stringify ( sameRepositoryResult ) , new RegExp ( callerToken ) )
194+
195+ await assert . rejects (
196+ executeAccessCase ( request , { GITHUB_TOKEN : "" , EXPLICIT_ACCESS_TOKEN_CONFIGURED : "false" } ) ,
197+ )
198+ assert . match ( JSON . parse ( await readFile ( resultPath , "utf8" ) ) . access . error , / N o e f f e c t i v e G i t H u b t o k e n / )
199+
200+ const crossRepositoryRequest = {
201+ ...request ,
202+ target_repo : "automattic/another-target" ,
203+ access : { ...request . access , allowed_repos : [ "automattic/another-target" ] , access_token_repos : [ "automattic/another-target" ] } ,
204+ }
205+ await assert . rejects (
206+ executeAccessCase ( crossRepositoryRequest , { GITHUB_TOKEN : callerToken , EXPLICIT_ACCESS_TOKEN_CONFIGURED : "false" } ) ,
207+ )
208+ assert . match ( JSON . parse ( await readFile ( resultPath , "utf8" ) ) . access . error , / e x p l i c i t A C C E S S _ T O K E N i s r e q u i r e d f o r c r o s s - r e p o s i t o r y p u b l i c a t i o n / )
209+
210+ const targetMismatchRequest = {
211+ ...request ,
212+ target_repo : "automattic/another-target" ,
213+ }
214+ await assert . rejects (
215+ executeAccessCase ( targetMismatchRequest , { GITHUB_TOKEN : callerToken , EXPLICIT_ACCESS_TOKEN_CONFIGURED : "true" } ) ,
216+ )
217+ assert . match ( JSON . parse ( await readFile ( resultPath , "utf8" ) ) . access . error , / T a r g e t r e p o s i t o r y i s n o t e x p l i c i t l y a u t h o r i z e d / )
218+
167219const malformedRequest = { ...request , verification_commands : [ { description : "Missing command" } ] }
168220await writeFile ( requestPath , `${ JSON . stringify ( malformedRequest , null , 2 ) } \n` )
169221await assert . rejects ( execFileAsync ( "node" , [ new URL ( "../.github/scripts/run-agent-task/execute-native-agent-task.mjs" , import . meta. url ) . pathname ] , {
@@ -174,6 +226,7 @@ await assert.rejects(execFileAsync("node", [new URL("../.github/scripts/run-agen
174226 AGENT_TASK_REQUEST_PATH : requestPath ,
175227 AGENT_TASK_WORKSPACE : tmp ,
176228 WP_CODEBOX_WORKFLOW_ROOT : new URL ( ".." , import . meta. url ) . pathname ,
229+ GITHUB_TOKEN : "test-caller-token" ,
177230 EXTERNAL_PACKAGE_SOURCE_POLICY : '{"version":1,"repositories":{"automattic/example-agent-packages":["packages/example-agent.agent.json"]}}' ,
178231 } ,
179232} ) , / v e r i f i c a t i o n _ c o m m a n d s \[ 0 \] \. c o m m a n d / )
@@ -187,15 +240,16 @@ await execFileAsync("npm", ["run", "test:php-runner-workspace-tools"], { cwd: ne
187240
188241const outputs = await readFile ( outputPath , "utf8" )
189242assert . match ( outputs , / j o b _ s t a t u s < < _ _ W P _ C O D E B O X _ O U T P U T _ _ \n s k i p p e d \n _ _ W P _ C O D E B O X _ O U T P U T _ _ / )
190- assert . match ( outputs , / c r e d e n t i a l _ m o d e < < _ _ W P _ C O D E B O X _ O U T P U T _ _ \n r u n n e r - ( p r o v i d e r | d e f a u l t ) - c r e d e n t i a l s \n _ _ W P _ C O D E B O X _ O U T P U T _ _ / )
243+ assert . match ( outputs , / c r e d e n t i a l _ m o d e < < _ _ W P _ C O D E B O X _ O U T P U T _ _ \n r u n n e r - a c c e s s - t o k e n \n _ _ W P _ C O D E B O X _ O U T P U T _ _ / )
244+ assert . doesNotMatch ( outputs , / c a l l e r - t o k e n - f r o m - r u n - 2 9 2 9 3 3 3 5 9 7 2 / )
191245assert . match ( outputs , / r e q u e s t _ p a t h < < _ _ W P _ C O D E B O X _ O U T P U T _ _ \n \. c o d e b o x \/ a g e n t - t a s k - r e q u e s t \. j s o n \n _ _ W P _ C O D E B O X _ O U T P U T _ _ / )
192246assert . match ( outputs , / r e s u l t _ p a t h < < _ _ W P _ C O D E B O X _ O U T P U T _ _ \n \. c o d e b o x \/ a g e n t - t a s k - w o r k f l o w - r e s u l t \. j s o n \n _ _ W P _ C O D E B O X _ O U T P U T _ _ / )
193247
194248// Uploads come only from a fail-closed staging directory. Policy data remains
195249// secret even though public package bytes may be present in runtime input.
196250const artifactsPath = join ( tmp , ".codebox" , "agent-task-artifacts" )
197251await mkdir ( artifactsPath , { recursive : true } )
198- await writeFile ( join ( artifactsPath , "safe.txt" ) , "secret-agent-value" )
252+ await writeFile ( join ( artifactsPath , "safe.txt" ) , "secret-agent-value secret-github-value " )
199253await writeFile ( join ( artifactsPath , "oversize.txt" ) , `secret-agent-value${ "x" . repeat ( 4 * 1024 * 1024 ) } ` )
200254await writeFile ( join ( artifactsPath , "binary.bin" ) , Buffer . from ( [ 0 , ...Buffer . from ( "secret-agent-value" ) ] ) )
201255const outsideArtifact = join ( tmp , "outside-secret.txt" )
@@ -208,6 +262,7 @@ await execFileAsync("node", [new URL("../.github/scripts/run-agent-task/prepare-
208262} )
209263const uploadArtifactsPath = join ( tmp , ".codebox" , "agent-task-upload" , ".codebox" , "agent-task-artifacts" )
210264assert . match ( await readFile ( join ( uploadArtifactsPath , "safe.txt" ) , "utf8" ) , / \[ R E D A C T E D \] / )
265+ assert . doesNotMatch ( await readFile ( join ( uploadArtifactsPath , "safe.txt" ) , "utf8" ) , / s e c r e t - g i t h u b - v a l u e / )
211266assert . doesNotMatch ( await readFile ( join ( tmp , ".codebox" , "agent-task-upload" , ".codebox" , "agent-task-request.json" ) , "utf8" ) , / s e c r e t - a g e n t - v a l u e | s e c r e t - g i t h u b - v a l u e | \{ " p r i v a t e " : " p o l i c y " \} / )
212267for ( const name of [ "oversize.txt" , "binary.bin" , "linked-secret.txt" ] ) {
213268 await assert . rejects ( readFile ( join ( uploadArtifactsPath , name ) , "utf8" ) , / E N O E N T / )
0 commit comments