Skip to content

Commit 65bb4f1

Browse files
committed
Harden GitHub Actions workflows based on zizmor audit
- Move untrusted ${{ }} into env vars to prevent script injection - Pin all actions to commit SHAs (no version bumps) - Set top-level permissions: {} with minimal job-level grants - Add concurrency groups and job names - Fix PowerShell/github-script injection in Dockerfile-update workflows - Pin semgrep container image by digest
1 parent 2e6e98a commit 65bb4f1

12 files changed

Lines changed: 180 additions & 75 deletions

.github/workflows/auto-update-Dockerfiles.yml

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
name: Auto-Update Lambda Dockerfiles Daily
22

3-
permissions:
4-
contents: write
5-
pull-requests: write
3+
permissions: {}
64

75
on:
86
# Run daily at midnight UTC
@@ -11,9 +9,17 @@ on:
119
# Allows to run this workflow manually from the Actions tab for testing
1210
workflow_dispatch:
1311

12+
concurrency:
13+
group: ${{ github.workflow }}
14+
cancel-in-progress: false
15+
1416
jobs:
1517
auto-update:
18+
name: Auto-update Dockerfiles and open PR
1619
runs-on: ubuntu-latest
20+
permissions:
21+
contents: write # to push the daily Dockerfile update branch
22+
pull-requests: write # to open the update PR and label it
1723
env:
1824
NET_8_AMD64_Dockerfile: "LambdaRuntimeDockerfiles/Images/net8/amd64/Dockerfile"
1925
NET_8_ARM64_Dockerfile: "LambdaRuntimeDockerfiles/Images/net8/arm64/Dockerfile"
@@ -39,7 +45,7 @@ jobs:
3945
run: |
4046
$version = & "./LambdaRuntimeDockerfiles/get-latest-aspnet-versions.ps1" -MajorVersion "8"
4147
if (-not [string]::IsNullOrEmpty($version)) {
42-
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "${{ env.DOCKERFILE_PATH }}" -NextVersion $version
48+
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "$env:DOCKERFILE_PATH" -NextVersion $version
4349
} else {
4450
Write-Host "Skipping .NET 8 AMD64 update - No version detected"
4551
}
@@ -53,7 +59,7 @@ jobs:
5359
run: |
5460
$version = & "./LambdaRuntimeDockerfiles/get-latest-aspnet-versions.ps1" -MajorVersion "8"
5561
if (-not [string]::IsNullOrEmpty($version)) {
56-
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "${{ env.DOCKERFILE_PATH }}" -NextVersion $version
62+
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "$env:DOCKERFILE_PATH" -NextVersion $version
5763
} else {
5864
Write-Host "Skipping .NET 8 ARM64 update - No version detected"
5965
}
@@ -67,7 +73,7 @@ jobs:
6773
run: |
6874
$version = & "./LambdaRuntimeDockerfiles/get-latest-aspnet-versions.ps1" -MajorVersion "9"
6975
if (-not [string]::IsNullOrEmpty($version)) {
70-
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "${{ env.DOCKERFILE_PATH }}" -NextVersion $version
76+
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "$env:DOCKERFILE_PATH" -NextVersion $version
7177
} else {
7278
Write-Host "Skipping .NET 9 AMD64 update - No version detected"
7379
}
@@ -81,7 +87,7 @@ jobs:
8187
run: |
8288
$version = & "./LambdaRuntimeDockerfiles/get-latest-aspnet-versions.ps1" -MajorVersion "9"
8389
if (-not [string]::IsNullOrEmpty($version)) {
84-
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "${{ env.DOCKERFILE_PATH }}" -NextVersion $version
90+
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "$env:DOCKERFILE_PATH" -NextVersion $version
8591
} else {
8692
Write-Host "Skipping .NET 9 ARM64 update - No version detected"
8793
}
@@ -95,7 +101,7 @@ jobs:
95101
run: |
96102
$version = & "./LambdaRuntimeDockerfiles/get-latest-aspnet-versions.ps1" -MajorVersion "10"
97103
if (-not [string]::IsNullOrEmpty($version)) {
98-
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "${{ env.DOCKERFILE_PATH }}" -NextVersion $version
104+
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "$env:DOCKERFILE_PATH" -NextVersion $version
99105
} else {
100106
Write-Host "Skipping .NET 10 AMD64 update - No version detected"
101107
}
@@ -109,7 +115,7 @@ jobs:
109115
run: |
110116
$version = & "./LambdaRuntimeDockerfiles/get-latest-aspnet-versions.ps1" -MajorVersion "10"
111117
if (-not [string]::IsNullOrEmpty($version)) {
112-
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "${{ env.DOCKERFILE_PATH }}" -NextVersion $version
118+
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "$env:DOCKERFILE_PATH" -NextVersion $version
113119
} else {
114120
Write-Host "Skipping .NET 10 ARM64 update - No version detected"
115121
}
@@ -123,7 +129,7 @@ jobs:
123129
run: |
124130
$version = & "./LambdaRuntimeDockerfiles/get-latest-aspnet-versions.ps1" -MajorVersion "11"
125131
if (-not [string]::IsNullOrEmpty($version)) {
126-
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "${{ env.DOCKERFILE_PATH }}" -NextVersion $version
132+
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "$env:DOCKERFILE_PATH" -NextVersion $version
127133
} else {
128134
Write-Host "Skipping .NET 11 AMD64 update - No version detected"
129135
}
@@ -137,7 +143,7 @@ jobs:
137143
run: |
138144
$version = & "./LambdaRuntimeDockerfiles/get-latest-aspnet-versions.ps1" -MajorVersion "11"
139145
if (-not [string]::IsNullOrEmpty($version)) {
140-
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "${{ env.DOCKERFILE_PATH }}" -NextVersion $version
146+
& "./LambdaRuntimeDockerfiles/update-dockerfile.ps1" -DockerfilePath "$env:DOCKERFILE_PATH" -NextVersion $version
141147
} else {
142148
Write-Host "Skipping .NET 11 ARM64 update - No version detected"
143149
}
@@ -196,7 +202,7 @@ jobs:
196202
- name: Create Pull Request
197203
id: pull-request
198204
if: ${{ steps.commit-push.outputs.CHANGES_MADE == 'true' }}
199-
uses: repo-sync/pull-request@v2
205+
uses: repo-sync/pull-request@7e79a9f5dc3ad0ce53138f01df2fad14a04831c5 # v2
200206
with:
201207
source_branch: ${{ steps.commit-push.outputs.BRANCH }}
202208
destination_branch: "dev"
@@ -226,13 +232,15 @@ jobs:
226232
# Add "Release Not Needed" label to the PR
227233
- name: Add Release Not Needed label
228234
if: ${{ steps.pull-request.outputs.pr_number }}
229-
uses: actions/github-script@v8
235+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
236+
env:
237+
PR_NUMBER: ${{ steps.pull-request.outputs.pr_number }}
230238
with:
231239
github-token: ${{ secrets.GITHUB_TOKEN }}
232240
script: |
233241
github.rest.issues.addLabels({
234242
owner: context.repo.owner,
235243
repo: context.repo.repo,
236-
issue_number: ${{ steps.pull-request.outputs.pr_number }},
244+
issue_number: Number(process.env.PR_NUMBER),
237245
labels: ['Release Not Needed']
238246
})

