149149 registry-auths :
150150 description : " Raw authentication to registries, defined as YAML objects (for image output)"
151151 required : false
152+ build-secrets :
153+ description : " YAML object mapping BuildKit secret IDs to values, with optional nested target mappings"
154+ required : false
152155 github-token :
153156 description : " GitHub Token used to authenticate against the repository for Git context"
154157 required : false
@@ -215,6 +218,7 @@ jobs:
215218 metaImages : ${{ steps.set.outputs.metaImages }}
216219 sign : ${{ steps.set.outputs.sign }}
217220 privateRepo : ${{ steps.set.outputs.privateRepo }}
221+ targets : ${{ steps.set.outputs.targets }}
218222 ghaCacheSign : ${{ steps.set.outputs.ghaCacheSign }}
219223 proxyNetwork : ${{ steps.set.outputs.proxyNetwork }}
220224 steps :
@@ -400,7 +404,7 @@ jobs:
400404 }
401405 );
402406 await core.group(`Set envs`, async () => {
403- core.info(JSON.stringify(envs, null, 2));
407+ core.info(JSON.stringify(Object.keys( envs).sort() , null, 2));
404408 });
405409
406410 const metaImages = inpMetaImages.map(image => image.toLowerCase());
@@ -414,9 +418,15 @@ jobs:
414418 try {
415419 await core.group(`Validating definition`, async () => {
416420 const bake = new Bake();
421+ // Resolve the graph without local secret files. The build job validates
422+ // secrets after applying the workflow-provided source overrides.
423+ const validationOverrides = inpSet.filter(override => {
424+ const key = override.split('=', 1)[0].split('.')[1];
425+ return !['secret', 'secrets', 'secrets+'].includes(key);
426+ });
417427 def = await bake.getDefinition({
418428 files: inpFiles,
419- overrides: inpSet ,
429+ overrides: [...validationOverrides, '*.secrets='] ,
420430 sbom: inpSbom ? `generator=${inpSbomImage}` : 'false',
421431 source: bakeSource,
422432 targets: [inpTarget]
@@ -426,8 +436,9 @@ jobs:
426436 if (!def) {
427437 throw new Error('Bake definition not set');
428438 }
429- BakeTargets.resolve(def, inpTarget);
439+ const targets = BakeTargets.resolve(def, inpTarget);
430440 target = inpTarget;
441+ core.setOutput('targets', JSON.stringify(targets));
431442 });
432443 } catch (error) {
433444 core.setFailed(error);
@@ -710,6 +721,82 @@ jobs:
710721 cosignPath,
711722 `${containerName}:/usr/bin/cosign`
712723 ]);
724+ -
725+ name : Configure AWS credentials
726+ if : ${{ needs.registry-identities.outputs.aws-ecr-enabled == 'true' }}
727+ uses : aws-actions/configure-aws-credentials@e1253824e5c10ff9df46874f81ed3ec929e19cfd # v6.3.0
728+ with :
729+ role-to-assume : ${{ needs.registry-identities.outputs.aws-ecr-role-to-assume }}
730+ aws-region : ${{ needs.registry-identities.outputs.aws-ecr-region }}
731+ -
732+ name : Login to Amazon ECR
733+ if : ${{ needs.registry-identities.outputs.aws-ecr-enabled == 'true' }}
734+ uses : docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
735+ env :
736+ AWS_ACCOUNT_IDS : ${{ needs.registry-identities.outputs.aws-ecr-account-ids }}
737+ with :
738+ registry-auth : |
739+ - registry: ${{ needs.registry-identities.outputs.aws-ecr-registry }}
740+ -
741+ name : Authenticate to Google Cloud
742+ id : gcp-wif-auth
743+ if : ${{ needs.registry-identities.outputs.gcp-wif-enabled == 'true' }}
744+ uses : google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
745+ with :
746+ token_format : access_token
747+ workload_identity_provider : ${{ needs.registry-identities.outputs.gcp-wif-workload-identity-provider }}
748+ service_account : ${{ needs.registry-identities.outputs.gcp-wif-service-account }}
749+ project_id : ${{ needs.registry-identities.outputs.gcp-wif-project-id }}
750+ create_credentials_file : false
751+ export_environment_variables : false
752+ -
753+ name : Login to Google Artifact Registry
754+ if : ${{ needs.registry-identities.outputs.gcp-wif-enabled == 'true' }}
755+ uses : docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
756+ with :
757+ registry-auth : |
758+ - registry: ${{ needs.registry-identities.outputs.gcp-wif-registry }}
759+ username: oauth2accesstoken
760+ password: ${{ steps.gcp-wif-auth.outputs.access_token }}
761+ -
762+ name : Login to Docker Hub with OIDC
763+ if : ${{ needs.registry-identities.outputs.dockerhub-oidc-enabled == 'true' }}
764+ uses : docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
765+ env :
766+ DOCKERHUB_OIDC_CONNECTIONID : ${{ needs.registry-identities.outputs.dockerhub-oidc-connection-id }}
767+ with :
768+ registry-auth : |
769+ - registry: ${{ needs.registry-identities.outputs.dockerhub-oidc-registry }}
770+ username: ${{ needs.registry-identities.outputs.dockerhub-oidc-username }}
771+ -
772+ name : Authenticate to Azure
773+ if : ${{ needs.registry-identities.outputs.azure-acr-enabled == 'true' }}
774+ uses : azure/login@a641126d1b8aa4d1fa005f4f92df94a3a4c4c906 # v3.1.0
775+ with :
776+ client-id : ${{ needs.registry-identities.outputs.azure-acr-client-id }}
777+ tenant-id : ${{ needs.registry-identities.outputs.azure-acr-tenant-id }}
778+ subscription-id : ${{ needs.registry-identities.outputs.azure-acr-subscription-id }}
779+ -
780+ name : Login to Azure Container Registry
781+ if : ${{ needs.registry-identities.outputs.azure-acr-enabled == 'true' }}
782+ env :
783+ ACR_REGISTRY : ${{ needs.registry-identities.outputs.azure-acr-registry }}
784+ AZURE_CORE_OUTPUT : none
785+ run : az acr login --name "${ACR_REGISTRY%.azurecr.io}"
786+ -
787+ name : Set up chainctl
788+ if : ${{ needs.registry-identities.outputs.chainguard-enabled == 'true' }}
789+ uses : chainguard-dev/setup-chainctl@2cddd35a2f120d9973e58094dc6878c93cf58c28 # v0.5.1
790+ with :
791+ identity : ${{ needs.registry-identities.outputs.chainguard-identity }}
792+ apk-host : ${{ needs.registry-identities.outputs.chainguard-apk-host }}
793+ libraries-host : ${{ needs.registry-identities.outputs.chainguard-libraries-host }}
794+ -
795+ name : Login to registry
796+ if : ${{ inputs.push && inputs.output == 'image' && env.REGISTRY_AUTHS_PRESENT == 'true' }}
797+ uses : docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
798+ with :
799+ registry-auth : ${{ secrets.registry-auths }}
713800 -
714801 name : Prepare
715802 id : prepare
@@ -721,6 +808,8 @@ jobs:
721808 INPUT_CACHE : ${{ inputs.cache }}
722809 INPUT_CACHE-SCOPE : ${{ inputs.cache-scope }}
723810 INPUT_CACHE-MODE : ${{ inputs.cache-mode }}
811+ INPUT_BUILD-SECRETS : ${{ secrets.build-secrets }}
812+ INPUT_TARGETS : ${{ needs.prepare.outputs.targets }}
724813 INPUT_CONTEXT : ${{ inputs.context }}
725814 INPUT_FILES : ${{ inputs.files }}
726815 INPUT_OUTPUT : ${{ inputs.output }}
@@ -737,15 +826,15 @@ jobs:
737826 INPUT_BAKE-FILE-TAGS : ${{ steps.meta.outputs.bake-file-tags }}
738827 INPUT_BAKE-FILE-ANNOTATIONS : ${{ steps.meta.outputs.bake-file-annotations }}
739828 INPUT_BAKE-FILE-LABELS : ${{ steps.meta.outputs.bake-file-labels }}
740- INPUT_GITHUB-TOKEN : ${{ secrets.github-token || github.token }}
741829 INPUT_BUILDKIT-PROXY-NETWORK : ${{ inputs.buildkit-proxy-network }}
742830 with :
743831 script : |
744832 const os = require('os');
745833 const { Build } = require('@docker/github-builder-runtime/lib/buildx/build');
834+ const { BuildSecrets } = require('@docker/github-builder-runtime/lib/github-builder/build-secrets');
746835 const { GitHub } = require('@docker/github-builder-runtime/lib/github/github');
747836 const { Util } = require('@docker/github-builder-runtime/lib/util');
748-
837+
749838 const inpPlatform = core.getInput('platform');
750839 const platformPairSuffix = inpPlatform ? `-${inpPlatform.replace(/\//g, '-')}` : '';
751840 core.setOutput('platform-pair-suffix', platformPairSuffix);
@@ -756,6 +845,8 @@ jobs:
756845 const inpCache = core.getBooleanInput('cache');
757846 const inpCacheScope = core.getInput('cache-scope');
758847 const inpCacheMode = core.getInput('cache-mode');
848+ const inpBuildSecrets = core.getInput('build-secrets', {trimWhitespace: false});
849+ const inpTargets = core.getInput('targets');
759850 const inpContext = core.getInput('context');
760851 const inpFiles = Util.getInputList('files');
761852 const inpOutput = core.getInput('output');
@@ -764,7 +855,6 @@ jobs:
764855 const inpSet = Util.getInputList('set', {ignoreComma: true, quote: false});
765856 const inpTarget = core.getInput('target');
766857 const inpVars = Util.getInputList('vars');
767- const inpGitHubToken = core.getInput('github-token');
768858 const inpBuildkitProxyNetwork = core.getBooleanInput('buildkit-proxy-network');
769859
770860 const inpMetaImages = core.getMultilineInput('meta-images');
@@ -781,7 +871,7 @@ jobs:
781871 tags: inpMetaTags
782872 };
783873 const renderTemplate = value => Util.compileHandlebars(value, {noEscape: true}, {meta});
784-
874+
785875 const gitContextAttrs = GitHub.context.ref.startsWith('refs/tags/') ? {checksum: GitHub.context.sha} : {'fetch-by-commit': 'true'};
786876 const bakeSource = await new Build().gitContext({subdir: inpContext, attrs: gitContextAttrs});
787877 await core.group(`Set source output`, async () => {
@@ -799,7 +889,16 @@ jobs:
799889 core.info(sbom);
800890 core.setOutput('sbom', sbom);
801891 });
802-
892+
893+ let buildSecrets;
894+ try {
895+ buildSecrets = BuildSecrets.prepareBake(inpBuildSecrets, inpTarget, JSON.parse(inpTargets || '[]'));
896+ } catch (err) {
897+ core.setFailed(err.message);
898+ return;
899+ }
900+ core.setOutput('secret-dir', buildSecrets.directory);
901+
803902 const envs = Object.assign({},
804903 inpVars ? inpVars.reduce((acc, curr) => {
805904 const idx = curr.indexOf('=');
@@ -809,12 +908,15 @@ jobs:
809908 return acc;
810909 }, {}) : {},
811910 {
812- BUILDKIT_MULTI_PLATFORM: '1',
813- BUILDX_BAKE_GIT_AUTH_TOKEN: inpGitHubToken
911+ BUILDKIT_MULTI_PLATFORM: '1'
814912 }
815913 );
914+
915+ // Git authentication is supplied directly to the Bake action.
916+ delete envs.BUILDX_BAKE_GIT_AUTH_TOKEN;
917+
816918 await core.group(`Set envs`, async () => {
817- core.info(JSON.stringify(envs, null, 2));
919+ core.info(JSON.stringify(Object.keys( envs).sort() , null, 2));
818920 core.setOutput('envs', JSON.stringify(envs));
819921 });
820922
@@ -878,85 +980,10 @@ jobs:
878980 bakeOverrides.push(`*.cache-from=type=gha,scope=${inpCacheScope || inpTarget}${platformPairSuffix}${proxyNetworkSuffix}`);
879981 bakeOverrides.push(`*.cache-to=type=gha,ignore-error=true,scope=${inpCacheScope || inpTarget}${platformPairSuffix}${proxyNetworkSuffix},mode=${inpCacheMode}`);
880982 }
983+ bakeOverrides.push(...buildSecrets.inputs);
881984 core.info(JSON.stringify(bakeOverrides, null, 2));
882985 core.setOutput('overrides', bakeOverrides.join(os.EOL));
883986 });
884- -
885- name : Configure AWS credentials
886- if : ${{ needs.registry-identities.outputs.aws-ecr-enabled == 'true' }}
887- uses : aws-actions/configure-aws-credentials@e1253824e5c10ff9df46874f81ed3ec929e19cfd # v6.3.0
888- with :
889- role-to-assume : ${{ needs.registry-identities.outputs.aws-ecr-role-to-assume }}
890- aws-region : ${{ needs.registry-identities.outputs.aws-ecr-region }}
891- -
892- name : Login to Amazon ECR
893- if : ${{ needs.registry-identities.outputs.aws-ecr-enabled == 'true' }}
894- uses : docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
895- env :
896- AWS_ACCOUNT_IDS : ${{ needs.registry-identities.outputs.aws-ecr-account-ids }}
897- with :
898- registry-auth : |
899- - registry: ${{ needs.registry-identities.outputs.aws-ecr-registry }}
900- -
901- name : Authenticate to Google Cloud
902- id : gcp-wif-auth
903- if : ${{ needs.registry-identities.outputs.gcp-wif-enabled == 'true' }}
904- uses : google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
905- with :
906- token_format : access_token
907- workload_identity_provider : ${{ needs.registry-identities.outputs.gcp-wif-workload-identity-provider }}
908- service_account : ${{ needs.registry-identities.outputs.gcp-wif-service-account }}
909- project_id : ${{ needs.registry-identities.outputs.gcp-wif-project-id }}
910- create_credentials_file : false
911- export_environment_variables : false
912- -
913- name : Login to Google Artifact Registry
914- if : ${{ needs.registry-identities.outputs.gcp-wif-enabled == 'true' }}
915- uses : docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
916- with :
917- registry-auth : |
918- - registry: ${{ needs.registry-identities.outputs.gcp-wif-registry }}
919- username: oauth2accesstoken
920- password: ${{ steps.gcp-wif-auth.outputs.access_token }}
921- -
922- name : Login to Docker Hub with OIDC
923- if : ${{ needs.registry-identities.outputs.dockerhub-oidc-enabled == 'true' }}
924- uses : docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
925- env :
926- DOCKERHUB_OIDC_CONNECTIONID : ${{ needs.registry-identities.outputs.dockerhub-oidc-connection-id }}
927- with :
928- registry-auth : |
929- - registry: ${{ needs.registry-identities.outputs.dockerhub-oidc-registry }}
930- username: ${{ needs.registry-identities.outputs.dockerhub-oidc-username }}
931- -
932- name : Authenticate to Azure
933- if : ${{ needs.registry-identities.outputs.azure-acr-enabled == 'true' }}
934- uses : azure/login@a641126d1b8aa4d1fa005f4f92df94a3a4c4c906 # v3.1.0
935- with :
936- client-id : ${{ needs.registry-identities.outputs.azure-acr-client-id }}
937- tenant-id : ${{ needs.registry-identities.outputs.azure-acr-tenant-id }}
938- subscription-id : ${{ needs.registry-identities.outputs.azure-acr-subscription-id }}
939- -
940- name : Login to Azure Container Registry
941- if : ${{ needs.registry-identities.outputs.azure-acr-enabled == 'true' }}
942- env :
943- ACR_REGISTRY : ${{ needs.registry-identities.outputs.azure-acr-registry }}
944- AZURE_CORE_OUTPUT : none
945- run : az acr login --name "${ACR_REGISTRY%.azurecr.io}"
946- -
947- name : Set up chainctl
948- if : ${{ needs.registry-identities.outputs.chainguard-enabled == 'true' }}
949- uses : chainguard-dev/setup-chainctl@2cddd35a2f120d9973e58094dc6878c93cf58c28 # v0.5.1
950- with :
951- identity : ${{ needs.registry-identities.outputs.chainguard-identity }}
952- apk-host : ${{ needs.registry-identities.outputs.chainguard-apk-host }}
953- libraries-host : ${{ needs.registry-identities.outputs.chainguard-libraries-host }}
954- -
955- name : Login to registry
956- if : ${{ inputs.push && inputs.output == 'image' && env.REGISTRY_AUTHS_PRESENT == 'true' }}
957- uses : docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
958- with :
959- registry-auth : ${{ secrets.registry-auths }}
960987 -
961988 name : Build
962989 id : bake
@@ -967,7 +994,18 @@ jobs:
967994 targets : ${{ steps.prepare.outputs.target }}
968995 sbom : ${{ steps.prepare.outputs.sbom }}
969996 set : ${{ steps.prepare.outputs.overrides }}
997+ github-token : ${{ secrets.github-token || github.token }}
970998 env : ${{ fromJson(steps.prepare.outputs.envs || '{}') }}
999+ -
1000+ name : Remove build secrets
1001+ if : ${{ always() && steps.prepare.outputs.secret-dir != '' }}
1002+ uses : actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1003+ env :
1004+ INPUT_SECRET-DIR : ${{ steps.prepare.outputs.secret-dir }}
1005+ with :
1006+ script : |
1007+ const { BuildSecrets } = require('@docker/github-builder-runtime/lib/github-builder/build-secrets');
1008+ BuildSecrets.cleanup(core.getInput('secret-dir', {required: true}));
9711009 -
9721010 name : Get image digest
9731011 id : get-image-digest
0 commit comments