Repository navigation
159 lines (149 loc) · 7.24 KB
/
Copy pathrun-script.yml
File metadata and controls
159 lines (149 loc) · 7.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
name: "Run script"
on:
workflow_call:
inputs:
run:
description: "Script for the run step"
type: string
required: true
pre-commit-cache:
description: "Restore the pre-commit cache, saving it on non-PR events"
type: boolean
default: false
uv-cache:
description: "Restore uv's cache, saving it on non-PR events"
type: boolean
default: false
full-git-history:
type: boolean
description: "Whether to fetch full git history rather than just current HEAD"
default: false
github-token:
type: boolean
description: "Expose the job's GitHub token to the script as GH_TOKEN. It carries whatever permissions the caller grants, so grant only what the script needs"
default: false
mise-env:
type: string
description: "Value for MISE_ENV, selecting additional mise.<env>.toml config files"
default: ""
aws-role:
type: string
description: "ARN of an AWS role to assume through GitHub OIDC before the script runs. The caller must grant id-token: write"
default: ""
aws-region:
type: string
description: "AWS region for the credentials aws-role yields"
default: "us-east-1"
secrets:
STEP_SECURITY_API_KEY:
required: false
SSH_PRIVATE_KEY:
description: "SSH private key to install for the script, e.g. a deploy key for cloning a private repository"
required: false
# No permissions here: the job takes exactly what the caller grants. That is
# contents: read for most callers, plus id-token: write for those passing
# aws-role. A called workflow cannot be granted more than its caller has, and
# asking for id-token: write here would fail every caller that doesn't grant it.
# The caller's grant is therefore the only cap on the token github-token
# exposes, so callers must grant no more than contents: read (and id-token).
jobs:
run:
runs-on: ubuntu-latest
env:
HARDEN_RUNNER: ${{ secrets.STEP_SECURITY_API_KEY != '' }} # zizmor: ignore[secrets-outside-env]
SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY != '' }} # zizmor: ignore[secrets-outside-env]
MISE_ENV: ${{ inputs.mise-env }}
MISE_LOCKED: "1"
steps:
- name: Harden Runner
if: env.HARDEN_RUNNER == 'true'
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with:
use-policy-store: true
api-key: ${{ secrets.STEP_SECURITY_API_KEY }} # zizmor: ignore[secrets-outside-env]
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: ${{ inputs.full-git-history && '0' || '1' }}
- name: Configure AWS credentials
if: inputs.aws-role != ''
uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0
with:
role-to-assume: ${{ inputs.aws-role }}
aws-region: ${{ inputs.aws-region }}
# The runner's known_hosts already covers github.com. The key goes in a
# file of its own, named in ~/.ssh/config, so it works whatever its type.
- name: Install SSH key
if: env.SSH_KEY == 'true'
run: |
umask 077
mkdir -p ~/.ssh
printf '%s\n' "$SSH_PRIVATE_KEY" > ~/.ssh/run-script-key
printf 'Host *\n IdentityFile ~/.ssh/run-script-key\n' >> ~/.ssh/config
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env]
- name: Install mise
uses: jdx/mise-action@7a4e45a543138629540c9a1616d08632b893e492 # v5.0.1
with:
minimum_release_age: 7d
cache: true
# Caches are restored on every run except pull requests from forks of a
# public repository: a trusted run may have filled them with private
# artifacts (packages from a private registry, clones of private hook
# repositories), which an outsider's script could read and exfiltrate.
# Forks of a private repository belong to people who can already read it.
#
# Hook environments are built with the toolchains mise installs (Python,
# Node, ...), so the key covers the mise config and lockfiles and the
# selected environment as well as the hook pins: a toolchain bump must
# not restore environments built against the old one.
- name: Restore pre-commit cache
if: inputs.pre-commit-cache && !(github.event.pull_request.head.repo.fork && !github.event.repository.private)
id: pre-commit-cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ runner.os }}-${{ runner.arch }}-${{ inputs.mise-env }}-${{ hashFiles('.pre-commit-config.yaml', 'mise.toml', 'mise.lock', 'mise.*.toml', 'mise.*.lock') }}
# uv verifies what it installs against uv.lock's hashes, so a stale entry
# only costs a download; restore the newest cache when the lock moved.
- name: Restore uv cache
if: inputs.uv-cache && !(github.event.pull_request.head.repo.fork && !github.event.repository.private)
id: uv-cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/uv
key: uv-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('uv.lock') }}
restore-keys: |
uv-${{ runner.os }}-${{ runner.arch }}-
- name: Run
# Some tools reject an empty GH_TOKEN (e.g. zizmor), so unset it rather
# than leaving it empty.
run: | # zizmor: ignore[template-injection] caller-provided script
[ -n "$GH_TOKEN" ] || unset GH_TOKEN
# Point prek at the pre-commit cache path so the cache step covers
# both. Exported here because `env:` values don't expand `~`.
export PREK_HOME="$HOME/.cache/pre-commit"
${{ inputs.run }}
env:
GH_TOKEN: ${{ inputs.github-token && github.token || '' }}
# Cache saves are gated to non-PR events: an untrusted PR run must not be
# able to write a cache that a later trusted build restores and executes
# (cache poisoning).
- name: Save pre-commit cache
if: inputs.pre-commit-cache && github.event_name != 'pull_request' && steps.pre-commit-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/pre-commit
key: ${{ steps.pre-commit-cache.outputs.cache-primary-key }}
# Keep only what's slow to rebuild: --ci drops pre-built wheels, which
# download again quickly, and keeps wheels built from source.
- name: Prune uv cache
if: inputs.uv-cache && github.event_name != 'pull_request' && steps.uv-cache.outputs.cache-hit != 'true'
run: uv cache prune --ci
- name: Save uv cache
if: inputs.uv-cache && github.event_name != 'pull_request' && steps.uv-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/uv
key: ${{ steps.uv-cache.outputs.cache-primary-key }}