Reusable GitHub Actions for the Tempo organization.
| Action | Description |
|---|---|
docker-login |
Log in to GHCR and optionally Docker Hub |
docker-build-push |
Build and push Docker images |
docker-metadata-tags |
Standard Tempo Docker tagging strategy |
cosign-sign |
Sign container images with cosign |
publish-event |
POST webhook events to downstream systems |
github-sts |
Exchange GitHub OIDC tokens for short-lived GitHub App tokens |
socket-firewall |
Install Socket Firewall with a short-lived, repository-scoped token |
create-pull-request |
Commit working-tree changes and open a PR |
pr-audit-comment |
Handle PR audit issue-comment commands |
setup-rust-build |
Install Rust toolchain, mold linker, and sccache |
setup-foundry |
Install Foundry toolchain |
setup-argo-cli |
Install Argo Workflows CLI |
scan-github-actions |
Security scan (zizmor) + lint (actionlint) for GitHub Actions workflows |
Reference actions using tempoxyz/gh-actions/actions/<name>@main (pin to a commit SHA in production — see Versioning):
steps:
- uses: tempoxyz/gh-actions/actions/setup-rust-build@main
with:
toolchain: stable
components: clippy,rustfmt
- uses: tempoxyz/gh-actions/actions/docker-login@main
with:
ghcr-token: ${{ secrets.GITHUB_TOKEN }}
- uses: tempoxyz/gh-actions/actions/publish-event@main
with:
url: ${{ secrets.EVENTS_ARGS }}
event-type: registry_package
tag: sha-${{ steps.shortsha.outputs.shortsha }}Examples in this repo use @main for brevity. For production, pin to a full commit SHA — branch refs like @main are mutable, and the bundled scan-github-actions workflow flags unpinned uses. Add a trailing reference comment; the optional pinact policy check requires one for bare SHA pins, and it also improves readability:
uses: tempoxyz/gh-actions/actions/setup-rust-build@<commit-sha> # mainThis repo does not yet publish version tags; SHA pinning is the recommended stable reference.
| Workflow | Description | Source |
|---|---|---|
pr-audit |
Publish a pr_audit event when a PR is labeled (read-only) |
tempo, zones |
label-prs |
Label new PRs from their linked issue | tempo, zones |
scan-github-actions |
Security scan, lint, and optional action pin policy checks | any |
reproducible-build |
Reproducible build verification | tempo |
rust-lint |
Shared Rust clippy, fmt, typos, and deny checks | rust repos |
rust-build-binaries |
Build Rust binaries and upload artifacts | rust repos |
cargo-update-pr |
Open a scheduled cargo update PR |
tempo |
auto-assign-pr |
Auto-assign the author to their PR | tempo |
Reference reusable workflows using tempoxyz/gh-actions/.github/workflows/<name>.yml@main (pin to a commit SHA in production — see Versioning).
Publishes a pr_audit event when a pull request receives a configured label. This reusable workflow is read-only (contents: read); comment-driven audit commands are handled separately by the pr-audit-comment composite action in a caller-owned job (see below).
name: PR Audit
on:
pull_request:
types: [labeled]
jobs:
pr-audit:
uses: tempoxyz/gh-actions/.github/workflows/pr-audit.yml@main
permissions:
contents: read
with:
environment: pr-audit
required-labels: |
cyclops
agentic-audit
secrets:
EVENTS_KEY: ${{ secrets.EVENTS_KEY }}
EVENTS_CERT: ${{ secrets.EVENTS_CERT }}
EVENTS_ARGS: ${{ secrets.EVENTS_ARGS }}Optional inputs:
required-label— label that triggers audit publishing (default:cyclops); kept for compatibilityrequired-labels— comma or newline-separated labels that trigger audit publishing; when set, this overridesrequired-labelenvironment— GitHub Environment name, such aspr-audit, used to gate audit publishingbranch/pr-number— target for ad-hocworkflow_dispatchcallersrequire-completed-audit— publish aCyclops audit runmerge-gate status (default:false)
When require-completed-audit: true, internal and non-Dependabot pull requests remain pending until tempoxyz-bot posts a completed Cyclops review; fork and Dependabot pull requests are exempt. Completed reviews remain valid after later commits. The caller must add pull_request_target, pull_request_review, and merge_group triggers, grant pull-requests: read and statuses: write, and require the resulting Cyclops audit run status on the protected branch. Reusable workflows cannot declare caller event triggers.
on:
pull_request:
types: [labeled]
pull_request_target: # zizmor: ignore[dangerous-triggers]
types: [opened, reopened, synchronize, labeled, unlabeled]
pull_request_review:
types: [submitted]
merge_group:
jobs:
pr-audit:
uses: tempoxyz/gh-actions/.github/workflows/pr-audit.yml@main
permissions:
contents: read
pull-requests: read
statuses: write
with:
require-completed-audit: true
secrets:
EVENTS_KEY: ${{ secrets.EVENTS_KEY }}
EVENTS_CERT: ${{ secrets.EVENTS_CERT }}
EVENTS_ARGS: ${{ secrets.EVENTS_ARGS }}Repos that need protected environment gates, such as Zones' environment: pr-audit gate for EVENTS_*, should pass environment: pr-audit so the publish job preserves that approval boundary.
Because comment handling needs issues: write and pull-requests: read, it lives in a caller-owned job that runs the pr-audit-comment composite action rather than in the read-only reusable workflow. Add it alongside the label job:
on:
pull_request:
types: [labeled]
issue_comment:
types: [created]
jobs:
pr-audit:
uses: tempoxyz/gh-actions/.github/workflows/pr-audit.yml@main
permissions:
contents: read
with:
environment: pr-audit
secrets:
EVENTS_KEY: ${{ secrets.EVENTS_KEY }}
EVENTS_CERT: ${{ secrets.EVENTS_CERT }}
EVENTS_ARGS: ${{ secrets.EVENTS_ARGS }}
pr-audit-comment:
if: >-
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
(
startsWith(github.event.comment.body, 'cyclops audit') ||
startsWith(github.event.comment.body, '@decofe cyclops audit') ||
startsWith(github.event.comment.body, 'derek audit')
)
runs-on: ubuntu-latest
environment: pr-audit
permissions:
contents: read
issues: write
pull-requests: read
steps:
- uses: tempoxyz/gh-actions/actions/pr-audit-comment@main
with:
command-regex: '^(?:@decofe\s+)?(?:cyclops\s+audit|derek\s+audit)\b'
permission-check-mode: association
allowed-associations: OWNER,MEMBER
organization: tempoxyz
events-key: ${{ secrets.EVENTS_KEY }}
events-cert: ${{ secrets.EVENTS_CERT }}
events-args: ${{ secrets.EVENTS_ARGS }}
github-token: ${{ github.token }}The comment surface supports:
- comments:
cyclops audit,@decofe cyclops audit,derek audit - arguments:
fast,perf,iterations=N,hours=N,config=PATH,models=...,run-label=LABEL,dry-run,note="..."
Set permission-check-mode: org (with organization) for org-membership API
checks. Use permission-token when those checks need a token distinct from the
one used for PR reads and status comments:
permission-check-mode: org
organization: tempoxyz
github-token: ${{ secrets.DEREK_BENCH_TOKEN }}
permission-token: ${{ secrets.DEREK_BENCH_ACK_TOKEN }}If permission-token is omitted, membership checks use github-token as
before. In association mode, allowed-associations controls which GitHub
commenter associations may trigger an audit. It defaults to
OWNER,MEMBER,COLLABORATOR. In both permission modes, authorization applies to
the commenter, not the pull request author, so a trusted commenter can audit a
pull request from an external fork. allow-same-author is deprecated, has no
effect, and remains accepted only for compatibility with existing callers.
Labels newly opened pull requests by copying eligible labels from the issue linked in the pull request body.
name: Label PRs
on:
pull_request:
types: [opened]
jobs:
label-prs:
uses: tempoxyz/gh-actions/.github/workflows/label-prs.yml@main
permissions:
contents: read
issues: writeCaller workflows must grant these permissions on the reusable-workflow job. contents: read is needed to check out tempoxyz/gh-actions; issues: write reads issue labels and adds labels to the pull request through GitHub's Issues API.
The reusable workflow checks out tempoxyz/gh-actions at github.workflow_sha, so the bundled label script matches the pinned reusable workflow revision.
Security scan and lint for GitHub Actions workflows: zizmor for security and actionlint (with shellcheck/pyflakes) for workflow syntax and run: script correctness. Findings appear as GitHub workflow annotations and in the workflow log. The lint pass can be turned off with actionlint: false.
Set pinact: true to also run pinact in check-only mode. This enforces a default seven-day minimum age for pinned action commits and adds optional version-comment verification without editing files or adding a second reusable-workflow job. Caller-local Pinact configuration is merged on top of the trusted default source and can override its threshold, so repository configuration remains review-sensitive. Existing callers remain unchanged because the pinact check is opt-in.
zizmor, actionlint, and the optional pinact policy run together in a single Scan GitHub Actions check. The reusable workflow is read-only (actions: read, contents: read) and never requests security-events: write, so callers only grant read scopes. To upload SARIF to GitHub code scanning, use the composite action with advanced-security: true in a job you control (see its README).
name: Scan GitHub Actions
on:
push:
branches: [main]
pull_request:
jobs:
scan:
uses: tempoxyz/gh-actions/.github/workflows/scan-github-actions.yml@main
permissions:
actions: read
contents: read
with:
pinact: trueBy default zizmor scans the whole repo, so first-party workflows and actions anywhere (e.g. across a monorepo) are covered. Repos that vendor third-party workflows/actions can narrow zizmor's scope with the paths input (e.g. to .github/) to avoid flagging code they don't own. Pinact uses its own file discovery; monorepos with action manifests outside its defaults can set files in their Pinact configuration.
Optional inputs:
paths(default:.) — whitespace-separated paths for zizmor to scan; narrow to e.g..github/to exclude vendored or third-party treesconfig— path to a zizmor config file for rule overridesactionlint(default:true) — run actionlint (syntax, expression, and shellcheck/pyflakes checks) alongside the zizmor scanpinact(default:false) — run pinact policy checks alongside zizmor and actionlintpin-config(default:.pinact.yaml) — path to the caller repo's pinact configuration file; the default is optional when absentpin-no-api(default:false) — perform offline pin validation without API-based comment or minimum-age verificationverify-pin-comments(default:false) — verify that semver version comments resolve to the pinned SHAverify-pin-min-age(default:true) — verify current pins against configured minimum-age rulespin-min-age(default:7) — default minimum age in days for pinned action commits; caller-local Pinact configuration can override it
Builds a repository's byte-deterministic binary using scripts/reproducible-build.sh, writes a sha256 file, and uploads it as a short-lived artifact.
name: Reproducible Build
permissions: {}
on:
push:
branches: [main]
workflow_dispatch:
inputs:
ref:
description: "Git ref (branch, tag, or full SHA) to build reproducibly"
type: string
required: false
default: "main"
concurrency:
group: reproducible-build-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: ${{ github.event_name == 'push' }}
jobs:
build:
uses: tempoxyz/gh-actions/.github/workflows/reproducible-build.yml@main
permissions:
contents: read
with:
ref: ${{ inputs.ref }}
binary-name: tempoCaller workflows must grant contents: read on the reusable-workflow job so it can check out the repository being built.
Required input:
binary-name— name of the binary produced inout/
Optional inputs:
ref— Git ref to check outtarget(default:x86_64-unknown-linux-gnu)build-script(default:./scripts/reproducible-build.sh)runs-on(default:depot-ubuntu-latest-16)retention-days(default:7)
Runs a common Rust lint set: cargo clippy, cargo fmt, typos, and cargo deny.
name: Lint
on:
push:
branches: [main]
pull_request:
merge_group:
permissions: {}
jobs:
lint:
uses: tempoxyz/gh-actions/.github/workflows/rust-lint.yml@main
permissions:
contents: readOptional inputs:
rust-toolchain(default:nightly) — used for clippy and fmtclippy-flags(default:--all-targets --all-features --locked)fmt-flags(default:--all --check)deny-flags(default:--all-features)checkout-submodules(default:false) — passed to clippy checkout onlyclippy-runner,fmt-runner,typos-runner,deny-runner,timeout-minutes
Builds one or more Rust binaries with cargo build --bin <binary> --profile <profile> and uploads each binary as an artifact.
name: Build binaries
on:
workflow_dispatch:
permissions: {}
jobs:
build:
uses: tempoxyz/gh-actions/.github/workflows/rust-build-binaries.yml@main
permissions:
contents: read
with:
profile: release
binaries: |
api-server
worker
cliRequired input:
binaries— newline-separated binary names to build and uploadprofile— Cargo build profile
Optional inputs:
rust-toolchain(default:stable)runs-on(default:depot-ubuntu-latest-16)checkout-submodules(default:false)artifact-path-template(default:target/{profile}/{binary})retention-days(default:7)timeout-minutes(default:60)
Runs cargo update and opens or updates a pull request for Cargo.lock. The
branch push and PR use a short-lived GitHub App token minted via
github-sts — the built-in GITHUB_TOKEN is not
allowed to create pull requests.
jobs:
cargo-update-pr:
uses: tempoxyz/gh-actions/.github/workflows/cargo-update-pr.yml@main
permissions:
contents: read
id-token: writeThe calling repository must carry a trust policy at
.github/sts/cargo-update-pr.sts.yaml that grants its own workflow
contents: write and pull_requests: write, for example:
subject: repo:tempoxyz@<org-id>/<repo>@<repo-id>:ref:refs/heads/main
permissions:
contents: write
pull_requests: writeOptional inputs:
rust-toolchain(default:nightly)title(default:chore(deps): weekly cargo update)
Assigns newly opened or reopened pull requests to their author when the author is an internal collaborator.
name: Auto Assign PR to Author
on:
pull_request:
types: [opened, reopened]
permissions:
issues: write
pull-requests: write
jobs:
auto-assign:
uses: tempoxyz/gh-actions/.github/workflows/auto-assign-pr.yml@mainCaller workflows must grant issues: write and pull-requests: write.