Skip to content

Commit 0389939

Browse files
authored
feat: Support customization of the cache key (#24)
Pre-requisite for github/continuous-ai-for-accessibility#18 (Hubber access only) and github/continuous-ai-for-accessibility#27 (Hubber access only) This PR does three things: 1. Adds an optional `cache_key` input to the main action. This allows folks to choose the filename (and path) where findings will be saved (in the `gh-cache` branch). 2. Rejects weird `path` inputs in all `gh-cache/*` actions. The main action passes `cache_key` as `path` to these, so they must ensure its value is usable. 3. Adds a new `gh-cache/delete` action (for deleting a cached file). This is not _strictly_ related to customized cache keys, but I didn’t open a separate PR because `gh-cache/delete` uses the “Validate path” step introduced in this PR (item 2, above).
2 parents 4374ef4 + f5df87e commit 0389939

9 files changed

Lines changed: 186 additions & 5 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# delete
2+
3+
Delete a file or directory from the orphaned 'gh-cache' branch
4+
5+
## Usage
6+
7+
### Inputs
8+
9+
#### `path`
10+
11+
**Required** Relative path to a file or directory to delete. Allowed characters are `A-Za-z0-9._/-`. For example: `findings.json`.
12+
13+
#### `token`
14+
15+
**Required** Token with fine-grained permissions 'contents: write'.
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
name: "delete"
2+
description: "Delete a file or directory from the orphaned 'gh-cache' branch"
3+
4+
inputs:
5+
path:
6+
description: "Relative path to a file or directory to delete"
7+
required: true
8+
token:
9+
description: "Token with fine-grained permissions 'contents: write'"
10+
required: true
11+
12+
runs:
13+
using: "composite"
14+
steps:
15+
- name: Validate path
16+
shell: bash
17+
run: |
18+
# Check for empty
19+
if [[ -z "${{ inputs.path }}" ]]; then
20+
echo "Invalid 'path' input (empty)"
21+
exit 1
22+
fi
23+
# Check for absolute paths
24+
if [[ "${{ inputs.path }}" == /* ]]; then
25+
echo "Invalid 'path' input (absolute path): ${{ inputs.path }}"
26+
exit 1
27+
fi
28+
# Check for directory traversal
29+
if [[
30+
"${{ inputs.path }}" == "~"* ||
31+
"${{ inputs.path }}" =~ (^|/)\.\.(/|$)
32+
]]; then
33+
echo "Invalid 'path' input (directory traversal): ${{ inputs.path }}"
34+
exit 1
35+
fi
36+
# Check for disallowed characters (to ensure portability)
37+
if [[ ! "${{ inputs.path }}" =~ ^[A-Za-z0-9._/-]+$ ]]; then
38+
echo "Invalid 'path' input (disallowed characters): ${{ inputs.path }}"
39+
exit 1
40+
fi
41+
42+
- name: Checkout repository to temporary directory
43+
uses: actions/checkout@v5
44+
with:
45+
token: ${{ inputs.token }}
46+
fetch-depth: 0
47+
path: .gh-cache-${{ github.run_id }}
48+
show-progress: 'false'
49+
50+
- name: Switch to gh-cache branch (or create orphan)
51+
shell: bash
52+
working-directory: .gh-cache-${{ github.run_id }}
53+
run: |
54+
if git ls-remote --exit-code --heads origin gh-cache >/dev/null; then
55+
git checkout gh-cache >/dev/null 2>&1
56+
echo "Checked out existing 'gh-cache' branch"
57+
else
58+
git checkout --orphan gh-cache >/dev/null 2>&1
59+
git rm -rfq . # Clear files from the initial checkout, to avoid adding them to the orphaned branch
60+
echo "Created new orphaned 'gh-cache' branch"
61+
fi
62+
63+
- name: Copy file to repo
64+
shell: bash
65+
run: |
66+
if [ -f "${{ inputs.path }}" ]; then
67+
rm -Rf "${{ inputs.path }}"
68+
rm -Rf ".gh-cache-${{ github.run_id }}/${{ inputs.path }}"
69+
echo "Deleted '${{ inputs.path }}' from 'gh-cache' branch"
70+
fi
71+
72+
- name: Commit and push
73+
shell: bash
74+
working-directory: .gh-cache-${{ github.run_id }}
75+
run: |
76+
git add "${{ inputs.path }}" || true
77+
git config user.name "github-actions[bot]"
78+
git config user.email "github-actions[bot]@users.noreply.github.com"
79+
git commit -m "$(printf 'Delete artifact: %s' "${{ inputs.path }}")" \
80+
&& echo "Committed '${{ inputs.path }}' to 'gh-cache' branch" \
81+
|| echo "No changes to commit"
82+
git push origin gh-cache
83+
84+
- name: Clean up temporary directory
85+
shell: bash
86+
run: |
87+
rm -rf .gh-cache-${{ github.run_id }}
88+
89+
branding:
90+
icon: "trash"
91+
color: "red"

.github/actions/gh-cache/restore/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Checkout a file or directory from an orphaned 'gh-cache' branch.
88

99
#### `path`
1010

11-
**Required** Relative path to a file or directory to restore. For example: `findings.json`.
11+
**Required** Relative path to a file or directory to restore. Allowed characters are `A-Za-z0-9._/-`. For example: `findings.json`.
1212

1313
#### `token`
1414

.github/actions/gh-cache/restore/action.yml

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: "Checkout a file or directory from an orphaned 'gh-cache' branch"
33

44
inputs:
55
path:
6-
description: "Relative path to a file or directory to restore"
6+
description: "Relative path to a file or directory to restore."
77
required: true
88
token:
99
description: "Token with fine-grained permissions 'contents: read'"
@@ -16,6 +16,33 @@ inputs:
1616
runs:
1717
using: "composite"
1818
steps:
19+
- name: Validate path
20+
shell: bash
21+
run: |
22+
# Check for empty
23+
if [[ -z "${{ inputs.path }}" ]]; then
24+
echo "Invalid 'path' input (empty)"
25+
exit 1
26+
fi
27+
# Check for absolute paths
28+
if [[ "${{ inputs.path }}" == /* ]]; then
29+
echo "Invalid 'path' input (absolute path): ${{ inputs.path }}"
30+
exit 1
31+
fi
32+
# Check for directory traversal
33+
if [[
34+
"${{ inputs.path }}" == "~"* ||
35+
"${{ inputs.path }}" =~ (^|/)\.\.(/|$)
36+
]]; then
37+
echo "Invalid 'path' input (directory traversal): ${{ inputs.path }}"
38+
exit 1
39+
fi
40+
# Check for disallowed characters (to ensure portability)
41+
if [[ ! "${{ inputs.path }}" =~ ^[A-Za-z0-9._/-]+$ ]]; then
42+
echo "Invalid 'path' input (disallowed characters): ${{ inputs.path }}"
43+
exit 1
44+
fi
45+
1946
- name: Checkout repository to temporary directory
2047
uses: actions/checkout@v5
2148
with:

.github/actions/gh-cache/save/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Commit a file or directory to an orphaned 'gh-cache' branch.
88

99
#### `path`
1010

11-
**Required** Relative path to a file or directory to save. For example: `findings.json`.
11+
**Required** Relative path to a file or directory to save. Allowed characters are `A-Za-z0-9._/-`. For example: `findings.json`.
1212

1313
#### `token`
1414

.github/actions/gh-cache/save/action.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,33 @@ inputs:
1212
runs:
1313
using: "composite"
1414
steps:
15+
- name: Validate path
16+
shell: bash
17+
run: |
18+
# Check for empty
19+
if [[ -z "${{ inputs.path }}" ]]; then
20+
echo "Invalid 'path' input (empty)"
21+
exit 1
22+
fi
23+
# Check for absolute paths
24+
if [[ "${{ inputs.path }}" == /* ]]; then
25+
echo "Invalid 'path' input (absolute path): ${{ inputs.path }}"
26+
exit 1
27+
fi
28+
# Check for directory traversal
29+
if [[
30+
"${{ inputs.path }}" == "~"* ||
31+
"${{ inputs.path }}" =~ (^|/)\.\.(/|$)
32+
]]; then
33+
echo "Invalid 'path' input (directory traversal): ${{ inputs.path }}"
34+
exit 1
35+
fi
36+
# Check for disallowed characters (to ensure portability)
37+
if [[ ! "${{ inputs.path }}" =~ ^[A-Za-z0-9._/-]+$ ]]; then
38+
echo "Invalid 'path' input (disallowed characters): ${{ inputs.path }}"
39+
exit 1
40+
fi
41+
1542
- name: Checkout repository to temporary directory
1643
uses: actions/checkout@v5
1744
with:

.github/dependabot.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ updates:
2323
directory: "/.github/actions/gh-cache/cache"
2424
schedule:
2525
interval: "weekly"
26+
- package-ecosystem: "github-actions"
27+
directory: "/.github/actions/gh-cache/delete"
28+
schedule:
29+
interval: "weekly"
2630
- package-ecosystem: "github-actions"
2731
directory: "/.github/actions/gh-cache/restore"
2832
schedule:

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ https://primer.style/octicons/
2323

2424
**Required** Personal access token (PAT) with fine-grained permissions 'contents: write', 'issues: write', and 'pull_requests: write'.
2525

26+
#### `cache_key`
27+
28+
**Optional** Custom key for caching findings across runs. Allowed characters are `A-Za-z0-9._/-`. For example: `cached_findings-main-primer.style.json`.
29+
2630
### Example workflow
2731

2832
```YAML

action.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,28 @@ inputs:
1212
token:
1313
description: "Personal access token (PAT) with fine-grained permissions 'contents: write', 'issues: write', and 'pull_requests: write'"
1414
required: true
15+
cache_key:
16+
description: "Custom key for caching findings across runs"
17+
required: false
1518

1619
runs:
1720
using: "composite"
1821
steps:
22+
- name: Generate cache key
23+
id: cache_key
24+
shell: bash
25+
run: |
26+
CACHE_KEY="${{ inputs.cache_key }}"
27+
if [[ -z "$CACHE_KEY" ]]; then
28+
# If cache_key is not provided, generate a default one using the branch name, replacing characters (e.g. `/`) which would create unexpected paths.
29+
CACHE_KEY=$(printf 'cached_findings-%s' "${{ github.ref_name }}" | tr -cs 'A-Za-z0-9._-' '_')
30+
fi
31+
echo "cache_key=$CACHE_KEY" >> $GITHUB_OUTPUT
1932
- name: Restore cached_findings
2033
id: restore
2134
uses: github/continuous-ai-for-accessibility-scanner/.github/actions/gh-cache/cache@main
2235
with:
23-
key: cached_findings-${{ github.ref_name }}
36+
key: ${{ steps.cache_key.outputs.cache_key }}
2437
token: ${{ inputs.token }}
2538
- name: Find
2639
id: find
@@ -45,7 +58,7 @@ runs:
4558
- name: Save cached_findings
4659
uses: github/continuous-ai-for-accessibility-scanner/.github/actions/gh-cache/cache@main
4760
with:
48-
key: cached_findings-${{ github.ref_name }}
61+
key: ${{ steps.cache_key.outputs.cache_key }}
4962
value: ${{ steps.file.outputs.findings }}
5063
token: ${{ inputs.token }}
5164

0 commit comments

Comments
 (0)