build/bake: BuildKit secrets support#248
Conversation
8a0cb82 to
f81277e
Compare
| envs[envName] = secret; | ||
| secretEnvs.push(`${id}=${envName}`); | ||
| }); | ||
| core.setOutput('envs', JSON.stringify(envs)); |
There was a problem hiding this comment.
Are these setOutput calls really safe?
There was a problem hiding this comment.
I changed this so secret-bearing env values are exported with core.exportVariable(...) instead of being serialized through core.setOutput('envs', ...). The later env: ${{ fromJson(steps.prepare.outputs.envs || '{}') }} plumbing is gone from both build steps.
secret-envs remains an output in build.yml, but that only contains secret_id=ENV_NAME mappings, not secret values.
| Object.entries(buildSecrets).forEach(([id, secret], index) => { | ||
| const envName = toBuildSecretEnvName(id, index); | ||
| envs[envName] = secret; | ||
| secretOverrides.push(`*.secrets+=id=${id},env=${envName}`); |
There was a problem hiding this comment.
Why is this adding secrets to the definition? I would think secrets need to be defined already and just values are loaded here.
There was a problem hiding this comment.
I dug into this more and I think the secrets+= override is intentional here.
For Bake, target.secret defines both the BuildKit secret ID and the source for that secret. If a caller has secret = ["id=foo,env=MY_FOO"], only exporting another env var from the workflow does not change what Bake uses. Using *.secrets+=id=foo,env=<internal env> replaces the existing same-ID secret source instead of duplicating it, which I verified with buildx bake --print.
That keeps the reusable workflow contract as build-secrets: { foo: value } and avoids making callers reference github-builder internal env names in their Bake files. It also lets existing Bake targets keep local sources for direct docker buildx bake usage, while the reusable workflow overrides those sources when a matching build-secrets entry is provided.
I updated the docs to avoid saying file-based secrets are supported as workflow payloads. The workflow still accepts secret values only and exposes them to BuildKit from env vars. A Bake target can still declare a file source for local use, for example type=file,id=aws,src=${HOME}/.aws/credentials, and the reusable workflow overrides that source when build-secrets contains aws.
| try { | ||
| parsed = yaml.load(normalized, {schema: yaml.FAILSAFE_SCHEMA}); | ||
| } catch (err) { | ||
| throw new Error(`Failed to parse build-secrets YAML: ${err.message}`); |
There was a problem hiding this comment.
Can't this leak secret value? Same in bake.yml.
There was a problem hiding this comment.
Hum you right. Made some changes so malformed build-secrets YAML no longer reports err.message, which can include source snippets from the secret-bearing YAML. It now reports only:
Failed to parse build-secrets YAML at line X, column Y
| GIT_AUTH_TOKEN: inpGitHubToken | ||
| }; | ||
| const secretEnvs = ['GIT_AUTH_TOKEN=GIT_AUTH_TOKEN']; | ||
| Object.entries(buildSecrets).forEach(([id, secret], index) => { |
There was a problem hiding this comment.
Do we need to verify that GIT_AUTH_TOKEN is not overwritten?
There was a problem hiding this comment.
Yes good catch, I added a guard that rejects a user-provided BuildKit secret ID of GIT_AUTH_TOKEN.
| if (!parsed) { | ||
| return {}; | ||
| } | ||
| if (!parsed || Array.isArray(parsed) || typeof parsed !== 'object') { |
There was a problem hiding this comment.
second !parsed is dead code here
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
f81277e to
4fc7e6b
Compare
fixes #40
closes #239
This adds BuildKit secret support to the build and bake reusable workflows through a shared
build-secretsworkflow secret.The new
build-secretssecret accepts a YAML object that maps BuildKit secret IDs to secret values. The build workflow parses that YAML and forwards each entry todocker/build-push-actionthroughsecret-envs. The bake workflow uses the same contract and appends*.secrets+=id=...,env=...overrides fordocker/bake-action, which replaces existing same-ID Bake secret sources when they are already declared.A caller can pass a literal multiline secret with YAML block syntax.
A caller can also pass GitHub secrets through
toJSON(...)so multiline values and YAML-sensitive characters are preserved.Reusable workflows cannot accept arbitrary dynamic secret names, so this keeps the public contract stable while still allowing callers to provide any BuildKit secret ID they need.
The workflow does not accept file paths as secret payloads. Bake targets can still declare file-based secret sources for local
docker buildx bakeusage, and matchingbuild-secretsentries override those sources with env-backed workflow-provided values during the reusable workflow run.