@@ -355,26 +355,100 @@ class OIDC::TrustedPublisher::GitHubActionTest < ActiveSupport::TestCase
355355 assert_equal "example/my-gem" , publisher . workflow_repository
356356 end
357357
358- test "#to_access_policy with reusable workflow" do
358+ test "#to_access_policy with reusable workflow uses reusable workflow refs " do
359359 publisher = create ( :oidc_trusted_publisher_github_action ,
360360 repository_owner : "caller-org" ,
361361 repository_name : "caller-repo" ,
362362 workflow_filename : "shared-release.yml" ,
363363 workflow_repository_owner : "shared-org" ,
364364 workflow_repository_name : "shared-workflows" )
365365
366- policy = publisher . to_access_policy ( { ref : "refs/heads/main" , sha : "abc123" } )
366+ # Caller ref/sha differ from the reusable workflow's ref/sha
367+ policy = publisher . to_access_policy (
368+ ref : "refs/heads/main" , sha : "caller-sha-111" ,
369+ job_workflow_ref : "shared-org/shared-workflows/.github/workflows/shared-release.yml@refs/tags/v1.0" ,
370+ job_workflow_sha : "reusable-sha-222"
371+ )
372+
373+ # Should create statements using the reusable workflow's ref and sha, NOT the caller's
374+ assert_equal 2 , policy . statements . length
367375
368- # Verify job_workflow_ref points to the shared workflow repo, not the caller repo
369- first_statement = policy . statements . first
370- job_workflow_ref_condition = first_statement . conditions . find { |c | c . claim == "job_workflow_ref" }
376+ first_condition = policy . statements . first . conditions . find { |c | c . claim == "job_workflow_ref" }
371377
372- assert_equal "shared-org/shared-workflows/.github/workflows/shared-release.yml@refs/heads/main" ,
373- job_workflow_ref_condition . value
378+ assert_equal "shared-org/shared-workflows/.github/workflows/shared-release.yml@refs/tags/v1.0" ,
379+ first_condition . value
380+
381+ second_condition = policy . statements . second . conditions . find { |c | c . claim == "job_workflow_ref" }
382+
383+ assert_equal "shared-org/shared-workflows/.github/workflows/shared-release.yml@reusable-sha-222" ,
384+ second_condition . value
374385
375386 # Verify repository condition still points to caller repo (security)
376- repository_condition = first_statement . conditions . find { |c | c . claim == "repository" }
387+ repository_condition = policy . statements . first . conditions . find { |c | c . claim == "repository" }
377388
378389 assert_equal "caller-org/caller-repo" , repository_condition . value
379390 end
391+
392+ test "#to_access_policy with reusable workflow without job_workflow_sha" do
393+ publisher = create ( :oidc_trusted_publisher_github_action ,
394+ repository_owner : "caller-org" ,
395+ repository_name : "caller-repo" ,
396+ workflow_filename : "shared-release.yml" ,
397+ workflow_repository_owner : "shared-org" ,
398+ workflow_repository_name : "shared-workflows" )
399+
400+ policy = publisher . to_access_policy (
401+ ref : "refs/heads/main" , sha : "caller-sha-111" ,
402+ job_workflow_ref : "shared-org/shared-workflows/.github/workflows/shared-release.yml@refs/tags/v1.0"
403+ )
404+
405+ assert_equal 1 , policy . statements . length
406+
407+ condition = policy . statements . first . conditions . find { |c | c . claim == "job_workflow_ref" }
408+
409+ assert_equal "shared-org/shared-workflows/.github/workflows/shared-release.yml@refs/tags/v1.0" ,
410+ condition . value
411+ end
412+
413+ test "#to_access_policy same-repo workflow uses caller ref and sha" do
414+ publisher = create ( :oidc_trusted_publisher_github_action ,
415+ repository_owner : "example" ,
416+ repository_name : "my-gem" ,
417+ workflow_filename : "release.yml" ,
418+ workflow_repository_owner : nil ,
419+ workflow_repository_name : nil )
420+
421+ policy = publisher . to_access_policy ( { ref : "refs/heads/main" , sha : "abc123" } )
422+
423+ assert_equal 2 , policy . statements . length
424+
425+ first_condition = policy . statements . first . conditions . find { |c | c . claim == "job_workflow_ref" }
426+
427+ assert_equal "example/my-gem/.github/workflows/release.yml@refs/heads/main" ,
428+ first_condition . value
429+
430+ second_condition = policy . statements . second . conditions . find { |c | c . claim == "job_workflow_ref" }
431+
432+ assert_equal "example/my-gem/.github/workflows/release.yml@abc123" ,
433+ second_condition . value
434+ end
435+
436+ test "#to_access_policy reusable workflow rejects mismatched prefix" do
437+ publisher = create ( :oidc_trusted_publisher_github_action ,
438+ repository_owner : "caller-org" ,
439+ repository_name : "caller-repo" ,
440+ workflow_filename : "shared-release.yml" ,
441+ workflow_repository_owner : "shared-org" ,
442+ workflow_repository_name : "shared-workflows" )
443+
444+ # job_workflow_ref has a different workflow repo than expected
445+ assert_raises ( OIDC ::AccessPolicy ::AccessError ) do
446+ publisher . to_access_policy (
447+ ref : "refs/heads/main" ,
448+ sha : "caller-sha" ,
449+ job_workflow_ref : "attacker-org/evil-workflows/.github/workflows/shared-release.yml@refs/heads/main" ,
450+ job_workflow_sha : "attacker-sha-123"
451+ )
452+ end
453+ end
380454end
0 commit comments