Skip to content

Commit a2e8261

Browse files
Merge branch 'main' into lz/ext-danger
2 parents aac9829 + df41e0d commit a2e8261

File tree

8 files changed

+464
-16
lines changed

8 files changed

+464
-16
lines changed

.github/workflows/update-deps.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Update dependencies
2+
3+
on:
4+
workflow_dispatch:
5+
schedule:
6+
# Run weekly on Mondays at 8:00 UTC
7+
- cron: '0 8 * * 1'
8+
9+
permissions:
10+
contents: write
11+
pull-requests: write
12+
13+
jobs:
14+
danger:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: getsentry/github-workflows/updater@main
18+
with:
19+
path: danger/danger.properties
20+
name: Danger JS
21+
api-token: ${{ secrets.GITHUB_TOKEN }}

CHANGELOG.md

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,30 @@
11
# Changelog
22

3-
## Unreleased
3+
## 3.1.0
4+
5+
### Features
6+
7+
- Updater - Add `post-update-script` input parameter to run custom scripts after dependency updates ([#130](https://github.com/getsentry/github-workflows/pull/130), [#133](https://github.com/getsentry/github-workflows/pull/133))
8+
- Scripts receive original and new version as arguments
9+
- Support both bash (`.sh`) and PowerShell (`.ps1`) scripts
10+
- Enables workflows like updating lock files, running code generators, or modifying configuration files
11+
- Updater - Add SSH key support and comprehensive authentication validation ([#134](https://github.com/getsentry/github-workflows/pull/134))
12+
- Add `ssh-key` input parameter for deploy key authentication
13+
- Support using both `ssh-key` (for git) and `api-token` (for GitHub API) together
14+
- Add detailed token validation with actionable error messages
15+
- Detect common token issues: expiration, whitespace, SSH keys in wrong input, missing scopes
16+
- Validate SSH key format when provided
417

518
### Fixes
619

720
- Updater - Fix boolean input handling for `changelog-entry` parameter and add input validation ([#127](https://github.com/getsentry/github-workflows/pull/127))
21+
- Updater - Fix cryptic authentication errors with better validation and error messages ([#134](https://github.com/getsentry/github-workflows/pull/134), closes [#128](https://github.com/getsentry/github-workflows/issues/128))
22+
23+
### Dependencies
24+
25+
- Bump Danger JS from v11.3.1 to v13.0.4 ([#132](https://github.com/getsentry/github-workflows/pull/132))
26+
- [changelog](https://github.com/danger/danger-js/blob/main/CHANGELOG.md#1304)
27+
- [diff](https://github.com/danger/danger-js/compare/11.3.1...13.0.4)
828

929
## 3.0.0
1030

@@ -27,6 +47,7 @@
2747
- Updater and Danger reusable workflows are now composite actions ([#114](https://github.com/getsentry/github-workflows/pull/114))
2848

2949
To update your existing Updater workflows:
50+
3051
```yaml
3152
### Before
3253
native:
@@ -38,7 +59,7 @@
3859
# If a custom token is used instead, a CI would be triggered on a created PR.
3960
api-token: ${{ secrets.CI_DEPLOY_KEY }}
4061
41-
### After
62+
### After (v3.0)
4263
native:
4364
runs-on: ubuntu-latest
4465
steps:
@@ -49,7 +70,23 @@
4970
api-token: ${{ secrets.CI_DEPLOY_KEY }}
5071
```
5172

73+
**Note**: If you were using SSH deploy keys with the v2 reusable workflow, the v3.0 composite action initially only supported tokens.
74+
SSH key support was restored in v3.1 ([#134](https://github.com/getsentry/github-workflows/pull/134)). To use SSH keys, update to v3.1+ and use the `ssh-key` input:
75+
76+
```yaml
77+
### With SSH key (v3.1+)
78+
native:
79+
runs-on: ubuntu-latest
80+
steps:
81+
- uses: getsentry/github-workflows/updater@v3
82+
with:
83+
path: scripts/update-sentry-native-ndk.sh
84+
name: Native SDK
85+
ssh-key: ${{ secrets.CI_DEPLOY_KEY }}
86+
```
87+
5288
To update your existing Danger workflows:
89+
5390
```yaml
5491
### Before
5592
danger:

danger/action.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ runs:
4848
exit 1
4949
fi
5050
51-
# Using a pre-built docker image in GitHub container registry instead of NPM to reduce possible attack vectors.
51+
# Using a pre-built docker image in GitHub container registry instead of NPM to reduce possible attack vectors.
5252
- name: Setup container
5353
shell: bash
5454
run: |
@@ -65,6 +65,7 @@ runs:
6565
-e DANGER_DISABLE_TRANSPILATION="true" \
6666
-e EXTRA_DANGERFILE_INPUT="${{ inputs.extra-dangerfile }}" \
6767
ghcr.io/danger/danger-js:${{ steps.config.outputs.version }} \
68+
ghcr.io/danger/danger-js:${{ steps.config.outputs.version }} \
6869
-c "sleep infinity"
6970
7071
- name: Setup additional packages

danger/danger.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
version=13.0.4
2+
repo=https://github.com/danger/danger-js

updater/README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,18 @@ jobs:
9595
target-branch: v7
9696
pattern: '^1\.' # Limit to major version '1'
9797
api-token: ${{ secrets.CI_DEPLOY_KEY }}
98+
99+
# Use a post-update script (sh or ps1) to make additional changes after dependency update
100+
# The script receives two arguments: original version and new version
101+
post-update-script:
102+
runs-on: ubuntu-latest
103+
steps:
104+
- uses: getsentry/github-workflows/updater@v3
105+
with:
106+
path: modules/sentry-cocoa
107+
name: Cocoa SDK
108+
post-update-script: scripts/post-update.sh # Receives args: $1=old version, $2=new version
109+
api-token: ${{ secrets.CI_DEPLOY_KEY }}
98110
```
99111
100112
## Inputs
@@ -135,12 +147,45 @@ jobs:
135147
* type: string
136148
* required: false
137149
* default: '' (uses repository default branch)
150+
* `post-update-script`: Optional script to run after successful dependency update. Can be a bash script (`.sh`) or PowerShell script (`.ps1`). The script will be executed in the repository root directory before PR creation. The script receives two arguments:
151+
* `$1` / `$args[0]` - The original version (version before update)
152+
* `$2` / `$args[1]` - The new version (version after update)
153+
* type: string
154+
* required: false
155+
* default: ''
138156
* `api-token`: Token for the repo. Can be passed in using `${{ secrets.GITHUB_TOKEN }}`.
139157
If you provide the usual `${{ github.token }}`, no followup CI will run on the created PR.
140158
If you want CI to run on the PRs created by the Updater, you need to provide custom user-specific auth token.
141159
* type: string
142160
* required: true
143161

162+
### Post-Update Script Example
163+
164+
**Bash script** (`scripts/post-update.sh`):
165+
166+
```bash
167+
#!/usr/bin/env bash
168+
set -euo pipefail
169+
170+
ORIGINAL_VERSION="$1"
171+
NEW_VERSION="$2"
172+
173+
echo "Updated from $ORIGINAL_VERSION to $NEW_VERSION"
174+
# Make additional changes to repository files here
175+
```
176+
177+
**PowerShell script** (`scripts/post-update.ps1`):
178+
179+
```powershell
180+
param(
181+
[Parameter(Mandatory = $true)][string] $OriginalVersion,
182+
[Parameter(Mandatory = $true)][string] $NewVersion
183+
)
184+
185+
Write-Output "Updated from $OriginalVersion to $NewVersion"
186+
# Make additional changes to repository files here
187+
```
188+
144189
## Outputs
145190

146191
* `prUrl`: The created/updated PR's URL.

updater/action.yml

Lines changed: 145 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,17 @@ inputs:
3434
required: false
3535
default: ''
3636
api-token:
37-
description: 'Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }}'
38-
required: true
37+
description: 'Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }}. Not required if ssh-key is provided, but can be used together with ssh-key for GitHub API operations.'
38+
required: false
39+
default: ''
40+
ssh-key:
41+
description: 'SSH private key for repository authentication. Can be used alone or together with api-token (SSH for git, token for GitHub API).'
42+
required: false
43+
default: ''
44+
post-update-script:
45+
description: 'Optional script to run after successful dependency update. Can be a bash script (.sh) or PowerShell script (.ps1). The script will be executed in the caller-repo directory before PR creation.'
46+
required: false
47+
default: ''
3948

4049
outputs:
4150
prUrl:
@@ -102,6 +111,127 @@ runs:
102111
}
103112
Write-Output "✓ PR strategy value '${{ inputs.pr-strategy }}' is valid"
104113
114+
- name: Validate post-update-script
115+
if: ${{ inputs.post-update-script != '' }}
116+
shell: pwsh
117+
run: |
118+
# Validate that inputs.post-update-script contains only safe characters
119+
if ('${{ inputs.post-update-script }}' -notmatch '^[a-zA-Z0-9_\./#\s-]+$') {
120+
Write-Output "::error::Invalid post-update-script path: '${{ inputs.post-update-script }}'. Only alphanumeric characters, spaces, and _-./# are allowed."
121+
exit 1
122+
}
123+
Write-Output "✓ Post-update script path '${{ inputs.post-update-script }}' is valid"
124+
125+
- name: Validate authentication inputs
126+
shell: pwsh
127+
env:
128+
GH_TOKEN: ${{ inputs.api-token || github.token }}
129+
SSH_KEY: ${{ inputs.ssh-key }}
130+
run: |
131+
$hasToken = -not [string]::IsNullOrEmpty($env:GH_TOKEN)
132+
$hasSshKey = -not [string]::IsNullOrEmpty($env:SSH_KEY)
133+
134+
if (-not $hasToken -and -not $hasSshKey) {
135+
Write-Output "::error::Either api-token or ssh-key must be provided for authentication."
136+
exit 1
137+
}
138+
139+
if ($hasToken -and $hasSshKey) {
140+
Write-Output "✓ Using both SSH key (for git) and token (for GitHub API)"
141+
} elseif ($hasToken) {
142+
Write-Output "✓ Using token authentication"
143+
} else {
144+
Write-Output "✓ Using SSH key authentication"
145+
}
146+
147+
- name: Validate API token
148+
if: ${{ inputs.api-token != '' }}
149+
shell: pwsh
150+
env:
151+
GH_TOKEN: ${{ inputs.api-token || github.token }}
152+
run: |
153+
# Check if token is actually an SSH key
154+
if ($env:GH_TOKEN -match '-----BEGIN') {
155+
Write-Output "::error::The api-token input appears to contain an SSH private key."
156+
Write-Output "::error::Please use the ssh-key input for SSH authentication instead of api-token."
157+
exit 1
158+
}
159+
160+
# Check for whitespace
161+
if ($env:GH_TOKEN -match '\s') {
162+
$tokenLength = $env:GH_TOKEN.Length
163+
$whitespaceMatch = [regex]::Match($env:GH_TOKEN, '\s')
164+
$position = $whitespaceMatch.Index
165+
$char = $whitespaceMatch.Value
166+
$charName = switch ($char) {
167+
"`n" { "newline (LF)" }
168+
"`r" { "carriage return (CR)" }
169+
"`t" { "tab" }
170+
" " { "space" }
171+
default { "whitespace character (code: $([int][char]$char))" }
172+
}
173+
Write-Output "::error::GitHub token contains whitespace at position $position of $tokenLength characters: $charName"
174+
Write-Output "::error::This suggests the token secret may be malformed. Check for extra newlines when setting the secret."
175+
exit 1
176+
}
177+
178+
# Check token scopes (works for classic PATs only)
179+
$headers = curl -sS -I -H "Authorization: token $env:GH_TOKEN" https://api.github.com 2>&1
180+
$scopeLine = $headers | Select-String -Pattern '^x-oauth-scopes:' -CaseSensitive:$false
181+
if ($scopeLine) {
182+
$scopes = $scopeLine -replace '^x-oauth-scopes:\s*', '' -replace '\r', ''
183+
if ([string]::IsNullOrWhiteSpace($scopes)) {
184+
Write-Output "::warning::Token has no scopes. If using a fine-grained PAT, ensure it has Contents (write) and Pull Requests (write) permissions."
185+
} else {
186+
Write-Output "Token scopes: $scopes"
187+
if ($scopes -notmatch '\brepo\b' -and $scopes -notmatch '\bpublic_repo\b') {
188+
Write-Output "::warning::Token may be missing 'repo' or 'public_repo' scope. This may cause issues with private repositories."
189+
}
190+
}
191+
} else {
192+
Write-Output "::notice::Could not detect token scopes (this is normal for fine-grained PATs). Ensure token has Contents (write) and Pull Requests (write) permissions."
193+
}
194+
195+
# Check token validity and access
196+
gh api repos/${{ github.repository }} --silent 2>&1 | Out-Null
197+
if ($LASTEXITCODE -ne 0) {
198+
Write-Output "::error::GitHub token validation failed. Please verify:"
199+
Write-Output " 1. Token is not empty or malformed"
200+
Write-Output " 2. Token has not expired"
201+
Write-Output " 3. Token has an expiration date set"
202+
Write-Output " 4. Token has 'repo' and 'workflow' scopes"
203+
exit 1
204+
}
205+
206+
Write-Output "✓ GitHub token is valid and has access to this repository"
207+
208+
- name: Validate SSH key
209+
if: ${{ inputs.ssh-key != '' }}
210+
shell: pwsh
211+
env:
212+
SSH_KEY: ${{ inputs.ssh-key }}
213+
run: |
214+
# Check if SSH key looks valid
215+
if ($env:SSH_KEY -notmatch '-----BEGIN') {
216+
Write-Output "::warning::SSH key does not appear to start with a PEM header (-----BEGIN). Please verify the key format."
217+
}
218+
219+
# Check for common SSH key types
220+
$validKeyTypes = @('RSA', 'OPENSSH', 'DSA', 'EC', 'PRIVATE KEY')
221+
$hasValidType = $false
222+
foreach ($type in $validKeyTypes) {
223+
if ($env:SSH_KEY -match "-----BEGIN.*$type") {
224+
$hasValidType = $true
225+
break
226+
}
227+
}
228+
229+
if (-not $hasValidType) {
230+
Write-Output "::warning::SSH key type not recognized. Supported types: RSA, OPENSSH, DSA, EC, PRIVATE KEY"
231+
}
232+
233+
Write-Output "✓ SSH key format appears valid"
234+
105235
# What we need to accomplish:
106236
# * update to the latest tag
107237
# * create a PR
@@ -122,7 +252,8 @@ runs:
122252
- name: Checkout repository
123253
uses: actions/checkout@v4
124254
with:
125-
token: ${{ inputs.api-token }}
255+
token: ${{ inputs.api-token || github.token }}
256+
ssh-key: ${{ inputs.ssh-key }}
126257
ref: ${{ inputs.target-branch || github.ref }}
127258
path: caller-repo
128259

@@ -134,8 +265,9 @@ runs:
134265
DEPENDENCY_PATH: ${{ inputs.path }}
135266
DEPENDENCY_PATTERN: ${{ inputs.pattern }}
136267
GH_TITLE_PATTERN: ${{ inputs.gh-title-pattern }}
137-
GH_TOKEN: ${{ inputs.api-token }}
138-
run: ${{ github.action_path }}/scripts/update-dependency.ps1 -Path $env:DEPENDENCY_PATH -Pattern $env:DEPENDENCY_PATTERN -GhTitlePattern $env:GH_TITLE_PATTERN
268+
POST_UPDATE_SCRIPT: ${{ inputs.post-update-script }}
269+
GH_TOKEN: ${{ inputs.api-token || github.token }}
270+
run: ${{ github.action_path }}/scripts/update-dependency.ps1 -Path $env:DEPENDENCY_PATH -Pattern $env:DEPENDENCY_PATTERN -GhTitlePattern $env:GH_TITLE_PATTERN -PostUpdateScript $env:POST_UPDATE_SCRIPT
139271

140272
- name: Get the base repo info
141273
if: steps.target.outputs.latestTag != steps.target.outputs.originalTag
@@ -178,7 +310,7 @@ runs:
178310
shell: pwsh
179311
working-directory: caller-repo
180312
env:
181-
GH_TOKEN: ${{ inputs.api-token }}
313+
GH_TOKEN: ${{ inputs.api-token || github.token }}
182314
run: |
183315
$urls = @(gh api 'repos/${{ github.repository }}/pulls?base=${{ steps.root.outputs.baseBranch }}&head=${{ github.repository_owner }}:${{ steps.root.outputs.prBranch }}' --jq '.[].html_url')
184316
if ($urls.Length -eq 0)
@@ -205,7 +337,7 @@ runs:
205337
shell: pwsh
206338
working-directory: caller-repo
207339
env:
208-
GH_TOKEN: ${{ inputs.api-token }}
340+
GH_TOKEN: ${{ inputs.api-token || github.token }}
209341
run: |
210342
$changelog = ${{ github.action_path }}/scripts/get-changelog.ps1 `
211343
-RepoUrl '${{ steps.target.outputs.url }}' `
@@ -260,7 +392,8 @@ runs:
260392
if: ${{ ( steps.target.outputs.latestTag != steps.target.outputs.originalTag ) && ( steps.existing-pr.outputs.url == '') && ( steps.root.outputs.changed == 'false') }}
261393
uses: actions/checkout@v4
262394
with:
263-
token: ${{ inputs.api-token }}
395+
token: ${{ inputs.api-token || github.token }}
396+
ssh-key: ${{ inputs.ssh-key }}
264397
ref: ${{ inputs.target-branch || github.ref }}
265398
path: caller-repo
266399

@@ -270,8 +403,9 @@ runs:
270403
working-directory: caller-repo
271404
env:
272405
DEPENDENCY_PATH: ${{ inputs.path }}
273-
GH_TOKEN: ${{ inputs.api-token }}
274-
run: ${{ github.action_path }}/scripts/update-dependency.ps1 -Path $env:DEPENDENCY_PATH -Tag '${{ steps.target.outputs.latestTag }}'
406+
POST_UPDATE_SCRIPT: ${{ inputs.post-update-script }}
407+
GH_TOKEN: ${{ inputs.api-token || github.token }}
408+
run: ${{ github.action_path }}/scripts/update-dependency.ps1 -Path $env:DEPENDENCY_PATH -Tag '${{ steps.target.outputs.latestTag }}' -OriginalTag '${{ steps.target.outputs.originalTag }}' -PostUpdateScript $env:POST_UPDATE_SCRIPT
275409

276410
- name: Update Changelog
277411
if: ${{ inputs.changelog-entry == 'true' && ( steps.target.outputs.latestTag != steps.target.outputs.originalTag ) && ( steps.root.outputs.changed == 'false') }}
@@ -280,7 +414,7 @@ runs:
280414
env:
281415
DEPENDENCY_NAME: ${{ inputs.name }}
282416
CHANGELOG_SECTION: ${{ inputs.changelog-section }}
283-
GH_TOKEN: ${{ inputs.api-token }}
417+
GH_TOKEN: ${{ inputs.api-token || github.token }}
284418
run: |
285419
${{ github.action_path }}/scripts/update-changelog.ps1 `
286420
-Name $env:DEPENDENCY_NAME `

0 commit comments

Comments
 (0)