From f96997d315e00b49d89d7864d8e213649887f748 Mon Sep 17 00:00:00 2001
From: Kaizen Conroy <36202692+kaizencc@users.noreply.github.com>
Date: Tue, 11 Feb 2025 10:29:23 -0500
Subject: [PATCH 1/5] fix: docker build attestations break cdk-assets (400 Bad
 Request) (#342)

There are various issues in cdk that can be traced back to attestations
in docker:

https://github.com/aws/aws-cdk/issues/30258
https://github.com/aws/aws-cdk/issues/31549
https://github.com/aws/aws-cdk/issues/33264

cdk-assets cannot work with docker containerd because it will attempt to
upload multiple files to the same hash in ECR, and our ECR repository is
immutable (by requirement). docker recently changed their default to
turn on containerd which causes this issue to skyrocket.

the hotfix here is to add an environment variable when calling `docker`
so that the attestation file is not added to the manifest. we can later
look into adding support for including
[provenance](https://docs.docker.com/build/metadata/attestations/slsa-provenance/)
attestations if there is need for it.

i've chosen to fix this via environment variable instead of as a command
option `--provenance=false` because we must keep docker replacements in
mind, and at least finch [does
not](https://runfinch.com/docs/cli-reference/finch_build/) have a
`provenance` property at the moment.

in addition to this unit test that shows the env variable exists when
`docker build` is called, i have also ensured that this solves the issue
in my local setup + symlinked `cdk-assets`..

(cherry picked from commit 8bdea135b8c3ee2f28f0c18f8d8ec912442c9025)

# Conflicts:
#	lib/private/docker.ts
#	test/private/docker.test.ts
---
 lib/private/docker.ts       |  7 +++++++
 test/private/docker.test.ts | 41 +++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)

diff --git a/lib/private/docker.ts b/lib/private/docker.ts
index 53f99a3..f861fe8 100644
--- a/lib/private/docker.ts
+++ b/lib/private/docker.ts
@@ -122,7 +122,14 @@ export class Docker {
     ];
     await this.execute(buildCommand, {
       cwd: options.directory,
+<<<<<<< HEAD
       quiet: options.quiet,
+=======
+      subprocessOutputDestination: this.subprocessOutputDestination,
+      env: {
+        BUILDX_NO_DEFAULT_ATTESTATIONS: '1', // Docker Build adds provenance attestations by default that confuse cdk-assets
+      },
+>>>>>>> 8bdea13 (fix: docker build attestations break cdk-assets (400 Bad Request) (#342))
     });
   }
 
diff --git a/test/private/docker.test.ts b/test/private/docker.test.ts
index a9f942a..e6f6863 100644
--- a/test/private/docker.test.ts
+++ b/test/private/docker.test.ts
@@ -6,8 +6,26 @@ type ShellExecuteMock = jest.SpyInstance<
   Parameters<Docker['execute']>
 >;
 
+let docker: Docker;
+
+const makeShellExecuteMock = (fn: (params: string[]) => void): ShellExecuteMock =>
+  jest
+    .spyOn<{ execute: Docker['execute'] }, 'execute'>(Docker.prototype as any, 'execute')
+    .mockImplementation(
+      async (params: string[], _options?: Omit<ShellOptions, 'shellEventPublisher'>) => fn(params)
+    );
+
+afterEach(() => {
+  jest.restoreAllMocks();
+});
+
+beforeEach(() => {
+  docker = new Docker(() => {}, 'ignore');
+});
+
 describe('Docker', () => {
   describe('exists', () => {
+<<<<<<< HEAD
     let docker: Docker;
 
     const makeShellExecuteMock = (fn: (params: string[]) => void): ShellExecuteMock =>
@@ -23,6 +41,8 @@ describe('Docker', () => {
       docker = new Docker();
     });
 
+=======
+>>>>>>> 8bdea13 (fix: docker build attestations break cdk-assets (400 Bad Request) (#342))
     test('returns true when image inspect command does not throw', async () => {
       const spy = makeShellExecuteMock(() => undefined);
 
@@ -92,4 +112,25 @@ describe('Docker', () => {
       expect(imageExists).toBe(false);
     });
   });
+
+  describe('build', () => {
+    test('includes BUILDX_NO_DEFAULT_ATTESTATIONS env variable in commands', async () => {
+      const spy = makeShellExecuteMock(() => undefined);
+
+      await docker.build({
+        directory: 'foo',
+        tag: 'bar',
+      });
+
+      // Verify the options passed to build
+      expect(spy).toHaveBeenCalledWith(
+        expect.any(Array),
+        expect.objectContaining({
+          env: expect.objectContaining({
+            BUILDX_NO_DEFAULT_ATTESTATIONS: '1',
+          }),
+        })
+      );
+    });
+  });
 });

From 0fe11fbf92e2bec5b6e43c894189601e35ea85c9 Mon Sep 17 00:00:00 2001
From: Kaizen Conroy <36202692+kaizencc@users.noreply.github.com>
Date: Tue, 11 Feb 2025 10:54:08 -0500
Subject: [PATCH 2/5] Apply suggestions from code review

---
 lib/private/docker.ts       | 3 ---
 test/private/docker.test.ts | 2 --
 2 files changed, 5 deletions(-)

diff --git a/lib/private/docker.ts b/lib/private/docker.ts
index f861fe8..2179861 100644
--- a/lib/private/docker.ts
+++ b/lib/private/docker.ts
@@ -122,14 +122,11 @@ export class Docker {
     ];
     await this.execute(buildCommand, {
       cwd: options.directory,
-<<<<<<< HEAD
       quiet: options.quiet,
-=======
       subprocessOutputDestination: this.subprocessOutputDestination,
       env: {
         BUILDX_NO_DEFAULT_ATTESTATIONS: '1', // Docker Build adds provenance attestations by default that confuse cdk-assets
       },
->>>>>>> 8bdea13 (fix: docker build attestations break cdk-assets (400 Bad Request) (#342))
     });
   }
 
diff --git a/test/private/docker.test.ts b/test/private/docker.test.ts
index e6f6863..1ea98a7 100644
--- a/test/private/docker.test.ts
+++ b/test/private/docker.test.ts
@@ -41,8 +41,6 @@ describe('Docker', () => {
       docker = new Docker();
     });
 
-=======
->>>>>>> 8bdea13 (fix: docker build attestations break cdk-assets (400 Bad Request) (#342))
     test('returns true when image inspect command does not throw', async () => {
       const spy = makeShellExecuteMock(() => undefined);
 

From 143b05b12d31095a760ba2c68b526dfead122143 Mon Sep 17 00:00:00 2001
From: Kaizen Conroy <36202692+kaizencc@users.noreply.github.com>
Date: Tue, 11 Feb 2025 10:54:31 -0500
Subject: [PATCH 3/5] Update lib/private/docker.ts

---
 lib/private/docker.ts | 1 -
 1 file changed, 1 deletion(-)

diff --git a/lib/private/docker.ts b/lib/private/docker.ts
index 2179861..2e584a3 100644
--- a/lib/private/docker.ts
+++ b/lib/private/docker.ts
@@ -123,7 +123,6 @@ export class Docker {
     await this.execute(buildCommand, {
       cwd: options.directory,
       quiet: options.quiet,
-      subprocessOutputDestination: this.subprocessOutputDestination,
       env: {
         BUILDX_NO_DEFAULT_ATTESTATIONS: '1', // Docker Build adds provenance attestations by default that confuse cdk-assets
       },

From 2ade861951b2ade2dd3c25bcb962a96e64665b57 Mon Sep 17 00:00:00 2001
From: Kaizen Conroy <36202692+kaizencc@users.noreply.github.com>
Date: Tue, 11 Feb 2025 10:54:49 -0500
Subject: [PATCH 4/5] Update test/private/docker.test.ts

---
 test/private/docker.test.ts | 1 -
 1 file changed, 1 deletion(-)

diff --git a/test/private/docker.test.ts b/test/private/docker.test.ts
index 1ea98a7..6de39ba 100644
--- a/test/private/docker.test.ts
+++ b/test/private/docker.test.ts
@@ -25,7 +25,6 @@ beforeEach(() => {
 
 describe('Docker', () => {
   describe('exists', () => {
-<<<<<<< HEAD
     let docker: Docker;
 
     const makeShellExecuteMock = (fn: (params: string[]) => void): ShellExecuteMock =>

From 60409d44470f670e50c33276e7db1acbe41e92d5 Mon Sep 17 00:00:00 2001
From: Kaizen Conroy <36202692+kaizencc@users.noreply.github.com>
Date: Tue, 11 Feb 2025 10:58:15 -0500
Subject: [PATCH 5/5] Update docker.test.ts

---
 test/private/docker.test.ts | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/test/private/docker.test.ts b/test/private/docker.test.ts
index 6de39ba..1782dc8 100644
--- a/test/private/docker.test.ts
+++ b/test/private/docker.test.ts
@@ -25,21 +25,6 @@ beforeEach(() => {
 
 describe('Docker', () => {
   describe('exists', () => {
-    let docker: Docker;
-
-    const makeShellExecuteMock = (fn: (params: string[]) => void): ShellExecuteMock =>
-      jest
-        .spyOn<{ execute: Docker['execute'] }, 'execute'>(Docker.prototype as any, 'execute')
-        .mockImplementation(async (params: string[], _options?: ShellOptions) => fn(params));
-
-    afterEach(() => {
-      jest.restoreAllMocks();
-    });
-
-    beforeEach(() => {
-      docker = new Docker();
-    });
-
     test('returns true when image inspect command does not throw', async () => {
       const spy = makeShellExecuteMock(() => undefined);