Skip to content

Commit f3dae5b

Browse files
committed
Merge remote-tracking branch 'origin/main' into jg-codex/issue-292-guarded-merge-seam
* origin/main: fix: allow YAML timestamps in action scanner (#305)
2 parents f42a1d5 + 96a6d1d commit f3dae5b

1 file changed

Lines changed: 37 additions & 4 deletions

File tree

bin/repository-security-policy-test.rb

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22
# frozen_string_literal: true
33

44
require "minitest/autorun"
5+
require "date"
56
require "fileutils"
67
require "tmpdir"
78
require "yaml"
89

910
class RepositorySecurityPolicyTest < Minitest::Test
1011
ROOT = File.expand_path("..", __dir__)
12+
YAML_TIMESTAMP_CLASSES = [Date, Time].freeze
1113

1214
def test_github_actions_are_pinned_to_full_commit_shas
1315
reference_sets = Dir.glob(File.join(ROOT, ".github/workflows/*.{yml,yaml}")).map do |path|
14-
workflow = YAML.safe_load_file(path, aliases: true)
15-
[path, workflow_uses(workflow)]
16+
[path, workflow_uses(load_yaml_file(path))]
1617
end
1718
reference_sets.concat(action_paths.map do |path|
18-
action = YAML.safe_load_file(path, aliases: true)
19-
[path, composite_uses(action)]
19+
[path, composite_uses(load_yaml_file(path))]
2020
end)
2121

2222
mutable_uses = reference_sets.flat_map do |path, references|
@@ -54,6 +54,35 @@ def test_action_reference_scanner_reads_composite_action_structure
5454
assert_equal [["runs.steps.0.uses", "owner/action@v1"]], composite_uses(action)
5555
end
5656

57+
def test_action_reference_scanner_accepts_timestamp_scalars_and_still_rejects_mutable_uses
58+
sha = "0123456789abcdef0123456789abcdef01234567"
59+
60+
Dir.mktmpdir("repository-security-policy") do |root|
61+
immutable_workflow = File.join(root, "immutable.yml")
62+
mutable_workflow = File.join(root, "mutable.yml")
63+
File.write(immutable_workflow, <<~YAML)
64+
generated_on: 2026-08-02
65+
jobs:
66+
validate:
67+
steps: [{ uses: owner/action@#{sha} }]
68+
YAML
69+
File.write(mutable_workflow, <<~YAML)
70+
generated_at: 2026-08-02T12:34:56Z
71+
jobs:
72+
validate:
73+
steps: [{ uses: owner/action@v1 }]
74+
YAML
75+
76+
immutable_references = workflow_uses(load_yaml_file(immutable_workflow))
77+
mutable_references = workflow_uses(load_yaml_file(mutable_workflow))
78+
79+
assert_equal [["jobs.validate.steps.0.uses", "owner/action@#{sha}"]], immutable_references
80+
assert acceptable_action_reference?(immutable_references.first.last)
81+
assert_equal [["jobs.validate.steps.0.uses", "owner/action@v1"]], mutable_references
82+
refute acceptable_action_reference?(mutable_references.first.last)
83+
end
84+
end
85+
5786
def test_action_scanner_keeps_nested_temp_named_directories
5887
Dir.mktmpdir("repository-security-policy") do |root|
5988
nested_action = File.join(root, "skills/example/tmp/action.yml")
@@ -110,6 +139,10 @@ def test_dependabot_proposes_pinned_action_updates_for_review
110139

111140
private
112141

142+
def load_yaml_file(path)
143+
YAML.safe_load_file(path, permitted_classes: YAML_TIMESTAMP_CLASSES, aliases: true)
144+
end
145+
113146
def action_paths(root = ROOT)
114147
Dir.glob(File.join(root, "**/action.{yml,yaml}"), File::FNM_DOTMATCH).reject do |path|
115148
first_part = path.delete_prefix("#{root}/").split("/", 2).first

0 commit comments

Comments
 (0)