.github/workflows/aws-ci.yml

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,18 @@ on:
88
- dev
99
- "feature/**"
1010

11-
permissions:
12-
id-token: write
11+
permissions: {}
12+
13+
concurrency:
14+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
15+
cancel-in-progress: true
1316

1417
jobs:
1518
run-ci:
19+
name: Run CI
1620
runs-on: ubuntu-latest
21+
permissions:
22+
id-token: write # to assume AWS roles via OIDC
1723
steps:
1824
- name: Configure Load Balancer Credentials
1925
uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0
@@ -24,8 +30,13 @@ jobs:
2430
- name: Invoke Load Balancer Lambda
2531
id: lambda
2632
shell: pwsh
33+
env:
34+
LOAD_BALANCER_LAMBDA_NAME: ${{ secrets.CI_TESTING_LOAD_BALANCER_LAMBDA_NAME }}
35+
TEST_RUNNER_ACCOUNT_ROLES: ${{ secrets.CI_TEST_RUNNER_ACCOUNT_ROLES }}
36+
CODE_BUILD_PROJECT_NAME: ${{ secrets.CI_TESTING_CODE_BUILD_PROJECT_NAME }}
37+
BRANCH: ${{ github.sha }}
2738
run: |
28-
aws lambda invoke response.json --function-name "${{ secrets.CI_TESTING_LOAD_BALANCER_LAMBDA_NAME }}" --cli-binary-format raw-in-base64-out --payload '{"Roles": "${{ secrets.CI_TEST_RUNNER_ACCOUNT_ROLES }}", "ProjectName": "${{ secrets.CI_TESTING_CODE_BUILD_PROJECT_NAME }}", "Branch": "${{ github.sha }}"}'
39+
aws lambda invoke response.json --function-name "$env:LOAD_BALANCER_LAMBDA_NAME" --cli-binary-format raw-in-base64-out --payload "{`"Roles`": `"$env:TEST_RUNNER_ACCOUNT_ROLES`", `"ProjectName`": `"$env:CODE_BUILD_PROJECT_NAME`", `"Branch`": `"$env:BRANCH`"}"
2940
$roleArn=$(cat ./response.json)
3041
"roleArn=$($roleArn -replace '"', '')" >> $env:GITHUB_OUTPUT
3142
- name: Configure Test Runner Credentials
@@ -36,7 +47,7 @@ jobs:
3647
aws-region: us-west-2
3748
- name: Run Tests on AWS
3849
id: codebuild
39-
uses: aws-actions/aws-codebuild-run-build@v1
50+
uses: aws-actions/aws-codebuild-run-build@4d15a47425739ac2296ba5e7eee3bdd4bfbdd767 # v1.0.18
4051
with:
4152
project-name: ${{ secrets.CI_TESTING_CODE_BUILD_PROJECT_NAME }}
4253
- name: Configure Test Sweeper Lambda Credentials
@@ -49,10 +60,15 @@ jobs:
4960
- name: Invoke Test Sweeper Lambda
5061
if: always()
5162
shell: pwsh
63+
env:
64+
TEST_SWEEPER_LAMBDA_NAME: ${{ secrets.CI_TESTING_TEST_SWEEPER_LAMBDA_NAME }}
65+
CODE_BUILD_PROJECT_NAME: ${{ secrets.CI_TESTING_CODE_BUILD_PROJECT_NAME }}
5266
run: |
53-
aws lambda invoke response.json --function-name "${{ secrets.CI_TESTING_TEST_SWEEPER_LAMBDA_NAME }}" --cli-binary-format raw-in-base64-out --payload '{"Tags": "aws-repo=${{ secrets.CI_TESTING_CODE_BUILD_PROJECT_NAME }}"}'
67+
aws lambda invoke response.json --function-name "$env:TEST_SWEEPER_LAMBDA_NAME" --cli-binary-format raw-in-base64-out --payload "{`"Tags`": `"aws-repo=$env:CODE_BUILD_PROJECT_NAME`"}"
5468
- name: CodeBuild Link
5569
shell: pwsh
70+
env:
71+
BUILD_ID: ${{ steps.codebuild.outputs.aws-build-id }}
5672
run: |
57-
$buildId = "${{ steps.codebuild.outputs.aws-build-id }}"
73+
$buildId = "$env:BUILD_ID"
5874
echo $buildId

