Repository navigation
feat: run-script AWS role, SSH key and uv cache, and fix its pre-commit cache - #7
Conversation
### what Add three optional parameters to the `run-script` workflow: - `aws-role` (input): an AWS role to assume through GitHub OIDC with `aws-actions/configure-aws-credentials` before the script runs. `aws-region` (input, default `us-east-1`) sets its region. - `SSH_PRIVATE_KEY` (secret): an SSH key for the script, written to `~/.ssh/run-script-key` and named in `~/.ssh/config`, for example a deploy key pre-commit needs to clone a private hook repository. The workflow no longer sets permissions of its own, so its job runs with exactly what the caller grants. OIDC needs `id-token: write`, and a called workflow can't be granted more than its caller has, so requesting it here would likely fail every caller that doesn't grant it. Existing callers already grant `contents: read`, so they run as before. ### why Jobs that install a project's dependencies from a private registry, or whose pre-commit hooks come from a private repository, can't use `run-script` today. Platform's Lint job needs both: AWS credentials for CodeArtifact and the pre-commit deploy key. ### testing actionlint, zizmor, ruff and codespell pass (`prek run --all-files`). zizmor accepts the job without a permissions block. This repository's own CI runs on `run-script`, so it exercises the permissions change; the AWS and SSH steps run only once a caller passes them. ### docs The README's `run-script` section covers both new parameters, the permissions a caller must grant, and an example caller. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ache ### what - Add a `uv-cache` input (default false) that restores uv's cache on every run, falling back to the newest one when `uv.lock` moved, and prunes it with `uv cache prune --ci` and saves it off pull requests. - Key the pre-commit cache on the mise config and lockfiles and the selected `mise-env` as well as `.pre-commit-config.yaml`. - Export `PREK_HOME` from `$HOME` in the script instead of setting it in the step's `env:`. ### why Hook environments are built with the toolchains mise installs, so a Python bump restored environments built against the old interpreter. `PREK_HOME` was the literal string `~/.cache/pre-commit`, since `env:` values don't expand `~`, so prek wrote its environments to a `~` directory in the checkout and the cache step saved an empty one. ### testing actionlint, zizmor, ruff and codespell pass (`prek run --all-files`). This repository's CI uses `pre-commit-cache`, so it exercises the new key and `PREK_HOME`. ### docs The README's `run-script` section describes both caches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 2 files
Confidence score: 3/5
- In
.github/workflows/run-script.yml, removing the permission cap can expose a write-scoped token asGH_TOKENwhengithub-tokenis enabled. Keep the cap or otherwise ensure the exposed token is limited to read access.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".github/workflows/run-script.yml">
<violation number="1" location=".github/workflows/run-script.yml:32">
P2: Custom agent: **Flag Security Vulnerabilities**
Removing this cap lets a caller with write-enabled defaults expose a write-scoped token as `GH_TOKEN` when `github-token` is enabled, despite the input describing it as read-only. Keep the script’s token read-only, including when adding optional OIDC permissions.</violation>
</file>
Architecture diagram
sequenceDiagram
participant Caller as Caller Workflow
participant RS as run-script Workflow
participant GH as GitHub Actions Runtime
participant AWS as AWS (CodeArtifact)
participant SSH as SSH Deploy Key
participant Mise as mise-action
participant PreCache as pre-commit Cache
participant UvCache as uv Cache
participant Script as User Script (prek)
Note over Caller,RS: Caller grants permissions (contents:read, optional id-token:write)
Caller->>RS: Trigger workflow with inputs & secrets
Note over RS: No permissions block - inherits caller's grants
RS->>GH: Checkout repository (fetch-depth based on full-git-history)
alt aws-role provided
RS->>AWS: configure-aws-credentials via OIDC
Note over RS,AWS: Assumes role in aws-region (default us-east-1)
AWS-->>RS: Temporary credentials
end
alt SSH_PRIVATE_KEY secret provided
RS->>RS: Install SSH key to ~/.ssh/run-script-key
RS->>RS: Configure ~/.ssh/config with IdentityFile
end
RS->>Mise: Install toolchains (mise-action with cache)
Mise-->>RS: Toolchains ready
opt pre-commit-cache enabled
RS->>PreCache: Restore cache
Note over RS,PreCache: Key includes .pre-commit-config.yaml, mise config files, mise-env, runner OS/arch
PreCache-->>RS: Cache hit or miss
end
opt uv-cache enabled
RS->>UvCache: Restore cache
Note over RS,UvCache: Key based on uv.lock, falls back to newest by runner OS/arch
UvCache-->>RS: Cache hit or miss
end
RS->>Script: Run user script
Note over Script: PREK_HOME exported as $HOME/.cache/pre-commit
Note over Script: GH_TOKEN unset if empty
alt post-run on non-PR event with cache miss
opt pre-commit-cache enabled
RS->>PreCache: Save cache (pruned/updated hook environments)
end
opt uv-cache enabled
RS->>RS: Run "uv cache prune --ci" (drop pre-built wheels)
RS->>UvCache: Save pruned cache
end
end
Note over RS: Cache saves gated off pull requests to prevent cache poisoning
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| jobs: | ||
| run: | ||
| runs-on: ubuntu-latest | ||
| permissions: |
There was a problem hiding this comment.
P2: Custom agent: Flag Security Vulnerabilities
Removing this cap lets a caller with write-enabled defaults expose a write-scoped token as GH_TOKEN when github-token is enabled, despite the input describing it as read-only. Keep the script’s token read-only, including when adding optional OIDC permissions.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At .github/workflows/run-script.yml, line 32:
<comment>Removing this cap lets a caller with write-enabled defaults expose a write-scoped token as `GH_TOKEN` when `github-token` is enabled, despite the input describing it as read-only. Keep the script’s token read-only, including when adding optional OIDC permissions.</comment>
<file context>
@@ -22,17 +26,30 @@ on:
+ 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
</file context>
There was a problem hiding this comment.
Removing this is required for callers to be able to pass the required permissions (based on which features are enabled).
This is only an issue in case where a third party component (script, library, pre-commit hook) are compromised in a way that they extract secrets (like the GH token).
A third-party PR from a fork on a public repo won't run into this issue.
A trusted run can fill the pre-commit and uv caches with private packages or clones of private hook repositories, which a fork's script could read. Skip restoring them for pull requests from forks of a public repository. Also stop calling the github-token token read-only: the job takes the caller's permissions, so the caller's grant is the only cap on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
what
Add four optional parameters to the
run-scriptworkflow:aws-role(input): an AWS role to assume through GitHub OIDC withaws-actions/configure-aws-credentialsbefore the script runs.aws-region(input, defaultus-east-1) sets its region.SSH_PRIVATE_KEY(secret): an SSH key for the script, written to~/.ssh/run-script-keyand named in~/.ssh/config, for example a deploykey pre-commit needs to clone a private hook repository.
uv-cache(input, default false): restores uv's cache, falling back to thenewest one when
uv.lockmoved, and prunes it withuv cache prune --ciand saves it off pull requests.
Neither cache is restored for pull requests from forks of a public
repository. A trusted run may have filled them with private packages or
clones of private hook repositories, which the fork's script could read.
Forks of a private repository belong to people who can already read it, so
those still restore.
It also fixes the pre-commit cache. The key now covers the mise config and
lockfiles and the selected
mise-envas well as.pre-commit-config.yaml,and
PREK_HOMEis exported from$HOMEin the script instead of set in thestep's
env:.The workflow no longer sets permissions of its own, so its job runs with
exactly what the caller grants. OIDC needs
id-token: write, and a calledworkflow can't be granted more than its caller has, so requesting it here
would likely fail every caller that doesn't grant it. Existing callers
already grant
contents: read, so they run as before. The caller's grantis now the only cap on the token
github-tokenexposes, so the input nolonger calls it read-only, and the README says to grant nothing beyond
contents: read(plusid-token: writeforaws-role).why
Jobs that install a project's dependencies from a private registry, or
whose pre-commit hooks come from a private repository, can't use
run-scripttoday. Platform's Lint job needs both: AWS credentials forCodeArtifact and the pre-commit deploy key. Installing its dependencies
on every run is also slow without uv's cache.
Hook environments are built with the toolchains mise installs, so a Python
bump restored environments built against the old interpreter.
PREK_HOMEwas the literal string
~/.cache/pre-commit, sinceenv:values don'texpand
~, so prek wrote its environments to a~directory in thecheckout and the cache step saved an empty one.
testing
actionlint, zizmor, ruff and codespell pass (
prek run --all-files).zizmor accepts the job without a permissions block. This repository's own
CI runs on
run-scriptwithpre-commit-cache, so it exercises thepermissions change, the new pre-commit key and
PREK_HOME. The AWS, SSH anduv cache steps run only once a caller passes them, and the fork check only
on a fork's pull request.
docs
The README's
run-scriptsection covers the new parameters, both cachesand when they're skipped, the permissions a caller must grant, and an
example caller.
🤖 Generated with Claude Code