Skip to content

Commit 04752f5

Browse files
authored
Merge pull request #8 from github/immutable-actions
Immutable actions support
2 parents 9f26e97 + d08a61a commit 04752f5

File tree

5 files changed

+138
-10
lines changed

5 files changed

+138
-10
lines changed

audit_workflow_runs.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ async function createActionsRunResults(owner, repo, run, actions) {
109109
name: action[0],
110110
version: action[1],
111111
sha: action[2],
112+
immutable_version: action[3],
113+
digest: action[4],
112114
});
113115
}
114116
return action_run_results;
@@ -280,7 +282,7 @@ async function main() {
280282
? auditEnterpriseOrOrg(orgOrEntName, orgOrEnt, startDate, endDate)
281283
: auditRepo(orgOrEntName, startDate, endDate);
282284

283-
console.log("org,repo,workflow,run_id,created_at,name,version,sha");
285+
console.log("org,repo,workflow,run_id,created_at,name,version,sha,immutable_version,digest");
284286

285287
const checkActions = Object.keys(actionsToAudit).length > 0;
286288

audit_workflow_runs.test.js

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ function testSearchForActionsLines() {
8686
2025-03-28T12:00:02Z Some other log line
8787
`;
8888
const expected1 = [
89-
["actions/checkout", "v4", "11bd71901bbe5b1630ceea73d27597364c9af683"],
90-
["actions/setup-node", "v3", "22cd71901bbe5b1630ceea73d27597364c9af684"],
89+
["actions/checkout", "v4", "11bd71901bbe5b1630ceea73d27597364c9af683", null, null],
90+
["actions/setup-node", "v3", "22cd71901bbe5b1630ceea73d27597364c9af684", null, null],
9191
];
9292
assert.deepStrictEqual(
9393
searchForActionsLines(logContent1),
@@ -112,7 +112,7 @@ function testSearchForActionsLines() {
112112
2025-03-28T12:00:02Z Download action repository 'actions/setup-node@v3' (SHA:22cd71901bbe5b1630ceea73d27597364c9af684)
113113
`;
114114
const expected3 = [
115-
["actions/checkout", "v4", "11bd71901bbe5b1630ceea73d27597364c9af683"],
115+
["actions/checkout", "v4", "11bd71901bbe5b1630ceea73d27597364c9af683", null, null],
116116
];
117117
assert.deepStrictEqual(
118118
searchForActionsLines(logContent3),
@@ -133,12 +133,88 @@ function testSearchForActionsLines() {
133133
const logContent5 = `2025-03-28T12:00:00Z Download action repository 'actions/checkout@v4' (SHA:invalid_sha)
134134
2025-03-28T12:00:01Z Malformed log line
135135
`;
136-
const expected5 = [["actions/checkout", "v4", "invalid_sha"]];
136+
const expected5 = [["actions/checkout", "v4", "invalid_sha", null, null]];
137137
assert.deepStrictEqual(
138138
searchForActionsLines(logContent5),
139139
expected5,
140140
"Should handle malformed log lines gracefully"
141141
);
142+
143+
// Test case: Immutable action groups, plus mutable actions
144+
const logContent6 = `2025-07-14T13:16:54.1997507Z Current runner version: '2.326.0'
145+
2025-07-14T13:16:54.2032898Z ##[group]Runner Image Provisioner
146+
2025-07-14T13:16:54.2034192Z Hosted Compute Agent
147+
2025-07-14T13:16:54.2035482Z Version: 20250711.363
148+
2025-07-14T13:16:54.2036437Z Commit: 6785254374ce925a23743850c1cb91912ce5c14c
149+
2025-07-14T13:16:54.2037793Z Build Date: 2025-07-11T20:04:25Z
150+
2025-07-14T13:16:54.2038731Z ##[endgroup]
151+
2025-07-14T13:16:54.2039633Z ##[group]Operating System
152+
2025-07-14T13:16:54.2040684Z Ubuntu
153+
2025-07-14T13:16:54.2041493Z 24.04.2
154+
2025-07-14T13:16:54.2042229Z LTS
155+
2025-07-14T13:16:54.2043203Z ##[endgroup]
156+
2025-07-14T13:16:54.2044107Z ##[group]Runner Image
157+
2025-07-14T13:16:54.2045360Z Image: ubuntu-24.04
158+
2025-07-14T13:16:54.2046348Z Version: 20250710.1.0
159+
2025-07-14T13:16:54.2048046Z Included Software: https://github.com/actions/runner-images/blob/ubuntu24/20250710.1/images/ubuntu/Ubuntu2404-Readme.md
160+
2025-07-14T13:16:54.2050926Z Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu24%2F20250710.1
161+
2025-07-14T13:16:54.2052697Z ##[endgroup]
162+
2025-07-14T13:16:54.2054600Z ##[group]GITHUB_TOKEN Permissions
163+
2025-07-14T13:16:54.2057484Z Contents: read
164+
2025-07-14T13:16:54.2058290Z Metadata: read
165+
2025-07-14T13:16:54.2059196Z Packages: read
166+
2025-07-14T13:16:54.2060021Z ##[endgroup]
167+
2025-07-14T13:16:54.2062876Z Secret source: Actions
168+
2025-07-14T13:16:54.2064129Z Prepare workflow directory
169+
2025-07-14T13:16:54.2740053Z Prepare all required actions
170+
2025-07-14T13:16:54.2798345Z Getting action download info
171+
2025-07-14T13:16:54.8182595Z ##[group]Download immutable action package 'actions/checkout@v4'
172+
2025-07-14T13:16:54.8183770Z Version: 4.2.2
173+
2025-07-14T13:16:54.8185077Z Digest: sha256:ccb2698953eaebd21c7bf6268a94f9c26518a7e38e27e0b83c1fe1ad049819b1
174+
2025-07-14T13:16:54.8186424Z Source commit SHA: 11bd71901bbe5b1630ceea73d27597364c9af683
175+
2025-07-14T13:16:54.8187251Z ##[endgroup]
176+
2025-07-14T13:16:54.9067829Z ##[group]Download immutable action package 'actions/setup-java@v4'
177+
2025-07-14T13:16:54.9068748Z Version: 4.7.1
178+
2025-07-14T13:16:54.9069568Z Digest: sha256:23223d64943473efb4336f60463c0429cd4f422cd5fc6c48a5cf0d5907c1aeac
179+
2025-07-14T13:16:54.9070517Z Source commit SHA: c5195efecf7bdfc987ee8bae7a71cb8b11521c00
180+
2025-07-14T13:16:54.9071298Z ##[endgroup]
181+
2025-07-14T13:16:55.2797700Z Download action repository 'sbt/setup-sbt@v1' (SHA:234370af1319038bf8dc432f8a7e4b83078a1781)
182+
2025-07-14T13:16:55.7318730Z Getting action download info
183+
2025-07-14T13:16:56.0547136Z ##[group]Download immutable action package 'actions/cache@v4'
184+
2025-07-14T13:16:56.0547618Z Version: 4.2.3
185+
2025-07-14T13:16:56.0548031Z Digest: sha256:c8a3bb963e1f1826d8fcc8d1354f0dd29d8ac1db1d4f6f20247055ae11b81ed9
186+
2025-07-14T13:16:56.0548578Z Source commit SHA: 5a3ec84eff668545956fd18022155c47e93e2684
187+
2025-07-14T13:16:56.0548968Z ##[endgroup]
188+
2025-07-14T13:16:56.1885796Z Complete job name: hello
189+
2025-07-14T13:16:56.2569979Z ##[group]Run actions/checkout@v4
190+
2025-07-14T13:16:56.2570683Z with:
191+
2025-07-14T13:16:56.2571032Z repository: github/invented-repo-for-test
192+
2025-07-14T13:16:56.2571669Z token: ***
193+
2025-07-14T13:16:56.2571947Z ssh-strict: true
194+
2025-07-14T13:16:56.2572231Z ssh-user: git
195+
2025-07-14T13:16:56.2572519Z persist-credentials: true
196+
2025-07-14T13:16:56.2572857Z clean: true
197+
2025-07-14T13:16:56.2573169Z sparse-checkout-cone-mode: true
198+
2025-07-14T13:16:56.2573505Z fetch-depth: 1
199+
2025-07-14T13:16:56.2573786Z fetch-tags: false
200+
2025-07-14T13:16:56.2574068Z show-progress: true
201+
2025-07-14T13:16:56.2574357Z lfs: false
202+
2025-07-14T13:16:56.2574617Z submodules: false
203+
2025-07-14T13:16:56.2575090Z set-safe-directory: true
204+
2025-07-14T13:16:56.2575645Z ##[endgroup]
205+
2025-07-14T13:16:56.4670673Z Syncing repository: github/invented-repo-for-test`
206+
207+
const expected6 = [
208+
["actions/checkout", "v4", "11bd71901bbe5b1630ceea73d27597364c9af683", "4.2.2", "ccb2698953eaebd21c7bf6268a94f9c26518a7e38e27e0b83c1fe1ad049819b1"],
209+
["actions/setup-java", "v4", "c5195efecf7bdfc987ee8bae7a71cb8b11521c00", "4.7.1", "23223d64943473efb4336f60463c0429cd4f422cd5fc6c48a5cf0d5907c1aeac"],
210+
["sbt/setup-sbt", "v1", "234370af1319038bf8dc432f8a7e4b83078a1781", null, null],
211+
["actions/cache", "v4", "5a3ec84eff668545956fd18022155c47e93e2684", "4.2.3", "c8a3bb963e1f1826d8fcc8d1354f0dd29d8ac1db1d4f6f20247055ae11b81ed9"],
212+
];
213+
assert.deepStrictEqual(
214+
searchForActionsLines(logContent6),
215+
expected6,
216+
"Should extract actions from an immutable action group"
217+
);
142218
}
143219

144220
// Run the tests

audit_workflow_runs_utils.js

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,31 +59,72 @@ export function parseFromInputFile(actionsToAuditFilename) {
5959
}
6060

6161
// Regex to spot, e.g. Download action repository 'actions/checkout@v4' (SHA:11bd71901bbe5b1630ceea73d27597364c9af683)
62-
const actionRegex = /^Download action repository '(.+?)' \(SHA:(.+?)\)/;
62+
const mutableActionPrefix = "Download action repository '";
63+
const mutableActionRegex = /^Download action repository '([^']+?)' \(SHA:([^)]+?)\)/;
64+
const immutableActionPrefix = "##[group]Download immutable action package '";
65+
const immutableActionRegex = /^##\[group\]Download immutable action package '([^'@]+?)@([^']*)'/;
66+
const gettingDownloadInfoLine = "Getting action download info";
6367

6468
export function searchForActionsLines(logContent) {
6569
const logLines = logContent.split("\n");
6670
const actions = [];
6771
let foundActions = false;
72+
let inImmutableGroup = false;
73+
let immutableAction = {};
6874

6975
for (const line of logLines) {
7076
// separate the timestamp from the data
7177
const data = line.split(" ").slice(1).join(" ");
7278
if (data == undefined) {
7379
continue;
7480
}
75-
if (data.startsWith("Download action repository '")) {
81+
if (data.startsWith(mutableActionPrefix)) {
7682
foundActions = true;
77-
const match = actionRegex.exec(data);
83+
const match = mutableActionRegex.exec(data);
7884
if (match) {
7985
const action = match[1];
8086
const sha = match[2];
8187

8288
const [repo, version] = action.split("@");
83-
actions.push([repo, version, sha]);
89+
actions.push([repo, version, sha, null, null]);
8490
}
85-
// quit processing the log after the first line that is not an action, if we already found actions
91+
} else if (data.startsWith(immutableActionPrefix)) {
92+
foundActions = true;
93+
inImmutableGroup = true;
94+
const match = immutableActionRegex.exec(data);
95+
if (match) {
96+
const action = match[1];
97+
const tag = match[2];
98+
99+
immutableAction = {
100+
action: action,
101+
tag: tag,
102+
version: null,
103+
sha: null,
104+
digest: null,
105+
}
106+
}
107+
} else if (inImmutableGroup && data.startsWith("##[endgroup]")) {
108+
actions.push([immutableAction.action, immutableAction.tag, immutableAction.sha, immutableAction.version, immutableAction.digest]);
109+
inImmutableGroup = false;
110+
} else if (inImmutableGroup) {
111+
const versionMatch = data.match(/Version: ([a-zA-Z0-9._-]+)/);
112+
const shaMatch = data.match(/Source commit SHA: ([a-f0-9]{40,})/);
113+
const digestMatch = data.match(/Digest: sha256:([a-f0-9]{64})/);
114+
if (versionMatch) {
115+
immutableAction.version = versionMatch[1];
116+
}
117+
if (shaMatch) {
118+
immutableAction.sha = shaMatch[1];
119+
}
120+
if (digestMatch) {
121+
immutableAction.digest = digestMatch[1];
122+
}
123+
} else if (data == gettingDownloadInfoLine) {
124+
// continue processing the log until we find an action line
125+
continue;
86126
} else if (foundActions) {
127+
// quit processing the log after the first line that is not an action, if we already found actions
87128
break;
88129
}
89130
}

test.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"tj-actions/changed-files": ["0e58ed8671d6b60d0890c21b07f8835ace038e67"],
3+
"reviewdog/*": ["*"]
4+
}

test2.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"aquasecurity/trivy-action": ["6e7b7d1fd3e4fef0c5fa8cce1229c54b2c9bd0d8"],
3+
"actions/setup-node": ["*"],
4+
"actions/checkout": ["*"]
5+
}

0 commit comments

Comments
 (0)