Skip to content

fix: update aws-actions/configure-aws-credentials from v4 to v6 (node24)#95

Open
kinyoklion wants to merge 9 commits into
mainfrom
devin/1781649132-update-aws-credentials-node24
Open

fix: update aws-actions/configure-aws-credentials from v4 to v6 (node24)#95
kinyoklion wants to merge 9 commits into
mainfrom
devin/1781649132-update-aws-credentials-node24

Conversation

@kinyoklion

@kinyoklion kinyoklion commented Jun 16, 2026

Copy link
Copy Markdown
Member

Summary

Eliminates both Node 20 deprecation warnings from the release-secrets composite action, and replaces the unmaintained third-party SSM action with a first-party, dependency-pinned TypeScript helper.

  1. aws-actions/configure-aws-credentials v4 → v6 (node20 → node24). The only breaking change in v6 is the Node bump; inputs (audience, role-to-assume, aws-region) are unchanged. Pinned by SHA to v6.2.0.

  2. Replaces dkershner6/aws-ssm-getparameters-action (node20, no upstream update) with actions/release-secrets/ssm — a small TypeScript action bundled to dist/index.js with ncc, run via node dist/index.js. It parses the ssm_parameter_pairs format, fetches parameters with WithDecryption (chunked to the 10-name API limit), masks values via @actions/core, validates every requested path resolved before exporting anything, and exports via core.exportVariable.

    Masking and multiline-safe $GITHUB_ENV writes are handled by @actions/core / the runner rather than hand-rolled shell: core.setSecret already masks both the whole value and each line of a multiline secret (the runner's add-mask handler splits on newlines since actions/runner#1521), and core.exportVariable writes the GITHUB_ENV heredoc.

Supply-chain hardening

  • Yarn 4 (via corepack, pinned through the packageManager field) instead of npm.
  • 7-day dependency cooldown: .yarnrc.yml sets npmMinimalAgeGate: "7d", so no package version newer than 7 days is ever resolved — mirroring the org Renovate minimumReleaseAge: "7 days" policy. nodeLinker: node-modules keeps ncc bundling working.
  • All dependencies are the latest CVE-free versions that are ≥7 days old; yarn npm audit --all is clean. This also resolves the Semgrep findings on the (dev-only) vitest/vite/esbuild transitives.
  • The CI workflow pins all GitHub Actions by SHA to the latest ≥7-day-old releases (actions/checkout@v6.0.3, actions/setup-node@v6.4.0).

CI

.github/workflows/test-release-secrets-ssm.yml runs on changes to the action: yarn install --immutable, yarn typecheck, yarn test (vitest, AWS SDK mocked), and a check-dist step that rebuilds and fails if the committed dist/ is stale. The build is deterministic; note dist/ is now multiple co-located chunks (newer AWS SDK + ncc code-splitting), all committed alongside index.js.

How to test

Use a workflow that calls release-secrets and verify:

  • AWS credentials are configured correctly (v6)
  • SSM parameters are fetched and exported as masked env vars (including multiline secrets such as PEM keys)
  • No Node 20 deprecation warnings appear in the logs

Link to Devin session: https://app.devin.ai/sessions/8bbd83e7ff0a489a9b06f810dab17d52
Requested by: @kinyoklion


Open in Devin Review

The v4 release uses Node 20 which is deprecated. v6 uses Node 24.
This resolves the Node 20 deprecation warning for this dependency.

Co-Authored-By: rlamb@launchdarkly.com <4955475+kinyoklion@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@kinyoklion kinyoklion marked this pull request as ready for review June 16, 2026 22:34
@kinyoklion kinyoklion requested a review from a team as a code owner June 16, 2026 22:34
… implementation

The dkershner6 action is pinned to node20 and has no node24 release.
Replace it with a shell script that uses the AWS CLI directly,
including ::add-mask:: for secret redaction in logs.

Co-Authored-By: rlamb@launchdarkly.com <4955475+kinyoklion@users.noreply.github.com>
Rewrites the SSM fetch script to fix issues found in review:
- Write multiline secret values to $GITHUB_ENV via a randomized
  heredoc delimiter (a plain NAME=value truncates multiline secrets
  and parses the tail as additional env entries); mask every line.
- Fail loudly when a requested parameter is missing instead of
  silently exporting fewer vars (handles InvalidParameters), and
  validate all paths are present before writing any to avoid a
  partially-populated $GITHUB_ENV.
- Resolve pairs by position rather than matching returned names back,
  so duplicate paths each get their own env var and no stale value is
  reused.
- Parse with mapfile + trim() via parameter expansion (xargs mangled
  quotes/backslashes; unquoted command substitution word-split input).

Adds a mocked smoke test (actions/release-secrets/tests) and a CI
workflow that runs it on changes to the action.
Move ::add-mask:: registration to the moment each value is read from
the AWS response, before it is stored in the map or used anywhere else,
so the unmasked-in-memory window is as small as possible and any future
code between fetch and write is covered by masking.
…lper

Replace the bash ssm-get-parameters.sh with a TypeScript implementation under
actions/release-secrets/ssm that uses @actions/core (masking + GITHUB_ENV
export) and @aws-sdk/client-ssm (the GetParameters call). The composite invokes
it via `node "$GITHUB_ACTION_PATH/ssm/dist/index.js"`.

Why:
- @actions/core owns the secret-handling plumbing (masking, multiline-safe
  GITHUB_ENV heredoc export) instead of hand-rolling it in shell.
- The AWS SDK removes the ambient `aws` CLI dependency and pins a reproducible
  client version via package-lock.json.
- First-party and unit-tested (vitest + aws-sdk-client-mock).

Behavior is preserved from the hardened bash: parse/trim/validate pairs, chunk
by 10, decrypt, mask every value (whole + per line, since runner log masking is
line-oriented), fail before writing anything if a parameter is missing, and
support duplicate paths.

CI (test-release-secrets-ssm.yml) runs typecheck, unit tests, and a check-dist
step that fails if the committed bundle drifts from source; the build Node is
pinned via .nvmrc so that comparison is stable.
semgrep-code-launchdarkly[bot]

This comment was marked as resolved.

semgrep-code-launchdarkly[bot]

This comment was marked as resolved.

semgrep-code-launchdarkly[bot]

This comment was marked as resolved.

…cooldown

- Replace npm/package-lock.json with Yarn 4 (via corepack) + yarn.lock
- Add .yarnrc.yml npmMinimalAgeGate: "7d" install-time cooldown, matching the
  org Renovate minimumReleaseAge policy; nodeLinker: node-modules so ncc bundles
- Bump all deps to the latest CVE-free, >=7-day-old versions (@actions/core 3,
  @aws-sdk/client-ssm 3.1067, typescript 6, vitest 4, @types/node 25, ncc 0.44).
  Clears the Semgrep vitest/vite/esbuild findings; `yarn npm audit` is clean
- Drop the hand-rolled per-line maskSecret loop and call core.setSecret directly:
  since actions/runner #1521 the runner already masks each line of a multiline
  secret, so replicating it was redundant
- Modernize tsconfig (Preserve/Bundler resolution + explicit rootDir) for TS 6
  and @actions/core v3 being ESM-only
- Convert CI to corepack/yarn (immutable install) and SHA-pin to the latest
  >=7-day-old actions: checkout v6.0.3, setup-node v6.4.0
There is no coverage tooling configured (vitest runs without --coverage and no
provider is installed), and vitest defaults to the v8 provider, which does not
honor istanbul pragmas. The guarded line is the CLI entrypoint, exercised via
`node dist/index.js` rather than unit tests.
@kinyoklion kinyoklion requested a review from joker23 June 18, 2026 23:21

@devin-ai-integration devin-ai-integration Bot left a comment

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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

…ectors

The `require.main === module` guard compiled to an always-false check once the
source became an ES module (tsconfig module: Preserve, needed for @actions/core
v3's ESM-only package), so ncc wrapped the entry and `run()` never executed —
the action was a silent no-op (malformed input exited 0, nothing exported).

- Split the entrypoint into src/main.ts, which imports run() from ./index and
  invokes it unconditionally; src/index.ts is now a side-effect-free library
  that tests import without triggering execution.
- Build now targets src/main.ts.
- Add a CI "Smoke-test the bundled entrypoint" step that runs node dist/index.js
  on malformed input and fails if it exits 0 — the unit tests import run() from
  source, so only an artifact-level check can catch a no-op bundle.
- Reject version/label selectors (`name:3`) in parsePairs: SSM returns the base
  name in Parameter.Name, so a selector would be fetched but then reported
  missing. Fail early with a clear message instead. Add a regression test.

Found by multi-agent review (adversarial agent, by executing the bundle).
@kinyoklion kinyoklion requested a review from a team June 22, 2026 20:15
The runImpl indirection added nothing: runImpl was internal, called from one
place, and the only difference was run() supplying the default SSMClient. A
default parameter is already a lazy DI seam (tests inject a mock client, so the
real client is never constructed), so a single async run() is equivalent.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants