Skip to content

feat(docker): forward BuildKit secrets to the image build - #15

Merged
samuelho-dev merged 1 commit into
mainfrom
samuel/buildkit-secrets
Aug 12, 2026
Merged

feat(docker): forward BuildKit secrets to the image build#15
samuelho-dev merged 1 commit into
mainfrom
samuel/buildkit-secrets

Conversation

@samuelho-dev

@samuelho-dev samuelho-dev commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Why

A build that needs a credential had no way to receive one. build-args are the only existing channel and they are recoverable from image history, so a token cannot go through them.

Concretely: creativetoolkits' web image builds without SENTRY_AUTH_TOKEN, so withSentryConfig disables source-map upload. Every Sentry release for that project carries 0 artifacts, and production stack traces cannot be de-minified.

What

One optional build-secrets secret, forwarded to docker/build-push-action's secrets: parameter. Callers pass id=value lines and read them in a Dockerfile via RUN --mount=type=secret,id=<id>; the value is never written to a layer.

Compatibility

Additive. An unset input forwards an empty string, which mounts nothing, so all five current call sites keep their present behaviour with no change.

Summary by CodeRabbit

  • New Features
    • Added optional support for securely passing build secrets during Docker image builds.
    • Supports multiple newline-separated BuildKit secret definitions.

Callers that need a credential during the build had no way to supply one.
build-args are recoverable from image history, so a token cannot go there.

Adds an optional build-secrets input, passed straight to
docker/build-push-action's secrets parameter. Empty input mounts nothing,
so existing callers are unaffected.
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The reusable Docker workflow now accepts newline-separated BuildKit secret definitions and passes them to the Docker build action.

Changes

Build secret support

Layer / File(s) Summary
Declare and forward BuildKit secrets
.github/workflows/docker-build-push.yml
The workflow adds an optional build-secrets secret and passes secrets.build-secrets to docker/build-push-action.

Estimated code review effort: 2 (Simple) | ~5 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes forwarding BuildKit secrets to the Docker image build, which is the main change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@samuelho-dev
samuelho-dev merged commit c92a1ab into main Aug 12, 2026
2 of 3 checks passed
@samuelho-dev
samuelho-dev deleted the samuel/buildkit-secrets branch August 12, 2026 04:20

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/docker-build-push.yml:
- Around line 87-93: Update the workflow step that prepares or passes
build-secrets so each individual credential value is registered with GitHub
Actions masking before docker/build-push-action runs. Preserve the existing
id=value, one-per-line format and ensure every parsed secret value is masked
separately, including when ACTIONS_STEP_DEBUG is enabled.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5049d0d4-eb57-43a4-881b-9b8a00fece07

📥 Commits

Reviewing files that changed from the base of the PR and between aad056c and b147855.

📒 Files selected for processing (1)
  • .github/workflows/docker-build-push.yml

Comment on lines +87 to +93
build-secrets:
description: >-
BuildKit secrets as `id=value`, one per line, exposed to the build via
`RUN --mount=type=secret,id=<id>`. Use this for credentials a build must
read: `build-args` are recoverable from image history, mounted secrets
are not written to any layer.
required: false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

file=".github/workflows/docker-build-push.yml"
printf '%s\n' '--- workflow context ---'
sed -n '70,100p' "$file"
sed -n '165,195p' "$file"

printf '%s\n' '--- references to build-secrets and debug settings ---'
rg -n -C 3 'build-secrets|ACTIONS_STEP_DEBUG|RUNNER_DEBUG|docker/build-push-action|secret' .github README.md 2>/dev/null || true

printf '%s\n' '--- repository metadata ---'
git ls-files '.github/workflows/docker-build-push.yml'

Repository: samuelho-dev/git-flow

Length of output: 27362


🌐 Web query:

docker/build-push-action structured secrets multiline secret masking debug logs GitHub Actions

💡 Result:

