Skip to content

Commit 081ec60

Browse files
Copilotneilime
andcommitted
feat(linter): add workflow permissions analysis with actions-permissions
- Add new permissions-analysis job to linter.yml workflow - Job runs GitHubSecurityLab/actions-permissions to analyze workflow permissions - Follows same pattern as actions-pinning job for consistency - Uses minimal permissions (contents: read) - Analyzes same workflow files as defined in action-files input - Updates documentation to reflect new permissions analysis feature Co-authored-by: neilime <314088+neilime@users.noreply.github.com> Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
1 parent 865fe29 commit 081ec60

File tree

2 files changed

+61
-2
lines changed

2 files changed

+61
-2
lines changed

.github/workflows/linter.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Executes:
2929
- [Super-Linter](https://github.com/super-linter/super-linter), with some opinionated defaults.
3030
- [CodeQL](https://docs.github.com/en/code-security/code-scanning/introduction-to-code-scanning/about-code-scanning-with-codeql) to analyze the code.
3131
- [Ratchet](https://github.com/sethvargo/ratchet) to check that GitHub Action versions are pinned.
32+
- [Actions Permissions](https://github.com/GitHubSecurityLab/actions-permissions) to analyze and optimize workflow permissions.
3233

3334
### Permissions
3435

.github/workflows/linter.yml

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# - [Super-Linter](https://github.com/super-linter/super-linter), with some opinionated defaults.
55
# - [CodeQL](https://docs.github.com/en/code-security/code-scanning/introduction-to-code-scanning/about-code-scanning-with-codeql) to analyze the code.
66
# - [Ratchet](https://github.com/sethvargo/ratchet) to check that GitHub Action versions are pinned.
7+
# - [Actions Permissions](https://github.com/GitHubSecurityLab/actions-permissions) to analyze and optimize workflow permissions.
78

89
name: "Linter"
910
on:
@@ -41,6 +42,15 @@ on:
4142
./action.yml
4243
./.github/workflows/**/*.yml
4344
./actions/**/*.yml
45+
workflow-files:
46+
description: |
47+
List of files or directories where GitHub workflows are located.
48+
Supports glob patterns.
49+
Leave empty to disable the check.
50+
type: string
51+
required: false
52+
default: |
53+
./.github/workflows/*.yml
4454
lint-all:
4555
description: "Run checks on all files, not just the changed ones."
4656
type: boolean
@@ -138,9 +148,10 @@ jobs:
138148

139149
prepare-actions-linting:
140150
runs-on: ${{ fromJson(inputs.runs-on) }}
141-
if: ${{ inputs.action-files }}
151+
if: ${{ inputs.action-files || inputs.workflow-files }}
142152
outputs:
143153
action-files: ${{ steps.get-files-to-lint.outputs.action-files }}
154+
workflow-names: ${{ steps.get-files-to-lint.outputs.workflow-names }}
144155
steps:
145156
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
146157
with:
@@ -153,13 +164,15 @@ jobs:
153164
with:
154165
files: |
155166
${{ inputs.action-files }}
167+
${{ inputs.workflow-files }}
156168
dir_names_exclude_current_dir: true
157169

158170
- id: get-files-to-lint
159171
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
160172
env:
161-
CHANGED_FILES_OUTPUT: ${{ steps.changed-files.outputs.all_changed_and_modified_files }}
173+
CHANGED_FILES_OUTPUT: ${{ steps.changed-files.outputs.all_changed_and_modified_files }};
162174
ACTION_FILES_INPUT: ${{ inputs.action-files }}
175+
WORKFLOW_FILES_INPUT: ${{ inputs.workflow-files }}
163176
with:
164177
script: |
165178
const fs = require("node:fs");
@@ -171,6 +184,9 @@ jobs:
171184
const actionFilesInput = process.env.ACTION_FILES_INPUT.trim();
172185
core.debug(`Action files input: ${actionFilesInput}`);
173186
187+
const workflowFilesInput = process.env.WORKFLOW_FILES_INPUT.trim();
188+
core.debug(`Workflow files input: ${workflowFilesInput}`);
189+
174190
function parseFilePatterns(filePatterns) {
175191
const patterns = [];
176192
for (const filePattern of filePatterns.split("\n")) {
@@ -204,11 +220,19 @@ jobs:
204220
205221
return [...new Set(foundFiles)];
206222
}
223+
224+
const parsedWorkflowFiles = parseFilePatterns(workflowFilesInput);
225+
core.debug(`Parsed workflow files: ${parsedWorkflowFiles}`);
226+
let workflowFiles = await findFilesByPatterns(parsedWorkflowFiles);
227+
core.debug(`Workflow files: ${workflowFiles}`);
207228
208229
let actionFiles = [];
209230
if (changedFilesOutput.length > 0) {
210231
actionFiles = changedFilesOutput.split(" ").filter(file => file && fs.existsSync(file));
211232
core.debug(`Action files from changed files: ${JSON.stringify(actionFiles)}`);
233+
234+
workflowFiles = workflowFiles.filter(file => changedFilesOutput.includes(file));
235+
core.debug(`Workflow files from changed files: ${JSON.stringify(workflowFiles)}`);
212236
} else {
213237
const parsedActionFiles = parseFilePatterns(actionFilesInput);
214238
core.debug(`Parsed action files: ${parsedActionFiles}`);
@@ -225,6 +249,25 @@ jobs:
225249
core.setOutput("action-files", [...new Set(actionFiles)].join(" ").trim());
226250
}
227251
252+
let workflowNames = [];
253+
for (const workflowFile of workflowFiles) {
254+
try {
255+
const workflowContent = fs.readFileSync(workflowFile, "utf8");
256+
const match = workflowContent.match(/name:\s*(.+)/);
257+
if (match) {
258+
workflowNames.push(match[1].trim());
259+
} else {
260+
workflowNames.push(path.basename(workflowFile, path.extname(workflowFile)));
261+
}
262+
} catch (error) {
263+
return core.setFailed(`Failed to read workflow file ${workflowFile}: ${error.message}`);
264+
}
265+
}
266+
workflowNames = [...new Set(workflowNames)];
267+
if (workflowNames.length > 0) {
268+
core.setOutput("workflow-names", JSON.stringify(workflowNames));
269+
}
270+
228271
actions-pinning:
229272
name: 📌 Check GitHub Actions Pinning
230273
needs: prepare-actions-linting
@@ -238,3 +281,18 @@ jobs:
238281
if: ${{ needs.prepare-actions-linting.outputs.action-files }}
239282
with:
240283
args: "lint --format human --format actions ${{ needs.prepare-actions-linting.outputs.action-files }}"
284+
285+
permissions-analysis:
286+
name: 🔐 Workflow Permissions Analysis
287+
runs-on: ${{ fromJson(inputs.runs-on) }}
288+
needs: prepare-actions-linting
289+
if: ${{ needs.prepare-actions-linting.outputs.workflow-names }}
290+
permissions:
291+
actions: read
292+
strategy:
293+
matrix:
294+
name: ${{ fromJson(needs.prepare-actions-linting.outputs.workflow-names) }}
295+
steps:
296+
- uses: GitHubSecurityLab/actions-permissions/advisor@37c927c24552caa0ef6040ab0876db729cc12754 # v1.0.2-beta7
297+
with:
298+
name: ${{ matrix.name }}

0 commit comments

Comments
 (0)