Skip to content

feat: support flexible secret passing methods in workflows - #225

Merged
metalwarrior665 merged 7 commits into
masterfrom
claude/zen-mayer-7md3vw
Oct 29, 2026
Merged

metalwarrior665 merged 7 commits into
masterfrom
claude/zen-mayer-7md3vw

Conversation

@metalwarrior665

@metalwarrior665 metalwarrior665 commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

I checked it briefly; this is still up for discussion. It is quite ugly but we don't have many good options.

Closes #205

Summary

This PR refactors how secrets are passed to reusable workflows, replacing the single secrets: inherit approach with three flexible methods: passing secrets by name, using ALL_SECRETS for bulk passing, or using secrets: inherit within the Apify org. This improves security by allowing explicit secret declaration and works across organization boundaries.

Key Changes

  • Updated README documentation with comprehensive guidance on three secret-passing methods:

    • By name (recommended): explicit and works from any repo
    • ALL_SECRETS: bulk passing via toJSON(secrets) without maintaining a list
    • secrets: inherit: org-restricted but convenient for Apify repos
  • Modified workflow files to declare accepted secrets and use fallback logic:

    • public_pr-build-test.yaml: Added secret declarations and fallback expressions using || operator
    • public_platform-tests.yaml: Added secret declarations and fallback expressions
    • public_push-build-latest.yaml: Added secret declarations and fallback expressions
    • public_platform-tests-claude-investigate-and-fix.yaml: Updated example comments to show explicit secret passing
  • Enhanced run-with-apify-tokens.mjs script:

    • Added unpack() helper function to safely parse JSON secrets
    • Implemented three-tier secret lookup: APIFY_ACTOR_TOKENS → top-level secrets → ALL_SECRETS
    • Improved error messages to guide users on where to check for missing tokens
  • Added masking support in checkout-restore-dependencies action:

    • New all-secrets and apify-actor-tokens inputs
    • "Mask packed secrets" step that registers individual token values as masks before they're used
    • Prevents accidental exposure of tokens extracted from JSON blobs
  • Updated example workflows in README to show explicit secret passing instead of secrets: inherit

Notable Implementation Details

  • Secrets passed by name take precedence over those in ALL_SECRETS, allowing callers to override
  • The masking step uses jq to extract and register individual values from JSON secrets before any step can use them
  • Fallback expressions use fromJSON(secrets.ALL_SECRETS || '{}') to safely handle missing secrets
  • Actor tokens remain special-cased in APIFY_ACTOR_TOKENS JSON object since each repo names its own tokens
  • All three methods can be mixed in a single workflow call

https://claude.ai/code/session_01Wf2reqEVbnQV3vmZ7fjekm

…e workflows

`secrets: inherit` only works within the same org or enterprise, so the build and test workflows
got no secrets when called from anywhere else. They now declare their secrets and accept them
three ways, which can be mixed:

- by name, with the Actor tokens packed into APIFY_ACTOR_TOKENS, a JSON object keyed by the
  `tokenEnvVar` names from apify-test-tools.config.json (the names differ per repo, so they
  cannot be declared one by one)
- everything at once as `ALL_SECRETS: ${{ toJSON(secrets) }}`
- `secrets: inherit`, unchanged for repos in the apify org

The setup action registers every value inside the two JSON secrets as a mask, since the runner
only masks the blob as a whole. The README now shows passing by name and mentions the other two.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wf2reqEVbnQV3vmZ7fjekm
Moves the masking jq out of the setup action into .github/scripts/mask-packed-secrets.sh so it
can be tested, and makes it reject non-object JSON like the wrapper does (jq's to_entries
accepts arrays too).

The tests cover the three ways of passing Actor tokens, which source wins, the missing-token
warning, and that malformed packed secrets fail without printing their value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wf2reqEVbnQV3vmZ7fjekm
@metalwarrior665 metalwarrior665 changed the title Support flexible secret passing methods in workflows feat: support flexible secret passing methods in workflows Oct 27, 2026
@metalwarrior665
metalwarrior665 marked this pull request as ready for review October 27, 2026 14:37

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tl;dr: if its mentioned on apify-test-tools.config.json it should be passed through ALL_SECRETS (but with a different name). If not, we should state them explicitly. And these two should not mix.

I'd split these, known secrets used explicitly on the workflow or on the CLI should be explicitly stated as part of the secrets. Whereas user-defined stuff like token env vars to be read (stated on their config file) should be passed in through the secrets hack.

I see no reason for the NPM_TOKEN to be passed through ALL_SECRETS. Also, its not all secrets, but secrets taken from the test tools config the ones we want to pass in.

secrets: inherit should be a fallback for the ALL_SECRETS lookup

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in ae574d6. Fixed secrets are declared and passed by name only. Config-defined secrets go in CONFIG_SECRETS (renamed from APIFY_ACTOR_TOKENS so it isn't tied to Actor tokens if the config grows). The wrapper checks CONFIG_SECRETS first, then inherited secrets. ALL_SECRETS and the fromJSON fallbacks are gone. Callers who don't want to list the names can still pass CONFIG_SECRETS: ${{ toJSON(secrets) }}; only the names the config declares get through.


Generated by Claude Code

…_SECRETS

Per review: a secret a workflow always reads (NPM_TOKEN, TESTER_APIFY_TOKEN, the Slack tokens) is
now only taken by name, and the secrets apify-test-tools.config.json names go in one packed
secret, CONFIG_SECRETS (was APIFY_ACTOR_TOKENS). The two no longer mix.

- Drops the ALL_SECRETS secret and the `fromJSON(secrets.ALL_SECRETS ...)` fallbacks in every
  step. Callers who don't want to list config secrets can pass `toJSON(secrets)` as
  CONFIG_SECRETS; the wrapper still only uses the names the config declares.
- The wrapper looks a token up in CONFIG_SECRETS, then among inherited secrets.
- Renames the wrapper's step variable to WORKFLOW_SECRETS so it isn't mistaken for a secret
  callers pass, and the masking script to mask-config-secrets.sh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wf2reqEVbnQV3vmZ7fjekm
… when it's empty

public_platform-tests always runs the tests, so it now declares TESTER_APIFY_TOKEN as required.
public_pr-build-test keeps it optional, since `skip-platform-tests` runs no tests.

`required` only checks that the caller lists the secret, not that it has a value: the repo may not
have it, and PRs from forks never get secrets. Both workflows now check for an empty token right
after setup and fail with a clear message, instead of an Apify API error deep inside vitest (and,
in the PR workflow, after the Actors were already built).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wf2reqEVbnQV3vmZ7fjekm
…g, revert before merging

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wf2reqEVbnQV3vmZ7fjekm
…r testing, revert before merging"

This reverts commit e3ed14f.
@metalwarrior665

Copy link
Copy Markdown
Member Author

tested on live repo, all seems good

@metalwarrior665
metalwarrior665 merged commit 22f7e80 into master Oct 29, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

secrets: inherit is forbidden across GitHub accounts (unless in same Enterprise)

4 participants