To handle multiline secrets with the docker/build-push-action in GitHub Actions, you must wrap the key-value pair in double quotes [1][2]. This enables the action to correctly parse the multiline content and maintain the necessary formatting [1]. Implementation details: - Formatting: Use the secrets input in your workflow YAML, ensuring multiline values are quoted. If your secret contains double quotes, you must double-escape them [1][2]. yaml with: secrets: | "MY_MULTILINE_SECRET=${{ secrets.GPG_KEY }}" - Important Note on Whitespace: The underlying parser for GitHub Actions inputs may strip trailing newlines from multiline secrets [3]. If your application requires these trailing newlines (e.g., for certain SSH key formats), you may need to append a newline character during the Docker build process, such as by using echo "" >> /path/to/secret within your Dockerfile after the secret is mounted [3]. - Debug Logs and Masking: While GitHub Actions attempts to mask secrets in logs, they may occasionally appear in debug-level output [4]. This is generally considered a function of the GitHub Actions runner runtime rather than the docker/build-push-action itself [4]. To avoid accidental exposure, ensure you are using dedicated secret mounts (via --mount=type=secret in your Dockerfile) rather than passing sensitive data as build arguments (build-args), as build arguments are not masked and will be persisted in the final image layers [4]. - Usage: Mount the secret in your Dockerfile to consume it securely during the build [1][5]: dockerfile RUN --mount=type=secret,id=MY_MULTILINE_SECRET \ cat /run/secrets/MY_MULTILINE_SECRET

Citations:


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- docker/build-push-action v7.3.0 metadata ---'
curl -fsSL https://api.github.com/repos/docker/build-push-action/git/ref/tags/v7.3.0 |
  jq '{ref, object}'
curl -fsSL https://raw.githubusercontent.com/docker/build-push-action/v7.3.0/src/context.ts |
  rg -n -C 5 'secret|Secret|debug|input'

printf '%s\n' '--- action runtime and input logging ---'
curl -fsSL https://raw.githubusercontent.com/docker/build-push-action/v7.3.0/src/main.ts |
  rg -n -C 5 'getInput|debug|context|secret'
curl -fsSL https://raw.githubusercontent.com/docker/build-push-action/v7.3.0/src/context.ts |
  sed -n '1,240p'

printf '%s\n' '--- cited issue ---'
curl -fsSL https://api.github.com/repos/docker/build-push-action/issues/1025 |
  jq '{title, state, body, html_url}'

Repository: samuelho-dev/git-flow

Length of output: 20794


🌐 Web query:

site:docs.github.com actions secure use secrets structured values masking multiline secrets

💡 Result:

To secure secrets in GitHub Actions, adhere to the following best practices: Avoid Structured Data as Secrets GitHub strongly recommends against storing structured data (such as JSON, XML, or YAML blobs) as a single secret [1][2]. GitHub's automated redaction system relies on matching exact secret values; encapsulating sensitive data within structured formats significantly reduces the effectiveness of this redaction, increasing the risk that secrets will be exposed in workflow logs [1][2]. Instead, store each individual sensitive value as its own separate secret [1][2]. Masking Sensitive Values If you generate sensitive values during a workflow (e.g., tokens or keys derived from other secrets) or need to mask non-secret data, use the ::add-mask:: workflow command [1][3][4]. * Syntax: echo "::add-mask::<value>" [3][4] * Behavior: When a value is masked, it is treated as a secret for the remainder of the job, and any instance of that exact string appearing in the logs will be replaced with * [3][4]. * Important: Masking must be performed once per job, and the value must be registered before it is printed to the logs or used in other commands [3][4]. Handling Multiline Secrets If you must use multiline strings, avoid using them as secrets if possible. If they are unavoidable, be aware that standard redaction may be less reliable for complex, arbitrary multiline content. For passing multiline strings as outputs or environment variables, use delimiters to prevent shell injection or formatting issues: echo "{name}<<{delimiter}" >> $GITHUB_OUTPUT echo "{value}" >> $GITHUB_OUTPUT echo "{delimiter}" >> $GITHUB_OUTPUT If the value is completely arbitrary and contains the chosen delimiter, do not use this format; instead, write the secret to a temporary file on the runner to avoid command-line parsing issues [4]. General Security Principles * Use Secrets for Sensitive Info: Do not store sensitive data as plaintext in workflow files [1][2]. * Register Transformed Secrets: If a secret is transformed (e.g., Base64 encoded, signed, or used to generate a new token), register the resulting value using ::add-mask:: to ensure it is also redacted if printed [1][2]. * Avoid Command-Line Passing: When possible, pass secrets via environment variables rather than command-line arguments to prevent them from being visible in process monitoring tools like ps [5].