.github/workflows/build-lambda-runtime-dockerfiles.yml

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@ on:
88
paths:
99
- "LambdaRuntimeDockerfiles/**"
1010

11-
permissions:
12-
contents: read
11+
permissions: {}
12+
13+
concurrency:
14+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
15+
cancel-in-progress: true
1316

1417
jobs:
1518
build-runtime-images:
1619
name: Build runtime image (${{ matrix.name }})
1720
runs-on: ubuntu-latest
21+
permissions:
22+
contents: read # to check out the repository and build the Dockerfiles
1823
strategy:
1924
fail-fast: false
2025
matrix:
@@ -45,16 +50,18 @@ jobs:
4550
platform: linux/arm64
4651

4752
steps:
48-
- uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2 #v4.2.2
53+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
54+
with:
55+
persist-credentials: false
4956

5057
- name: Set up QEMU
51-
uses: docker/setup-qemu-action@v4
58+
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4
5259

5360
- name: Set up Docker Buildx
54-
uses: docker/setup-buildx-action@v4
61+
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
5562

5663
- name: Build ${{ matrix.name }}
57-
uses: docker/build-push-action@v7
64+
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
5865
with:
5966
context: .
6067
file: ${{ matrix.dockerfile }}

.github/workflows/change-file-in-pr.yml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,36 @@ on:
44
pull_request:
55
types: [opened, synchronize, reopened, labeled]
66

7+
permissions: {}
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
11+
cancel-in-progress: true
12+
713
jobs:
814
check-files-in-directory:
915
if: ${{ !contains(github.event.pull_request.labels.*.name, 'Release Not Needed') && !contains(github.event.pull_request.labels.*.name, 'Release PR') }}
1016
name: Change File Included in PR
1117
runs-on: ubuntu-latest
18+
permissions:
19+
contents: read # to check out the repository and list changed files
1220

1321
steps:
1422
- name: Checkout PR code
15-
uses: actions/checkout@v6
23+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
24+
with:
25+
persist-credentials: false
1626

1727
- name: Get List of Changed Files
1828
id: changed-files
19-
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5
29+
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5
2030

