Skip to content

Commit a199aa4

Browse files
committed
Now audits single repos too
1 parent 992ca04 commit a199aa4

3 files changed

Lines changed: 48 additions & 31 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
node_modules/
22
.DS_Store
3-
workflow_audit_results.json
3+
workflow_audit_results.sljson

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ For Enterprise Server or Data Residency users, please set `GITHUB_BASE_URL` in y
1919
node audit_workflow_runs.js <org or enterprise name> <"ent" or "org"> <start date> <end date> [<action>] [<commit SHA>]
2020
```
2121

22+
Results are printed to the console in CSV, and also appended to a file in the current directory, named `workflow_audit_results.sljson`.
23+
2224
For example:
2325

2426
```bash

audit_workflow_runs.js

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -97,38 +97,53 @@ async function* auditOrganizationWithoutAuditLog(orgName, startDate, endDate) {
9797

9898
for (const repo of repos.data) {
9999
// Step 2: Get all workflow runs in the repository within the date range
100-
try {
101-
const workflowRuns = await octokit.actions.listWorkflowRunsForRepo({
102-
owner: orgName,
103-
repo: repo.name,
104-
per_page: 100,
105-
created: `${startDate}..${endDate}`,
106-
});
107-
108-
for (const run of workflowRuns.data.workflow_runs) {
109-
// Step 3: Get the logs for the workflow run
110-
const actions = await extractActionsFromLogs(run.logs_url);
111-
112-
const action_run_results = await createActionsRunResults(
113-
orgName,
114-
repo.name,
115-
run,
116-
actions
117-
);
118-
119-
for (const result of action_run_results) {
120-
yield result;
121-
}
122-
}
123-
} catch (error) {
124-
continue;
100+
for await (const result of _auditRepo(orgName, repo.name, startDate, endDate)) {
101+
yield result;
125102
}
126103
}
127104
} catch (error) {
128105
console.error("Error auditing organization:", error.message);
129106
}
130107
}
131108

109+
// audit a single repository
110+
async function* auditRepo(repoName, startDate, endDate) {
111+
const [org, repo] = repoName.split("/");
112+
113+
for await (const result of _auditRepo(org, repo, startDate, endDate)) {
114+
yield result;
115+
}
116+
}
117+
118+
// audit a single repository, using the orgname and repo name
119+
async function* _auditRepo(org, repo, startDate, endDate) {
120+
try {
121+
const workflowRuns = await octokit.actions.listWorkflowRunsForRepo({
122+
owner: org,
123+
repo: repo,
124+
per_page: 100,
125+
created: `${startDate}..${endDate}`,
126+
});
127+
128+
for (const run of workflowRuns.data.workflow_runs) {
129+
const actions = await extractActionsFromLogs(run.logs_url);
130+
131+
const action_run_results = await createActionsRunResults(
132+
org,
133+
repo,
134+
run,
135+
actions
136+
);
137+
138+
for (const result of action_run_results) {
139+
yield result;
140+
}
141+
}
142+
} catch (error) {
143+
console.error("Error auditing repo:", error.message);
144+
}
145+
}
146+
132147
// use the Enterprise/Organization audit log to list all workflow runs in that period
133148
// for each workflow run, extract the actions used
134149
// 1. get the audit log, searching for `worklows` category, workflows.prepared_workflow_job
@@ -181,18 +196,18 @@ async function main() {
181196
const args = process.argv.slice(2);
182197

183198
if (args.length < 4) {
184-
console.error("Usage: node main.js <org-or-ent-name> <org|ent> <start-date> <end-date> [<action-name>] [<action-commit-sha>]");
199+
console.error("Usage: node main.js <org-or-ent-name> <org|ent|repo> <start-date> <end-date> [<action-name>] [<action-commit-sha>]");
185200
return;
186201
}
187202

188203
const [orgOrEntName, orgOrEnt, startDate, endDate] = args;
189204

190-
if (!['ent', 'org'].includes(orgOrEnt)) {
191-
console.error("<org|ent|repo> must be 'ent', 'org'");
205+
if (!['ent', 'org', 'repo'].includes(orgOrEnt)) {
206+
console.error("<org|ent|repo> must be 'ent', 'org', 'repo'");
192207
return;
193208
}
194209

195-
const action_run_results = auditEnterpriseOrOrg(orgOrEntName, orgOrEnt, startDate, endDate);
210+
const action_run_results = orgOrEnt != 'repo' ? auditEnterpriseOrOrg(orgOrEntName, orgOrEnt, startDate, endDate) : auditRepo(orgOrEntName, startDate, endDate);
196211

197212
for await (const result of action_run_results) {
198213
if (args.length >= 5) {
@@ -207,7 +222,7 @@ async function main() {
207222

208223
console.log(Object.values(result).join(","));
209224
fs.appendFileSync(
210-
"workflow_audit_results.json",
225+
"workflow_audit_results.sljson",
211226
JSON.stringify(result) + "\n"
212227
);
213228
}

0 commit comments

Comments
 (0)