Citations:


🌐 Web query:

site:github.com/docker/build-push-action/issues/1025 secrets debug logs masking

💡 Result:

To prevent secrets from appearing in debug logs, the most effective approach is to avoid passing sensitive data through mechanisms that are logged by default, such as build arguments or environment variables [1]. Instead, use purpose-built secret management features, such as Docker's build-time secret mounting, which prevents secrets from being exposed in image layers or logs [1]. When integrating with CI/CD platforms like GitHub Actions, rely on the platform's native secret masking logic [1]. If secrets still appear, it may indicate a failure in the runner's masking engine or an insecure implementation, such as using build arguments where secret mounts are appropriate [1]. As a best practice, always favor dedicated secret stores and mounting mechanisms over passing sensitive information directly into commands or configurations that are likely to be output to debug logs [1].

Citations:


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- input-list parser ---'
curl -fsSL https://raw.githubusercontent.com/docker/actions-toolkit/v0.1.0/src/util.ts 2>/dev/null |
  rg -n -C 8 'getInputList' || true
curl -fsSL https://raw.githubusercontent.com/docker/actions-toolkit/main/src/util.ts 2>/dev/null |
  rg -n -C 12 'getInputList' || true

printf '%s\n' '--- build-push-action secret resolver ---'
curl -fsSL https://raw.githubusercontent.com/docker/actions-toolkit/main/src/buildx/build.ts 2>/dev/null |
  rg -n -C 8 'resolveSecretString|hasGitAuthTokenSecret' || true

printf '%s\n' '--- standalone transformation check ---'
python3 - <<'PY'
import json

aggregate = "TOKEN_ID=alpha-secret\nCERT_ID=bravo-secret"
parsed = [line for line in aggregate.splitlines() if line.strip()]
debug_inputs = json.dumps({"secrets": parsed}, separators=(",", ":"))
debug_args = json.dumps(
    ["build", "--secret", parsed[0], "--secret", parsed[1]],
    separators=(",", ":"),
)

print("aggregate:", repr(aggregate))
print("parsed:", parsed)
print("debug inputs:", debug_inputs)
print("debug args:", debug_args)
for secret in ("alpha-secret", "bravo-secret"):
    print(secret, "in debug inputs:", secret in debug_inputs,
          "in debug args:", secret in debug_args)
print("aggregate in debug inputs:", aggregate in debug_inputs)
print("aggregate in debug args:", aggregate in debug_args)
PY

Repository: samuelho-dev/git-flow

Length of output: 2917


Mask each credential inside build-secrets.

When ACTIONS_STEP_DEBUG is enabled, docker/build-push-action logs the parsed secrets input. The action logs each id=value entry separately, so masking only the original multi-line secret does not mask the individual credentials. Mask each credential before the action, or use separate workflow secrets.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/docker-build-push.yml around lines 87 - 93, Update the
workflow step that prepares or passes build-secrets so each individual
credential value is registered with GitHub Actions masking before
docker/build-push-action runs. Preserve the existing id=value, one-per-line
format and ensure every parsed secret value is masked separately, including when
ACTIONS_STEP_DEBUG is enabled.

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.

1 participant