2131
- name: Check for Change File(s) in .autover/changes/
32+
env:
33+
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
2234
run: |
2335
DIRECTORY=".autover/changes/"
24-
if echo "${{ steps.changed-files.outputs.all_changed_files }}" | grep -q "$DIRECTORY"; then
36+
if echo "$ALL_CHANGED_FILES" | grep -q "$DIRECTORY"; then
2537
echo "✅ One or more change files in '$DIRECTORY' are included in this PR."
2638
else
2739
echo "❌ No change files in '$DIRECTORY' are included in this PR."

.github/workflows/closed-issue-message.yml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,24 @@ on:
33
issues:
44
types: [closed]
55

6-
permissions:
7-
issues: write
6+
permissions: {}
7+
8+
concurrency:
9+
group: ${{ github.workflow }}
10+
cancel-in-progress: false
811

912
jobs:
1013
auto_comment:
14+
name: Comment on closed issue
1115
runs-on: ubuntu-latest
16+
permissions:
17+
issues: write # to comment on the closed issue
1218
steps:
13-
- uses: aws-actions/closed-issue-message@v2
19+
- uses: aws-actions/closed-issue-message@10aaf6366131b673a7c8b7742f8b3849f1d44f18 # v2
1420
with:
1521
# These inputs are both required
1622
repo-token: "${{ secrets.GITHUB_TOKEN }}"
1723
message: |
18-
Comments on closed issues are hard for our team to see.
19-
If you need more assistance, please either tag a team member or open a new issue that references this one.
24+
Comments on closed issues are hard for our team to see.
25+
If you need more assistance, please either tag a team member or open a new issue that references this one.
2026
If you wish to keep having a conversation with other community members under this issue feel free to do so.

.github/workflows/create-release-pr.yml

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,19 @@ on:
1111
type: string
1212
required: false
1313

14-
permissions:
15-
id-token: write
16-
repository-projects: read
14+
permissions: {}
15+
16+
concurrency:
17+
group: ${{ github.workflow }}
18+
cancel-in-progress: false
1719

1820
jobs:
1921
release-pr:
2022
name: Release PR
2123
runs-on: ubuntu-latest
24+
permissions:
25+
id-token: write # to assume AWS roles via OIDC
26+
repository-projects: read # to read project metadata when creating the release PR
2227

2328
env:
2429
INPUT_OVERRIDE_VERSION: ${{ github.event.inputs.OVERRIDE_VERSION }}
@@ -97,10 +102,11 @@ jobs:
97102
run: autover changelog
98103
# Push the release branch up as well as the created tag
99104
- name: Push Changes
105+
env:
106+
BRANCH: ${{ steps.create-release-branch.outputs.BRANCH }}
100107
run: |
101-
branch=${{ steps.create-release-branch.outputs.BRANCH }}
102-
git push origin $branch
103-
git push origin $branch --tags
108+
git push origin "$BRANCH"
109+
git push origin "$BRANCH" --tags
104110
# Get the release name that will be used to create a PR
105111
- name: Read Release Name
106112
id: read-release-name
@@ -117,7 +123,10 @@ jobs:
117123
- name: Create Pull Request
118124
env:
119125
GITHUB_TOKEN: ${{ env.FG_PAT }}
126+
VERSION: ${{ steps.read-release-name.outputs.VERSION }}
127+
CHANGELOG: ${{ steps.read-changelog.outputs.CHANGELOG }}
128+
BRANCH: ${{ steps.create-release-branch.outputs.BRANCH }}
120129
run: |
121130
gh label create "Release PR" --description "A Release PR that includes versioning and changelog changes" -c "#FF0000" -f
122-
pr_url="$(gh pr create --title "${{ steps.read-release-name.outputs.VERSION }}" --label "Release PR" --body "${{ steps.read-changelog.outputs.CHANGELOG }}" --base dev --head ${{ steps.create-release-branch.outputs.BRANCH }})"
131+
pr_url="$(gh pr create --title "$VERSION" --label "Release PR" --body "$CHANGELOG" --base dev --head "$BRANCH")"
123132

.github/workflows/handle-stale-discussions.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,20 @@ on:
55
discussion_comment:
66
types: [created]
77

8+
permissions: {}
9+
10+
concurrency:
11+
group: ${{ github.workflow }}
12+
cancel-in-progress: false
13+
814
jobs:
915
handle-stale-discussions:
1016
name: Handle stale discussions
1117
runs-on: ubuntu-latest
1218
permissions:
13-
discussions: write
19+
discussions: write # to mark and close stale discussions
1420
steps:
1521
- name: Stale discussions action
16-
uses: aws-github-ops/handle-stale-discussions@v1.6.0
22+
uses: aws-github-ops/handle-stale-discussions@c0beee451a5d33d9c8f048a6d4e7c856b5422544 # v1.6.0
1723
env:
1824
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

0 commit comments

Comments
 (0)