Skip to content

Commit cc64191

Browse files
authored
fix: Disable attestations and SBOMs for Heroku's container registry (#3350)
* Disable attestations and SBOMs for Heroku's container registry - disable attestations and SBOMs if the docker version is >= 24.0.0 - enforcing amd64 images coming from non-amd64 machines (aarch64) - enforce amd64 on push in addition to build Signed-off-by: Jesse Brown <jabrown85@gmail.com> * fixup! Disable attestations and SBOMs for Heroku's container registry Signed-off-by: Jesse Brown <jabrown85@gmail.com> --------- Signed-off-by: Jesse Brown <jabrown85@gmail.com>
1 parent dd36ca7 commit cc64191

File tree

3 files changed

+116
-6
lines changed

3 files changed

+116
-6
lines changed

packages/cli/src/commands/container/push.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export default class Push extends Command {
113113
hux.styledHeader(`Pushing ${job.name} (${job.dockerfile})`)
114114
}
115115

116-
await DockerHelper.pushImage(job.resource)
116+
await DockerHelper.pushImage(job.resource, this.config.arch)
117117
}
118118

119119
const plural = jobs.length !== 1

packages/cli/src/lib/container/docker_helper.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,14 @@ export const buildImage = async function ({dockerfile, resource, buildArgs, path
182182
const args = ['build', '-f', dockerfile, '-t', resource]
183183
// Older Docker versions don't allow for this flag, but we are
184184
// adding it here when necessary to allow for pushing a docker build from m1/m2 Macs.
185-
if (arch === 'arm64') args.push('--platform', 'linux/amd64')
185+
if (arch === 'arm64' || arch === 'aarch64') args.push('--platform', 'linux/amd64')
186+
187+
// newer docker versions support attestations and software bill of materials, so we want to disable them to save time/space
188+
// Heroku's container registry doesn't support pushing them right now
189+
if (await version() >= [24, 0, 0]) {
190+
args.push('--provenance', 'false')
191+
args.push('--sbom', 'false')
192+
}
186193

187194
for (const element of buildArgs) {
188195
if (element.length > 0) {
@@ -195,9 +202,14 @@ export const buildImage = async function ({dockerfile, resource, buildArgs, path
195202
return cmd('docker', args)
196203
}
197204

198-
export const pushImage = async function (resource: string) {
205+
export const pushImage = async function (resource: string, arch: string) {
199206
const args = ['push', resource]
200207

208+
// Older Docker versions don't allow for this flag, but we are
209+
// adding it here when necessary to allow for pushing a docker build from m1/m2 Macs.
210+
// Heroku's container registry doesn't support pushing multi-arch images so we need to push the expected arch
211+
if (arch === 'arm64' || arch === 'aarch64') args.push('--platform', 'linux/amd64')
212+
201213
return cmd('docker', args)
202214
}
203215

packages/cli/test/unit/lib/container/docker_helper.unit.test.ts

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,17 +208,43 @@ describe('DockerHelper', function () {
208208
})
209209

210210
it('successfully pushes image to DockerHelper cmd', async function () {
211+
const argsArray = ['push', 'registry.heroku.com/testapp/web', '--platform', 'linux/amd64']
211212
const eventStub = sandbox.stub(childProcess, 'spawn').callsFake(eventMock)
212213

213-
await DockerHelper.pushImage('registry.heroku.com/testapp/web')
214+
await DockerHelper.pushImage('registry.heroku.com/testapp/web', 'arm64')
215+
const options = eventStub.getCall(0).args[2]
216+
expect(eventStub.calledWith('docker', argsArray, options)).to.equal(true)
217+
})
214218

215-
expect(eventStub.calledOnce).to.equal(true)
219+
it('includes the platform flag when the arch is aarch64', async function () {
220+
const argsArray = ['push', 'registry.heroku.com/testapp/web', '--platform', 'linux/amd64']
221+
const eventStub = sandbox.stub(childProcess, 'spawn').callsFake(eventMock)
222+
223+
await DockerHelper.pushImage('registry.heroku.com/testapp/web', 'aarch64')
224+
const options = eventStub.getCall(0).args[2]
225+
expect(eventStub.calledWith('docker', argsArray, options)).to.equal(true)
226+
})
227+
228+
it('does not include the platform flag when the arch is not arm64', async function () {
229+
const argsArray = ['push', 'registry.heroku.com/testapp/web']
230+
const eventStub = sandbox.stub(childProcess, 'spawn').callsFake(eventMock)
231+
232+
await DockerHelper.pushImage('registry.heroku.com/testapp/web', 'amd64')
233+
const options = eventStub.getCall(0).args[2]
234+
expect(eventStub.calledWith('docker', argsArray, options)).to.equal(true)
216235
})
217236
})
218237

219238
describe('.buildImage', function () {
220239
const sandbox = sinon.createSandbox()
221240

241+
let versionStub: sinon.SinonStub
242+
243+
beforeEach(function () {
244+
versionStub = sandbox.stub(DockerHelper, 'version')
245+
versionStub.resolves([23, 99, 99])
246+
})
247+
222248
afterEach(function () {
223249
return sandbox.restore()
224250
})
@@ -241,7 +267,56 @@ describe('DockerHelper', function () {
241267
buildArgs: [],
242268
})
243269
const options = eventStub.getCall(0).args[2]
244-
console.log(eventStub.getCall(0).args)
270+
expect(eventStub.calledWith('docker', argsArray, options)).to.equal(true)
271+
})
272+
273+
it('includes the provenance and sbom flags when docker version is >= 24.0.0', async function () {
274+
versionStub.resolves([24, 0, 0])
275+
276+
const argsArray = [
277+
'build',
278+
'-f',
279+
'dockerfile',
280+
'-t',
281+
'registry.heroku.com/test-app/web',
282+
'--platform',
283+
'linux/amd64',
284+
'--provenance',
285+
'false',
286+
'--sbom',
287+
'false',
288+
'.',
289+
]
290+
const eventStub = sandbox.stub(childProcess, 'spawn').callsFake(eventMock)
291+
292+
await DockerHelper.buildImage({
293+
dockerfile: 'dockerfile',
294+
resource: 'registry.heroku.com/test-app/web',
295+
buildArgs: [],
296+
arch: 'arm64',
297+
})
298+
const options = eventStub.getCall(0).args[2]
299+
expect(eventStub.calledWith('docker', argsArray, options)).to.equal(true)
300+
})
301+
302+
it('does not include the platform flag when the arch is not arm64', async function () {
303+
const argsArray = [
304+
'build',
305+
'-f',
306+
'dockerfile',
307+
'-t',
308+
'registry.heroku.com/test-app/web',
309+
'.',
310+
]
311+
312+
const eventStub = sandbox.stub(childProcess, 'spawn').callsFake(eventMock)
313+
314+
await DockerHelper.buildImage({
315+
dockerfile: 'dockerfile',
316+
resource: 'registry.heroku.com/test-app/web',
317+
buildArgs: [],
318+
})
319+
const options = eventStub.getCall(0).args[2]
245320
expect(eventStub.calledWith('docker', argsArray, options)).to.equal(true)
246321
})
247322

@@ -267,5 +342,28 @@ describe('DockerHelper', function () {
267342
const options = eventStub.getCall(0).args[2]
268343
expect(eventStub.calledWith('docker', argsArray, options)).to.equal(true)
269344
})
345+
346+
it('includes the platform flag when arch is aarch64', async function () {
347+
const argsArray = [
348+
'build',
349+
'-f',
350+
'dockerfile',
351+
'-t',
352+
'registry.heroku.com/test-app/web',
353+
'--platform',
354+
'linux/amd64',
355+
'.',
356+
]
357+
const eventStub = sandbox.stub(childProcess, 'spawn').callsFake(eventMock)
358+
359+
await DockerHelper.buildImage({
360+
dockerfile: 'dockerfile',
361+
resource: 'registry.heroku.com/test-app/web',
362+
buildArgs: [],
363+
arch: 'aarch64',
364+
})
365+
const options = eventStub.getCall(0).args[2]
366+
expect(eventStub.calledWith('docker', argsArray, options)).to.equal(true)
367+
})
270368
})
271369
})

0 commit comments

Comments
 (0)