Conversation
| description: | | ||
| Name of an environment variable in the environment where 'inputs.script' is run. | ||
| Variable's value will be set to the value passed as 'secrets.script-env-secret-3-value'. | ||
| required: false |
There was a problem hiding this comment.
I think you need a default value here. What happens if the value is set but the key is not? It's a silly situation, but there's no other way to ensure sanity here.
perhaps just SCRIPT_ENV_SECRET_X_KEY, where X is 1, 2 or 3?
There was a problem hiding this comment.
I agree but unfortunately the secrets: inputs don't allow you to set a default. They only take description: and required:.
From actionlint:
.github/workflows/checks.yaml:55:9: unexpected key "default" for "secrets" section. expected one of "description", "required" [syntax-check]
I could add more handling in the shell script that processes these.
Also side note... would that script be a good use case for an action? I think yes.
There was a problem hiding this comment.
Also side note... would that script be a good use case for an action? I think yes.
I think you mean a shared-action? Maybe. At some point, I think it's hard to maintain what github considers to be secret. Will pipelining this through a shared-action, then returning its validated values still correctly mask stuff? I dunno. It's worth a try, but I wouldn't go too deep on any rabbit holes.
There was a problem hiding this comment.
Good point, good point. Ok I'll just leave this as an inline script for now, even with the extra handling to defend against "empty key, non-empty value", it won't be that complex.
There was a problem hiding this comment.
Ok think I've handled this in the latest commits. Setting the value but not the key should now result in a loud and clear error.
I've also moved most of the processing into a bash function, so that if we wanted to allow more than 3 secrets all the logic wouldn't need to be repeated.
| - repo: https://github.com/zizmorcore/zizmor-pre-commit | ||
| # Zizmor version. | ||
| rev: v1.19.0 | ||
| rev: v1.20.0 |
There was a problem hiding this comment.
Might as well update to the latest zizmor while we're doing this, to give it a chance to catch any security issues with this (it did not report any new issues).
msarahan
left a comment
There was a problem hiding this comment.
I think 3 secrets is very likely enough to cover all reasonable situations. If we need more, we can add one or two, but I wonder if we'll hit a limit at some point, like there is for inputs.
This is just musing, not requesting any change. I don't know what the upper limit is. Github's copilot says this:
[Copilot](https://docs.github.com/en/copilot/responsible-use-of-github-copilot-features/responsible-use-of-github-copilot-chat-in-githubcom) uses AI. Check for mistakes.
Inputs
For reusable workflows (on.workflow_call.inputs) each input must declare a type of boolean, number, or string.
If a caller passes an input that the called workflow does not declare, the run fails with an error.
For workflow_dispatch (manual trigger) inputs: maximum 25 top-level input properties and a maximum payload of 65,535 characters. (Default values when omitted: boolean → false, number → 0, string → "".)
Secrets
In a reusable workflow (on.workflow_call.secrets) declare the named secrets the called workflow expects. If the caller passes a secret that the called workflow did not declare, the run errors.
To pass secrets from the caller: use jobs.<job_id>.secrets to pass named secrets, or secrets: inherit to pass all of the caller's secrets to the directly called workflow.
Secrets are only passed to directly called workflows. In a chain A → B → C, C receives a secret from A only if A passed it to B and B then passed it to C.
Nested reusable workflows are limited to 10 levels (caller + up to 9 nested). Permissions and secrets can only be maintained or reduced through the chain — they cannot be elevated.
Best practices and gotchas
Avoid using structured data as a single secret (JSON/YAML blobs) because redaction may fail.
Audit and pin third-party actions; follow least-privilege for tokens used in workflows.
Make sure the called workflow declares any inputs and secrets you intend to pass to avoid errors.
Quick checklist to avoid errors
In the called workflow (on.workflow_call) declare every input with type and declare expected secrets.
In the caller job use with: for inputs and secrets: (or secrets: inherit) for secrets.
For nested workflows, re-pass secrets explicitly from each caller to the next.
Maybe that means it shares the 25-item limit on inputs? Maybe they each get 25? Who knows? I think we're safe for the foreseeable future.
| if test -n "${val_str}"; then | ||
| if ! test -n "${key_str}"; then | ||
| local input_name | ||
| echo "ERROR: '${input_prefix}-value' non-empty but '${input_prefix}-key' is empty. Set '${input_prefix}-key'." |
|
Thanks for considering the input limit, not something I'd thought of. It does look like 25 (https://github.com/orgs/community/discussions/8774, https://github.blog/changelog/2025-12-04-actions-workflow-dispatch-workflows-now-support-25-inputs/), unsure if that includes both Either way yeah, I think this should be fine for the foreseeable future and if we needed to support more than 25 in the future we could adjust to that then. |
This PR enables populating arbitrary environment variables for
script:from GitHub secrets, for the following workflows:conda-cpp-testsconda-python-testswheel-testsProposing this because something like it is needed for NVIDIA/cuopt#748. In that PR,
cuoptworkflows want to download datasets from a private S3 bucket, and need a way to pass in credentials and other sensitive configuration.Notes for Reviewers
Why this design?
GitHub Actions limitations:
env:at the callsite of a reusable workflowsecrets.*context at the callsite of a reusable workflowOther design considerations:
NVIDIA) to workflows sourced from another (rapidsai)cuopt-specific)GitHub Actions offers a preferred way to do this. The
workflow_call:workflow trigger accepts a mapping calledsecrets:, which is similar toinputs:but where GitHub knows to treat the values as sensitive (e.g. to obscure them from the UI and logs). See https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows#passing-inputs-and-secrets-to-a-reusable-workflowThis design of having separate inputs for the key and value also inspired by the
envFromconcept in Kubernetes:(kubernetes docs link)
Wait don't we already handle secrets in this repo? And differently?
Yes, there are a couple places where workflows accept a string in
inputs:with the name of a secret, and then later look it up. For example, inbuild-in-devcontainer:shared-workflows/.github/workflows/build-in-devcontainer.yaml
Lines 66 to 70 in 58dc4f0
shared-workflows/.github/workflows/build-in-devcontainer.yaml
Line 168 in 58dc4f0
I think the pattern introduced here is preferable, for a couple reasons:
RAPIDS_AUX_SECRET_1to be set and then processing that in scripts)How I tested this
On
cuoptPRs pointed at this branch: