Skip to content

Commit

Permalink
distribute: pin dependencies and sanitize inputs
Browse files Browse the repository at this point in the history
Signed-off-by: CrazyMax <[email protected]>
  • Loading branch information
crazy-max committed Feb 17, 2025
1 parent 5f34045 commit b7a3986
Showing 1 changed file with 73 additions and 36 deletions.
109 changes: 73 additions & 36 deletions .github/workflows/distribute.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,12 @@ on:
type: boolean
description: "Do not use cache when building the image"
required: false
default: false
bake-pull:
type: boolean
description: "Always attempt to pull a newer version of the image"
required: false
default: false
bake-provenance:
type: string
description: "Provenance is a shorthand for --set=*.attest=type=provenance"
Expand All @@ -108,73 +110,100 @@ on:
description: "API token used to authenticate to a Git repository for remote definitions"
required: false

env:
ACTIONS_TOOLKIT_VERSION: "0.54.0"
HANDLEBARS_VERSION: "4.7.8"

jobs:
prepare:
runs-on: ubuntu-latest
outputs:
includes: ${{ steps.set.outputs.includes }}
steps:
-
name: Install npm dependencies
uses: actions/github-script@v7
with:
script: |
await exec.exec('npm', ['install',
'@docker/actions-toolkit@${{ env.ACTIONS_TOOLKIT_VERSION }}',
'handlebars@${{ env.HANDLEBARS_VERSION }}'
]);
-
name: Set includes
id: set
uses: actions/github-script@v7
env:
INPUT_RUNNER: ${{ inputs.runner }}
INPUT_TARGET: ${{ inputs.target }}
INPUT_META-IMAGE: ${{ inputs.meta-image }}
INPUT_BAKE-ALLOW: ${{ inputs.bake-allow }}
INPUT_BAKE-FILES: ${{ inputs.bake-files }}
INPUT_BAKE-NO-CACHE: ${{ inputs.bake-no-cache }}
INPUT_BAKE-PROVENANCE: ${{ inputs.bake-provenance }}
INPUT_BAKE-SBOM: ${{ inputs.bake-sbom }}
INPUT_BAKE-SET: ${{ inputs.bake-set }}
INPUT_BAKE-SOURCE: ${{ inputs.bake-source }}
GITHUB_TOKEN: ${{ secrets.github-token || github.token }}
with:
script: |
let def;
const files = `${{ inputs.bake-files }}` ? `${{ inputs.bake-files }}`.split(/[\r?\n,]+/).filter(Boolean) : [];
const target = `${{ inputs.target }}`;
const handlebars = require('handlebars');
const { Bake } = require('@docker/actions-toolkit/lib/buildx/bake');
const { Build } = require('@docker/actions-toolkit/lib/buildx/build');
const { Context } = require('@docker/actions-toolkit/lib/context');
const { Util } = require('@docker/actions-toolkit/lib/util');
const metaImage = `${{ inputs.meta-image }}` ? `${{ inputs.meta-image }}`.split(/[\r?\n,]+/).filter(Boolean) : [];
if (metaImage.length > 1) {
if (Util.getInputList('meta-image').length > 1) {
throw new Error('Only one meta-image is allowed');
}
await core.group(`Install npm dependencies`, async () => {
await exec.exec('npm', ['install', '@docker/actions-toolkit', 'handlebars']);
const inpRunner = core.getInput('runner');
const inpTarget = core.getInput('target');
const inpBakeAllow = Util.getInputList('bake-allow');
const inpBakeFiles = Util.getInputList('bake-files');
const inpBakeNoCache = core.getBooleanInput('bake-no-cache');
const inpBakeProvenance = Build.getProvenanceInput('bake-provenance');
const inpBakeSbom = core.getInput('bake-sbom');
const inpBakeSet = Util.getInputList('bake-set', {ignoreComma: true, quote: false});
let inpBakeSource = handlebars.compile(core.getInput('source'))({
defaultContext: Context.gitContext()
});
if (!inpBakeSource) {
inpBakeSource = Context.gitContext();
}
if (inpBakeSource === '.') {
inpBakeSource = '';
}
let def;
await core.group(`Validating definition`, async () => {
const handlebars = require('handlebars');
const { Context } = require('@docker/actions-toolkit/lib/context');
const { Bake } = require('@docker/actions-toolkit/lib/buildx/bake');
let source = handlebars.compile(`${{ inputs.bake-source }}`)({
defaultContext: Context.gitContext()
});
if (!source) {
source = Context.gitContext();
}
if (source === '.') {
source = '';
}
const bake = new Bake();
def = await bake.getDefinition({
allow: `${{ inputs.bake-allow }}` ? `${{ inputs.bake-allow }}`.split(/[\r?\n,]+/).filter(Boolean) : [],
files: `${{ inputs.bake-files }}` ? `${{ inputs.bake-files }}`.split(/[\r?\n,]+/).filter(Boolean) : [],
noCache: ${{ inputs.bake-no-cache }},
overrides: `${{ inputs.bake-set }}` ? `${{ inputs.bake-set }}`.split(/[\r?\n,]+/).filter(Boolean) : [],
provenance: `${{ inputs.bake-provenance }}`,
sbom: `${{ inputs.bake-sbom }}`,
source: source,
targets: [`${{ inputs.target }}`],
githubToken: `${{ secrets.github-token || github.token }}`
allow: inpBakeAllow,
files: inpBakeFiles,
noCache: inpBakeNoCache,
overrides: inpBakeSet,
provenance: inpBakeProvenance,
sbom: inpBakeSbom,
source: inpBakeSource,
targets: [inpTarget],
githubToken: process.env.GITHUB_TOKEN
});
if (!def) {
throw new Error('Bake definition not set');
}
});
await core.group(`Set includes`, async () => {
const platforms = def.target[target].platforms;
const platforms = def.target[inpTarget].platforms;
if (platforms.length > 100) {
throw new Error('Too many platforms');
} else if (platforms.length <= 1) {
throw new Error('At least 2 platforms are required');
}
let includes = [];
platforms.forEach((platform, index) => {
let runner = `${{ inputs.runner }}`;
let runner = inpRunner;
if (runner === 'auto') {
runner = platform.startsWith('linux/arm') ? 'ubuntu-24.04-arm' : 'ubuntu-latest';
}
Expand Down Expand Up @@ -353,10 +382,12 @@ jobs:
name: Set digest output
id: digest
uses: actions/github-script@v7
env:
INPUT_TARGET: ${{ inputs.target }}
with:
script: |
const metadata = JSON.parse(`${{ steps.bake.outputs.metadata }}`);
const digest = metadata[`${{ inputs.target }}`]['containerimage.digest'];
const digest = metadata[core.getInput('target')]['containerimage.digest'];
const outputKey = `digest_${{ matrix.index }}`;
core.info(`Setting digest output: ${outputKey}=${digest}`);
core.setOutput(outputKey, digest);
Expand Down Expand Up @@ -392,8 +423,14 @@ jobs:
-
name: Create manifest list
uses: actions/github-script@v7
env:
INPUT_PUSH: ${{ inputs.push }}
INPUT_META-IMAGE: ${{ inputs.meta-image }}
with:
script: |
const inpPush = core.getBooleanInput('push');
const inpMetaImage = core.getInput('meta-image');
let digests = [];
await core.group(`Digests`, async () => {
digests = Object.values(JSON.parse(`${{ toJSON(needs.build.outputs) }}`));
Expand All @@ -411,10 +448,10 @@ jobs:
createArgs.push(`-t`, tag);
}
for (const digest of digests) {
createArgs.push(`${{ inputs.meta-image }}@${digest}`);
createArgs.push(`${inpMetaImage}@${digest}`);
}
if (${{ inputs.push }}) {
if (inpPush) {
if (tags.length === 0) {
throw new Error('No tags to create manifest list');
}
Expand All @@ -426,7 +463,7 @@ jobs:
}
});
await core.group(`Inspect image`, async () => {
await exec.getExecOutput('docker', ['buildx', 'imagetools', 'inspect', `${{ inputs.meta-image }}:${tags[0]}`], {
await exec.getExecOutput('docker', ['buildx', 'imagetools', 'inspect', `${inpMetaImage}:${tags[0]}`], {
ignoreReturnCode: true
}).then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
Expand Down

0 comments on commit b7a3986

Please sign in to comment.