Action reference¶
Generated by scripts/gen_action_reference.py. Edit action.yml, not this page.
For the task-shaped version, see Setup.
Targets¶
target is the only required input and it has no default. Everything else is
optional, and every one of them is checked against the target you picked: an input
that belongs to another target is a hard error naming both, before the checkout.
| Target | What it does |
|---|---|
github-pages |
Build an MkDocs site strictly and publish it to GitHub Pages |
cloudflare-docs |
Build an MkDocs site strictly and publish it to Workers Static Assets |
s3-cloudfront |
Sync a built static site to S3, invalidate CloudFront |
lambda-zip |
Publish a Lambda package to S3, update the function, move an alias |
terragrunt |
Discover, plan and (on an approval) apply Terragrunt stacks |
ansible |
Run a playbook over SSH, then prove it is idempotent |
cloudflare-workers |
Deploy a Worker and its static assets with Wrangler |
azure-functions-zip |
Publish a zip to an Azure Function App, then wait for it to answer |
Inputs¶
MagmaMoose/tremvok@v2 takes 120 inputs. target is the only one that
is required.
| Input | Applies to | Default | Description |
|---|---|---|---|
target |
the selector | not set | The deployment target. One of: github-pages Build an MkDocs site strictly and publish it to GitHub Pages. s3-cloudfront Sync a built static site to S3 and invalidate CloudFront. lambda-zip Publish a Lambda package to S3, update the function, move an alias. terragrunt Discover, plan and (on an approval) apply Terragrunt stacks. ansible Run an Ansible playbook over SSH, then prove it is idempotent. cloudflare-workers Deploy a Worker and its static assets with Wrangler. cloudflare-docs Build an MkDocs site strictly and publish it to Cloudflare Workers Static Assets, behind the docs router. azure-functions-zip Publish a zip to an Azure Function App, then wait for it to answer. |
mode |
all | auto |
What this run should do. One of: auto (default) push to the default branch = deploy, pull_request = preview, workflow_dispatch = deploy (pinned to the default branch). deploy Publish to the environment. preview Publish somewhere disposable; production is untouched. rollback Re-publish a previously published version. |
environment |
all | not set | Logical environment name, surfaced in notifications and the deployment record. Defaults to "production" (deploy) or "preview". |
working-directory |
all | . |
Directory to run in. Paths in the other inputs are relative to it. |
checkout |
all | true |
Run actions/checkout first. Set false if the caller already checked out. |
dry-run |
all | false |
Resolve, plan and report without changing anything. |
aws-region |
s3-cloudfront, lambda-zip, terragrunt |
not set | s3-cloudfront, lambda-zip, terragrunt: AWS region. Falls back to the AWS_REGION environment variable. |
aws-role-to-assume |
s3-cloudfront, lambda-zip, terragrunt |
not set | s3-cloudfront, lambda-zip, terragrunt: IAM role ARN to assume with this run's GitHub OIDC token. Strongly preferred over stored keys: the credential expires in an hour and the role's trust policy decides which repository and ref may use it. Requires permissions: id-token: write. Leave empty to use credentials an earlier step already configured. |
aws-role-duration-seconds |
s3-cloudfront, lambda-zip, terragrunt |
3600 |
s3-cloudfront, lambda-zip, terragrunt: lifetime of the assumed-role session. |
azure-client-id |
terragrunt, azure-functions-zip |
not set | terragrunt, azure-functions-zip: client id of the Entra ID app registration this run signs in as, using the run's GitHub OIDC token. The Azure counterpart of aws-role-to-assume, and preferred over a stored publish profile or client secret for the same reasons: the session is minted per run and expires, and the app registration's federated credential decides which repository and which ref may mint one. A publish profile is a long-lived file carrying the deployment rights of the whole site, tied to nothing. Requires permissions: id-token: write. Leave empty to use a session an earlier step created. On terragrunt this is the PROVIDER's credential and has nothing to do with the state backend's, which terragrunt-stack-env carries. provider "azurerm" with no explicit auth falls through its default chain to the Azure CLI, so a run with a perfectly good ARM_ACCESS_KEY still fails at plan on a runner nobody signed in. |
azure-tenant-id |
terragrunt, azure-functions-zip |
not set | terragrunt, azure-functions-zip: Entra ID tenant the app registration lives in. Required whenever azure-client-id is set. |
azure-subscription-id |
terragrunt, azure-functions-zip |
not set | terragrunt, azure-functions-zip: subscription to select after login. Required whenever azure-client-id is set. On terragrunt it is the CLI default a stack inherits when its own provider block names no subscription. |
gcp-workload-identity-provider |
terragrunt |
not set | terragrunt: full resource name of the workload identity pool provider this run federates with, projects/<number>/locations/global/workloadIdentityPools/<pool>/providers/<provider>. The Google counterpart of aws-role-to-assume and azure-client-id, and preferred over a downloaded service-account key for the same reasons: the credential is minted per run and expires, and the pool provider's attribute condition decides which repository and which ref may mint one. A service-account key is a long-lived file, valid until somebody deletes it, tied to nothing. Requires permissions: id-token: write. Leave empty to use credentials an earlier step created. On terragrunt this is the PROVIDER's credential. If your state lives in GCS the backend needs one too, and the same federated credentials serve both. |
gcp-service-account |
terragrunt |
not set | terragrunt: service account to impersonate after federating, name@project.iam.gserviceaccount.com. Empty (default) uses the federated identity directly, which works when the IAM bindings name the pool's principalSet rather than a service account. Set, the pool's principalSet needs roles/iam.workloadIdentityUser on it. |
gcp-project-id |
terragrunt |
not set | terragrunt: project exported as GOOGLE_PROJECT and GOOGLE_CLOUD_PROJECT, for configurations that do not name one themselves. Optional. |
pages-toolchain |
github-pages, cloudflare-docs |
auto |
github-pages, cloudflare-docs: how to install MkDocs, auto (default) | uv | pip. auto picks uv when a uv.lock is present, otherwise pip against pages-requirements. Detection exists so a caller does not have to declare per-repo what is already visible in the repo. |
pages-dependency-group |
github-pages, cloudflare-docs |
docs |
github-pages, cloudflare-docs: uv dependency-group holding the docs tooling (uv toolchain only). |
pages-requirements |
github-pages, cloudflare-docs |
docs/requirements.txt |
github-pages, cloudflare-docs: requirements file pinning the docs build (pip toolchain only). |
pages-python-version |
github-pages, cloudflare-docs |
3.12 |
github-pages, cloudflare-docs: Python version used to build the site. |
pages-strict |
github-pages, cloudflare-docs |
true |
github-pages, cloudflare-docs: build with --strict, so a broken internal link or a nav entry pointing at a missing file fails rather than publishing a site with holes in it. |
pages-site-dir |
github-pages, cloudflare-docs |
site |
github-pages, cloudflare-docs: directory the built site is written to. |
pages-lint |
github-pages, cloudflare-docs |
true |
github-pages, cloudflare-docs: run the repo-shape checks (README budget and section order, licence agreement, link targets, Marketplace preflight, INHERIT clobber) before building. These are the rules nothing else covers; --strict already catches broken internal links. |
pages-profile |
github-pages, cloudflare-docs |
auto |
github-pages, cloudflare-docs: repo profile for the shape checks, auto | action | service | spec. |
pages-readme-budget |
github-pages, cloudflare-docs |
0 |
github-pages, cloudflare-docs: override the README line budget. 0 uses the profile default. |
pages-markdownlint |
github-pages, cloudflare-docs |
true |
github-pages, cloudflare-docs: run markdownlint-cli2 over docs/ and README.md when a markdownlint config is present. Runs here rather than under MegaLinter because MegaLinter's security flavor carries no markdown linter, and MARKDOWN_MARKDOWNLINT emits no SARIF, so it could never gate on net-new findings anyway. |
pages-seo |
github-pages, cloudflare-docs |
true |
github-pages, cloudflare-docs: after the build, give every page its own meta description (from its first paragraph of prose; the home page keeps site_description), Open Graph and Twitter tags, a JSON-LD graph (WebSite, TechArticle, BreadcrumbList) and a markdown copy at <page>/index.md, linked from the page and from llms.txt. Configured by extra.seo in mkdocs.yml (locale, image, publisher, author, twitter), every key optional. A tag a page already carries is never replaced or doubled, so a site with its own SEO hook keeps it. false skips the step. |
build-git-credentials |
github-pages, cloudflare-workers, cloudflare-docs |
not set | github-pages, cloudflare-workers, cloudflare-docs: credentials for the private git hosts the build fetches from, one <host> <username>:<token> per line. Empty (default) changes nothing. git.example.invalid x-access-token:<a short-lived token> A docs build that installs its theme with pkg @ git+https://<host>/<org>/<repo>.git@<tag> needs that clone authenticated, and the clone is git's own, several processes below this action. Each line becomes one url.<credentialled>.insteadOf rewrite carried in GIT_CONFIG_COUNT / GIT_CONFIG_KEY_n / GIT_CONFIG_VALUE_n for the rest of this job, so the requirements file keeps pinning the plain URL and stays reviewable. Never git config --global: a self-hosted runner is shared and long-lived, and a global rewrite would leave the token in ~/.gitconfig for whatever runs on that machine next. The username is written out rather than assumed, because the forges disagree about it: x-access-token for a GitHub App token, oauth2 for a GitLab one. The split is at the FIRST :, which is the safe way round — the username is the half that cannot contain one, so a token that does survives intact. Every token is masked on receipt and never echoed. A malformed line is refused by index and host, and the host is only quoted when it looks like one, because a bare token pasted as a line would otherwise be printed into an annotation as public as the repository. Blank lines and # comments are ignored. |
artifact-path |
s3-cloudfront, lambda-zip, cloudflare-workers, azure-functions-zip |
not set | s3-cloudfront, lambda-zip, cloudflare-workers, azure-functions-zip: the built artifact, a directory for s3-cloudfront, a .zip for lambda-zip and azure-functions-zip. |
s3-bucket |
s3-cloudfront, lambda-zip |
not set | s3-cloudfront, lambda-zip: the bucket. For s3-cloudfront it serves the site; for lambda-zip it holds published artifacts. |
s3-key-prefix |
s3-cloudfront, lambda-zip |
not set | s3-cloudfront, lambda-zip: key prefix within the bucket. Previews are placed under <s3-key-prefix>/previews/<alias>/. |
s3-delete-orphans |
s3-cloudfront |
auto |
s3-cloudfront: pass --delete to aws s3 sync, removing bucket objects with no local counterpart. auto (default) means yes. |
cloudfront-distribution-id |
s3-cloudfront |
not set | s3-cloudfront: CloudFront distribution to invalidate after the sync. Empty means no invalidation, the CDN keeps serving the old objects until its TTL expires. |
cloudfront-site-url |
s3-cloudfront |
not set | s3-cloudfront: base URL the distribution serves, used to build the URL reported in notifications. |
lambda-function-name |
lambda-zip |
not set | lambda-zip: the function to update. |
lambda-function-alias |
lambda-zip |
live |
lambda-zip: the alias moved to the new version in deploy mode. A preview publishes a version and does not move it. |
lambda-version-label |
lambda-zip |
not set | lambda-zip: names the immutable S3 key (<s3-key-prefix>/<lambda-version-label>.zip). Defaults to the short commit SHA. |
terragrunt-root |
terragrunt |
terraform |
terragrunt: directory the stacks live under. |
terragrunt-exclude |
terragrunt |
modules _modules |
terragrunt: space-separated path segments that never hold a stack. modules _modules by default: a module has no state of its own, and guessing which stacks use it from a path is how a small module tidy-up ends up planning the whole estate. Add a stack that must only ever be applied by hand, one that rewrites a firewall wholesale, say, and the pipeline will not touch it. |
terragrunt-scope |
terragrunt |
auto |
terragrunt: auto (changed stacks on a PR/push, all on a schedule or dispatch), all, or changed. With terragrunt-pull-request set, auto means the stacks that pull request touches even on a manual run; all stays legal and means plan the whole estate, gate on that pull request's approval, comment on that pull request. |
terragrunt-pull-request |
terragrunt |
not set | terragrunt: act on this pull request number instead of the one in the event payload. For a manual run that has to plan a named pull request. Its reviews are what the approval gate reads, its thread is where the plan comment goes, and its head commit is what the check run is published against, fetched from the API because a dispatch event carries no pull request. Empty (default) uses the event, which is every automatic run. Digits only. A manual run plans: dispatching a workflow is not approving a commit, so terragrunt-apply: force is what applies one by hand. Checking out the right tree stays yours: pass ref: refs/pull/<n>/merge to your own actions/checkout step and set checkout: false here, or the run plans whatever is on disk and says so. |
terragrunt-apply |
terragrunt |
auto |
terragrunt: auto (apply on an independent approval), never (plan only), or force. Under auto the run must also be the event that asks for an apply: a pull-request review that is an approval, or a push with terragrunt-apply-on-merge on. A run that only finds an approval already standing plans and reports, because that approval was given for the commit it was given for and a commit pushed after it has not been reviewed. Re-approving applies. force skips the approval and is restricted to terragrunt-apply-operators. |
terragrunt-apply-on-merge |
terragrunt |
false |
terragrunt: true lets a push to the default branch apply what was merged. false (the default) plans on a push and applies nothing, which is what this target has always done. A push event carries no pull request, so with this on the run asks the API which pull request the commit was merged from and reads that pull request's reviews: a merge that had an independent approval applies, a merge without one is reported and not applied. Off, none of that happens: no commit-to-pull-request lookup, no approval read, plan only. Separate from terragrunt-apply on purpose. That input answers "who may authorise an apply?"; this one answers "should a merge commit apply at all?". Stacking the two questions into one enum makes both harder to read. |
terragrunt-apply-operators |
terragrunt |
not set | terragrunt: comma-separated GitHub logins allowed to force an apply by hand (terragrunt-apply: force on a manual run). Empty means nobody can, so the manual path fails closed. The normal path is an independent pull-request approval and needs nothing here. |
terragrunt-stack-env |
terragrunt |
not set | terragrunt: environment applied per stack, one <glob> KEY=VALUE per line. The first matching line wins for a given KEY, so a specific pattern goes above the catch-all exactly as it would in a case. Blank lines and # comments are ignored. */prd/*|*/prod/* ARM_ACCESS_KEY=<the production state key> * ARM_ACCESS_KEY=<the shared state key> For an estate whose production state lives in a separate account from the rest, which is a deliberate blast-radius boundary rather than an accident: one credential cannot reach both, and without this the only options are a job per credential class or a pipeline that fails on the first stack of the other kind. The values are secrets, so they are passed to each run with env rather than exported into the shell, and one stack's credential never reaches the next stack's run. A malformed line is refused by index, glob and KEY: nothing at or after the first = is ever printed, because the annotation it would appear in is as public as the repository. |
terragrunt-check-name |
terragrunt |
Terragrunt apply |
terragrunt: name of the check run published against the head commit. Make it a required check to enforce apply-before-merge. |
terragrunt-install |
terragrunt |
auto |
terragrunt: install pinned, checksum-verified tofu and terragrunt binaries before running, auto (default) installs only what is not already on PATH, always reinstalls, never uses whatever the runner provides. The download is cached per version pair, so a bump lands in a new directory and can never pick up a stale binary. |
terragrunt-version |
terragrunt |
1.0.8 |
terragrunt: the Terragrunt version to install and run. |
terragrunt-tofu-version |
terragrunt |
1.12.1 |
terragrunt: the OpenTofu version to install and run under Terragrunt. |
terragrunt-plugin-cache |
terragrunt |
~/.terraform-plugin-cache |
terragrunt: directory to persist provider plugins in across stacks and runs, exported as TF_PLUGIN_CACHE_DIR. The workspace is wiped on each checkout, so without it every stack re-downloads every provider, the single biggest cost in a multi-stack run. Empty disables the cache. |
terragrunt-refresh |
terragrunt |
auto |
terragrunt: refresh state from the provider before planning, auto (default) skips the refresh on a pull request and keeps it everywhere else, true always refreshes, false never does. Config-versus-state is enough for a pull-request check; the scheduled drift run is the one that has to ask the provider. |
terragrunt-timeout |
terragrunt |
900 |
terragrunt: seconds any one init, plan or apply may take before it is killed. 0 disables the timeout. A stalled provider call otherwise looks like a silent hang until the job limit. |
terragrunt-preflight-urls |
terragrunt |
not set | terragrunt: URLs to probe for reachability before the first plan, one per line. Empty (default) probes nothing. Terragrunt buffers plan output to a file, so a state backend or provider API the runner cannot reach is a silent wait until terragrunt-timeout rather than an error. One 8-second request per URL turns that into a red step naming the endpoint. https://<your-state-backend-host>/?comp=list https://<your-provider-api-host>/api/versions The rules worth knowing before you read a result: a code of 000 (DNS, connect, TLS or timeout) fails the run; any HTTP answer passes, 401 and 403 included, because an unauthenticated probe of a credentialed endpoint is supposed to be refused and being refused proves the endpoint is there. This proves reachability, not authorisation: a 403 does not mean the credential works. Blank lines and # comments are ignored. Put no credentials in these URLs; they are printed into the run log. A URL carrying userinfo is refused, and the refusal names the line by its index and shows the URL with the userinfo replaced rather than echoing the line. |
terragrunt-credential-preflight |
terragrunt |
auto |
terragrunt: check that every cloud the discovered stacks name has a credential on this runner, before the first plan. auto (default) fails the run, warn annotates and plans anyway, off checks nothing. Exists because the credential a terragrunt run needs is not one credential. The state backend has its own (terragrunt-stack-env), and every provider block the stacks declare has another, from a different chain, that nothing in the workflow mentions. The failure that produces is the least readable in this action: state reads fine, init succeeds, and the plan dies inside a provider with could not configure AzureCli Authorizer: … Please run 'az login', twenty stacks in a row, which reads as a broken runner rather than as a credential nobody wired. What it reads: the provider "<name>" blocks in each discovered stack and in every parent directory up to terragrunt-root, so a generate block in a shared root.hcl counts. What it knows: azurerm/azuread/azapi, aws, google/google-beta, vcd. A provider it does not recognise is passed over in silence rather than guessed at. The state backend is deliberately not checked. A backend with no credential fails in init, immediately, naming the backend, which is already the good failure; and an ARM_ACCESS_KEY opens one storage account and cannot configure a provider, so counting it either way would be wrong. What it will NOT report: a provider block that configures its own authentication (client_id, client_secret, use_oidc, use_msi, access_key, credentials, token, api_token …), because that stack answers the question itself. That is the exemption that keeps this from being a check people turn off. This proves a credential is present, never that it is valid or that it can reach the subscription, project or account the stack names — the same distinction terragrunt-preflight-urls draws between reachable and authorised. |
terragrunt-log-level |
terragrunt |
not set | terragrunt: value for TF_LOG when diagnosing a stuck provider call (debug, trace). Empty (default) leaves provider logging off; the log is written next to the plan and redacted before it is shown. |
terragrunt-extra-args |
terragrunt |
not set | terragrunt: extra flags appended to every plan and apply, split on whitespace. |
ansible-playbook |
ansible |
not set | ansible: path to the playbook to run, relative to working-directory. Required for this target. |
ansible-inventory |
ansible |
not set | ansible: inventory path or comma-separated host list passed to -i. Required for this target. |
ansible-version |
ansible |
11.1.0 |
ansible: exact version of the ansible PyPI distribution to install. Pinned rather than floating, because a collection that changes behaviour between releases is indistinguishable from a change you made. |
ansible-python-version |
ansible |
3.12 |
ansible: Python version the control node runs on. |
ansible-galaxy-requirements |
ansible |
not set | ansible: path to a galaxy requirements file installed with ansible-galaxy install -r before the run. Empty skips it. |
ansible-limit |
ansible |
not set | ansible: value for --limit, restricting the run to a subset of the inventory. |
ansible-tags |
ansible |
not set | ansible: value for --tags. |
ansible-skip-tags |
ansible |
not set | ansible: value for --skip-tags. |
ansible-check |
ansible |
auto |
ansible: run in check mode, auto (default) means check mode on a pull request and a real run everywhere else, true forces check mode, false forces a real run. A pull request that silently reconfigured a fleet would be a surprising way to find out what a diff does. |
ansible-diff |
ansible |
true |
ansible: pass --diff, so the log shows what each changed task changed. |
ansible-extra-vars |
ansible |
not set | ansible: value for --extra-vars. Accepts key=value pairs or JSON. |
ansible-extra-args |
ansible |
not set | ansible: extra flags appended to the playbook run, split on whitespace. |
ansible-ssh-private-key |
ansible |
not set | ansible: SSH private key used to reach the inventory. Pass a secret, never a literal. It is masked on receipt, written to a 0600 file under RUNNER_TEMP, and removed when the step exits however it exits. |
ansible-ssh-user |
ansible |
not set | ansible: value for --user. Leave empty to let the inventory or ansible.cfg decide. |
ansible-ssh-known-hosts |
ansible |
not set | ansible: known_hosts entries for the inventory, one per line. Empty means host-key checking is disabled for the run, which is a real downgrade, supply this for anything reachable from a network you do not control. |
ansible-vault-password |
ansible |
not set | ansible: vault password. Pass a secret. Masked on receipt, written to a 0600 file under RUNNER_TEMP, removed when the step exits. |
vault-addr |
ansible |
not set | ansible: base URL of a HashiCorp Vault, e.g. https://vault.example.com:8200. Set it, with vault-token, to name secrets by Vault reference instead of passing them in. Only the fields you reference are read. |
vault-token |
ansible |
not set | ansible: Vault token the references are read with. Pass a secret. Needs read on the paths you reference and nothing else. |
vault-namespace |
ansible |
not set | ansible: Vault namespace (Enterprise). Empty is correct for open-source Vault. |
ansible-vault-passthrough |
ansible |
false |
ansible: hand VAULT_ADDR, VAULT_TOKEN and VAULT_NAMESPACE to the ansible-playbook process, so the playbook can read its own secrets from the same HashiCorp Vault rather than having them copied into a second store that quietly stops being rotated. Needs vault-addr and vault-token; without both, nothing is passed. false by default, and the default removes them from the playbook's environment. A token scoped to the fields this action reads becomes a token every task, role and collection in the play can use, and widening a credential's blast radius should be a decision rather than something inherited by accident. Nothing to do with ansible-vault, the file-encryption tool; that is ansible-vault-password. |
ansible-ssh-private-key-vault |
ansible |
not set | ansible: Vault reference to the SSH private key, <path>#<field>, e.g. secret/data/team/app#ssh_private_key. The alternative to ansible-ssh-private-key, not a supplement: setting both fails. Use this where Vault is already the source of truth, so rotating there keeps rotating here and the key is not copied into a second store that quietly goes stale. |
ansible-ssh-known-hosts-vault |
ansible |
not set | ansible: Vault reference to the known_hosts entries, <path>#<field>. The alternative to ansible-ssh-known-hosts. |
ansible-vault-password-vault |
ansible |
not set | ansible: Vault reference to the ansible-vault password, <path>#<field>. The alternative to ansible-vault-password. |
ansible-verify-idempotence |
ansible |
true |
ansible: after a successful real run, run the playbook again in check mode and fail if any task would still change. A zero exit only proves the playbook ran; this is what proves it converged. Skipped automatically when the run itself was check mode. |
cloudflare-api-token |
cloudflare-workers, cloudflare-docs |
not set | cloudflare-workers, cloudflare-docs: API token Wrangler authenticates with. Pass a secret, never a literal. Mint it from Cloudflare's "Edit Cloudflare Workers" template rather than a hand-picked permission list, or the first deploy of a custom domain fails on a permission nobody thought to grant. |
cloudflare-account-id |
cloudflare-workers, cloudflare-docs |
not set | cloudflare-workers, cloudflare-docs: Cloudflare account id. Pass a secret. |
cloudflare-config |
cloudflare-workers, cloudflare-docs |
not set | cloudflare-workers, cloudflare-docs: path to the Wrangler config (wrangler.toml or wrangler.jsonc), passed as --config. Empty lets Wrangler find it, which is the normal case. The config owns the asset directory, routes, custom domains and 404 handling; the inputs here are overrides for the few things a workflow legitimately varies. |
cloudflare-worker-name |
cloudflare-workers, cloudflare-docs |
not set | cloudflare-workers, cloudflare-docs: overrides the name in the Wrangler config, passed as --name. |
cloudflare-env |
cloudflare-workers |
not set | cloudflare-workers: Wrangler environment, passed as --env. This selects a config block, which is not the same thing as the shared environment input: that one is a label for notifications and the deployment record. |
cloudflare-main |
cloudflare-workers |
not set | cloudflare-workers: entry point for a Worker that runs code, passed as Wrangler's positional path argument. Leave empty for an assets-only Worker, which is the shape that serves static files straight from the edge with no cold start and no code in the request path. |
cloudflare-build-command |
cloudflare-workers |
not set | cloudflare-workers: command run in working-directory before Wrangler, for a Worker that needs bundling. Empty skips it. |
cloudflare-compatibility-date |
cloudflare-workers |
not set | cloudflare-workers: overrides the config, passed as --compatibility-date. |
cloudflare-minify |
cloudflare-workers |
false |
cloudflare-workers: pass --minify. Applies to Worker code, not to static assets. |
cloudflare-vars |
cloudflare-workers |
not set | cloudflare-workers: plain (NOT secret) variables, one KEY=VALUE per line, each passed as --var. Wrangler deletes vars not present in the config unless --keep-vars is set, so anything set in the dashboard belongs in the config instead. |
cloudflare-wrangler-version |
cloudflare-workers, cloudflare-docs |
4.114.0 |
cloudflare-workers, cloudflare-docs: exact Wrangler version to run. Pinned, because the tool that publishes to production is not a floating dependency. |
cloudflare-node-version |
cloudflare-workers, cloudflare-docs |
24 |
cloudflare-workers, cloudflare-docs: Node version Wrangler runs on. Wrangler 4 declares engines.node >= 22, and on 20 it installs cleanly and then refuses to run, so this does not default to whatever the runner happens to ship. |
cloudflare-docs-host |
cloudflare-docs |
not set | cloudflare-docs: hostname the docs router serves, e.g. docs.magmamoose.com. The site Worker itself has no hostname — it is reachable only through the router's service binding — so this is the address the Access check and the reported URL are about. Required when cloudflare-docs-require-access is on. |
cloudflare-docs-path |
cloudflare-docs |
not set | cloudflare-docs: path segment this repository's site is served under on cloudflare-docs-host. Empty (default) uses the repository name, which is what the router dispatches on, so overriding it is for a repo whose site is mounted elsewhere. |
cloudflare-docs-require-access |
cloudflare-docs |
false |
cloudflare-docs: refuse to publish unless a Cloudflare Access application actually covers <cloudflare-docs-host>/<cloudflare-docs-path>. This is enforcement, not convention: "the site is behind Access" is otherwise a belief nothing checks, and the deploy is the one moment something can ask Cloudflare and refuse. Needs the Access: Apps READ permission on cloudflare-api-token — the "Edit Cloudflare Workers" template does not include it, and a 403 is treated as "could not tell", never as "nothing covers it". |
cloudflare-docs-index |
cloudflare-docs |
true |
cloudflare-docs: emit the docs corpus from the build: llms.txt and llms-full.txt written into the site before it is published, and a search index of every page for the documentation MCP servers. One pass over the markdown that was just rendered; no credentials and no network. Publishing the index is a separate opt-in, cloudflare-docs-index-bucket. |
cloudflare-docs-index-bucket |
cloudflare-docs |
not set | cloudflare-docs: R2 bucket the index is published to, as index/<repo>.json. Empty (default) writes llms.txt into the site and uploads no index. Only a deploy writes it, and only after the site itself deployed: a pull request would otherwise overwrite the shared corpus with an unmerged branch. Needs R2 object write on cloudflare-api-token, which the "Edit Cloudflare Workers" template does not include. |
cloudflare-docs-capability-file |
cloudflare-docs |
capability.json |
cloudflare-docs: this repository's capability declaration, published to capability/<repo>.json in cloudflare-docs-index-bucket. Empty disables it; the default names a file most repositories do not have, and absent is the normal case — most repositories are not house tools. Present, it is validated against https://mcp.magmamoose.com/schema/capability.schema.json on every run, including a pull request, and a declaration that does not satisfy it FAILS THE RUN: the MCP reads a malformed document as private and reports it as unreadable, counted and never named, which is the one state invisible from the publishing side. private is republished from the repository's own visibility on the same fail-closed rule as the docs index, and commit and generated are stamped from the run. |
cloudflare-extra-args |
cloudflare-workers |
not set | cloudflare-workers: extra flags appended to the Wrangler invocation, split on whitespace. |
cloudflare-verify-config |
cloudflare-workers |
true |
cloudflare-workers: before publishing, run wrangler deploy --dry-run and refuse to publish if Wrangler reports configuration it will not apply: an unexpected field (a misspelled [[r2_bucket]] is only a warning, and the Worker deploys with no bucket), or a top-level binding an --env deploy does not inherit. A binding is only real if Wrangler prints it. Costs one extra bundle per run. |
functions-app-name |
azure-functions-zip |
not set | azure-functions-zip: the Function App to publish to. Required for this target. |
functions-resource-group |
azure-functions-zip |
not set | azure-functions-zip: resource group the Function App lives in. Required for this target. |
functions-slot |
azure-functions-zip |
not set | azure-functions-zip: deployment slot to publish to instead of production. Empty (default) publishes to the app itself. This is also what a preview has to use. A pull request must not publish onto the routes production serves, and a slot is Azure's only destination that does not — but a Linux Consumption plan HAS NO SLOTS. So on Consumption a preview is refused and says why, rather than quietly shipping a branch to production. On Premium or Dedicated, set this and previews go to the slot. |
functions-ready-attempts |
azure-functions-zip |
30 |
azure-functions-zip: how many times to ask the app for an answer after publishing, before calling the deploy dead. Any HTTP status passes, including a 404 at the root, which is what a Function App whose only trigger is at /api/<name> normally returns. Only a connection failure and a 503 count as "not yet". The default is generous on purpose: a freshly created Consumption app 503s from both the site and its SCM endpoint until content is first published, so a FIRST deploy has to retry through that rather than fail on it. |
functions-ready-delay |
azure-functions-zip |
10 |
azure-functions-zip: seconds between readiness attempts. With the default attempts, that is a five-minute ceiling on a cold first publish. |
verify-url |
all | not set | Post-deploy: the URL that must answer. Empty skips verification. Catches the deploy that uploaded but did not bind, the one failure that otherwise looks green. |
verify-header |
all | not set | Post-deploy: a response header that must be present on verify-url (e.g. content-security-policy). |
verify-header-match |
all | not set | Post-deploy: an extended regex the verify-header value must match. |
verify-method |
all | GET |
Post-deploy: HTTP method used to request verify-url. GET by default. Set it where a GET cannot verify the endpoint at all. A webhook receiver binds POST and nothing else, so a GET reaches no function and the platform answers 404 — which is also what an empty package returns, leaving the check unable to tell a working deploy from a broken one. verify-method: POST with verify-status: 401 asserts that the function is bound and that its signature check refuses an unsigned request, which is the thing worth knowing. The method survives a redirect: curl otherwise downgrades a redirected POST to a GET, which would quietly turn the assertion into a different one. |
verify-status |
all | 200 |
Post-deploy: expected HTTP status from verify-url. |
verify-attempts |
all | 6 |
Post-deploy: how many times to try verify-url before failing. |
verify-delay |
all | 10 |
Post-deploy: seconds between verification attempts. |
notify |
all | always |
always (default), on-success, or on-failure. Applies to the webhook sinks. |
pr-comment |
all | auto |
Sticky pull-request comment. auto (default) means on for preview mode and for the terragrunt target. |
slack-webhook |
all | not set | Slack incoming-webhook URL. Empty means the sink is off. Never fails the deploy. |
teams-webhook |
all | not set | Microsoft Teams incoming-webhook URL. Empty means the sink is off. Never fails the deploy. |
api-url |
all | not set | Base URL of a Tremvok API to record this deployment with. Authenticates with a GitHub OIDC token, so the repository stores no credential. Empty means no record is kept. |
api-audience |
all | tremvok |
OIDC audience the Tremvok API expects. |
auth-token |
all | ${{ github.token }} |
Token used for the pull-request comment and the check run. Needs pull-requests: write and, for the terragrunt target, checks: write. |
allow-fork-preview |
all | false |
Let a fork pull request attempt a deploy. Off by default and almost always wrong: a fork cannot read secrets, so this only converts an honest skip into an auth error. |
allow-dispatch-from-any-ref |
all | false |
Let a manual run deploy from a branch other than the default one. Off by default, publishing a topic branch to production usually is not what "Run workflow" meant. |
Outputs¶
| Output | Description |
|---|---|
target |
The deployment target this run used. |
mode |
The resolved mode: deploy, preview or rollback. |
environment |
The resolved environment name. |
url |
URL of what was deployed, when the target produces one. |
deployed |
true when something was actually deployed (false for a skip). |
verified |
true when post-deploy verification ran and passed. |
skipped |
true when the run skipped (fork pull request, or no credential). |
skip-reason |
Why it skipped, in a sentence. |
record-id |
Identifier returned by the Tremvok API, when api-url is set. |
site-dir |
github-pages: absolute path to the built site. |
pages-toolchain |
github-pages: the toolchain actually used, uv or pip. |
version-id |
lambda-zip, cloudflare-workers, azure-functions-zip: the published version. A Lambda version number, a Worker Version ID, or the package sha256 — Azure exposes no per-deploy content hash of its own. |
stacks |
terragrunt: how many stacks this run discovered. |
plan-changes |
terragrunt: how many of those stacks planned with a diff. |
applied |
terragrunt: true when this run applied, false when it only planned. |
changed-tasks |
ansible: how many tasks reported changed on the real run. |
idempotent |
ansible: true when the second check-mode run found nothing left to change. |
Required permissions¶
Declared by the caller, because a composite action cannot declare
permissions:. Only what the target actually uses:
target: github-pages¶
permissions:
contents: read # checkout
pages: write # actions/deploy-pages, in the caller's own job
id-token: write # actions/deploy-pages
target: s3-cloudfront¶
permissions:
contents: read # checkout
id-token: write # assume the deploy role by OIDC
pull-requests: write # the sticky preview comment
target: lambda-zip¶
permissions:
contents: read # checkout
id-token: write # assume the deploy role by OIDC
pull-requests: write # the sticky preview comment
target: terragrunt¶
permissions:
contents: read # checkout
id-token: write # assume the deploy role by OIDC
pull-requests: write # the rolling plan comment
checks: write # the check run that makes apply-before-merge enforceable
target: ansible¶
permissions:
contents: read # checkout
pull-requests: write # the sticky run comment
target: cloudflare-workers¶
permissions:
contents: read # checkout
pull-requests: write # the sticky preview comment
target: cloudflare-docs¶
permissions:
contents: read # checkout
pull-requests: write # the sticky preview comment
target: azure-functions-zip¶
permissions:
contents: read # checkout
id-token: write # sign in to Azure by OIDC
pull-requests: write # the sticky preview comment
target: github-pages is the one target the action cannot finish on its own:
actions/deploy-pages needs pages: write and the github-pages environment, and a
composite action can declare neither. The action builds and stages the artifact; the
caller's job runs actions/deploy-pages. Every other target completes inside the
action.