This updates the keychain setup script to wait after verification fails and re-check after a few seconds. It may be that is takes a little time to build the certificate chain.

This also wraps calling the keychain setup script in a retry.

Bug: https://github.com/flutter/flutter/issues/168342
Change-Id: I09cd0a68df9a144dd93dda61bce3c5f656bbb6ba
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/65802
Commit-Queue: Victoria Ashworth <vashworth@google.com>
Reviewed-by: Matan Lurey <matanl@google.com>
diff --git a/recipe_modules/signing/__init__.py b/recipe_modules/signing/__init__.py
index 81ceec8..747b5e6 100644
--- a/recipe_modules/signing/__init__.py
+++ b/recipe_modules/signing/__init__.py
@@ -6,6 +6,7 @@
     'depot_tools/gsutil',
     'flutter/flutter_deps',
     'flutter/kms',
+    'flutter/retry',
     'flutter/zip',
     'recipe_engine/buildbucket',
     'recipe_engine/context',
@@ -16,4 +17,5 @@
     'recipe_engine/raw_io',
     'recipe_engine/runtime',
     'recipe_engine/step',
+    'recipe_engine/uuid',
 ]
diff --git a/recipe_modules/signing/api.py b/recipe_modules/signing/api.py
index 4cc5165..7be3f7f 100644
--- a/recipe_modules/signing/api.py
+++ b/recipe_modules/signing/api.py
@@ -112,21 +112,35 @@
 
     env['SETUP_KEYCHAIN_LOGS_PATH'] = setup_keychain_log_file
     with self.m.context(env=env, env_prefixes=env_prefixes):
-      try:
-        self.m.step(
-            'run keychain setup script', [resource_name],
-        )
-      finally:
-        # This will namespace the remote GCS path by the buildbucket build ID
-        buildbucket_id = self.m.buildbucket.build.id
-        remote_path = '%s/setup_keychain_logs.txt' % buildbucket_id
-        self.m.gsutil.upload(
-            bucket='flutter_tmp_logs',
-            source=setup_keychain_log_file,
-            dest=remote_path,
-            args=['-r'],
-            name='upload debug logs to %s' % remote_path
-        )
+      self.m.retry.basic_wrap(
+          lambda timeout: self._run_keychain_setup_script(
+              resource_name,
+              setup_keychain_log_file,
+          ),
+          max_attempts=3
+      )
+
+  def _run_keychain_setup_script(self, resource_name, setup_keychain_log_file):
+    try:
+      self.m.step(
+          'run keychain setup script',
+          [resource_name],
+      )
+    finally:
+      # This will namespace the remote GCS path by the buildbucket build ID
+      buildbucket_id = self.m.buildbucket.build.id
+
+      # Setup may occur multiple times during a build. Use a unique identifier
+      # so logs aren't overwritten.
+      uuid = self.m.uuid.random()
+      remote_path = '%s/setup_keychain_logs_%s.txt' % (buildbucket_id, uuid)
+      self.m.gsutil.upload(
+          bucket='flutter_tmp_logs',
+          source=setup_keychain_log_file,
+          dest=remote_path,
+          args=['-r'],
+          name='upload debug logs to %s' % remote_path
+      )
 
   def _signer_tasks(self, env, env_prefixes, files_to_sign):
     """Concurrently creates jobs to codesign each binary.
diff --git a/recipe_modules/signing/examples/code_sign.expected/failing_keychain.json b/recipe_modules/signing/examples/code_sign.expected/failing_keychain.json
new file mode 100644
index 0000000..40a152c
--- /dev/null
+++ b/recipe_modules/signing/examples/code_sign.expected/failing_keychain.json
@@ -0,0 +1,536 @@
+[
+  {
+    "cmd": [
+      "sw_vers",
+      "-productVersion"
+    ],
+    "name": "find macOS version"
+  },
+  {
+    "cmd": [],
+    "name": "Codesign Dependencies"
+  },
+  {
+    "cmd": [],
+    "name": "Codesign Dependencies.Installing Mac codesign CIPD pkg",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CLEANUP]/tmp_tmp_1",
+      "-ensure-file",
+      "flutter/codesign/${platform} latest",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "Codesign Dependencies.Installing Mac codesign CIPD pkg.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-latest----------\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"flutter/codesign/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "Setup codesign environment"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cloudkms",
+      "-ensure-file",
+      "infra/tools/luci/cloudkms/${platform} latest",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "Setup codesign environment.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-latest----------\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/cloudkms/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::gsutil]/resources/gsutil_smart_retry.py",
+      "--",
+      "RECIPE_REPO[depot_tools]/gsutil.py",
+      "----",
+      "cp",
+      "gs://flutter_configs/exported_p12.encrypted",
+      "[CLEANUP]/exported_p12.encrypted"
+    ],
+    "infra_step": true,
+    "name": "Setup codesign environment.gsutil download",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cloudkms/cloudkms",
+      "decrypt",
+      "-input",
+      "[CLEANUP]/exported_p12.encrypted",
+      "-output",
+      "[CLEANUP]/FLUTTER_P12",
+      "projects/flutter-infra-staging/locations/global/keyRings/luci/cryptoKeys/flutter-infra"
+    ],
+    "name": "Setup codesign environment.cloudkms get key",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cloudkms",
+      "-ensure-file",
+      "infra/tools/luci/cloudkms/${platform} latest",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "Setup codesign environment.ensure_installed (2)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-latest----------\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/cloudkms/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::gsutil]/resources/gsutil_smart_retry.py",
+      "--",
+      "RECIPE_REPO[depot_tools]/gsutil.py",
+      "----",
+      "cp",
+      "gs://flutter_configs/0325_p12password.encrypted",
+      "[CLEANUP]/0325_p12password.encrypted"
+    ],
+    "infra_step": true,
+    "name": "Setup codesign environment.gsutil download (2)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cloudkms/cloudkms",
+      "decrypt",
+      "-input",
+      "[CLEANUP]/0325_p12password.encrypted",
+      "-output",
+      "[CLEANUP]/FLUTTER_P12_PASSWORD",
+      "projects/flutter-infra-staging/locations/global/keyRings/luci/cryptoKeys/flutter-infra"
+    ],
+    "name": "Setup codesign environment.cloudkms get key (2)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cloudkms",
+      "-ensure-file",
+      "infra/tools/luci/cloudkms/${platform} latest",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "Setup codesign environment.ensure_installed (3)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-latest----------\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/cloudkms/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::gsutil]/resources/gsutil_smart_retry.py",
+      "--",
+      "RECIPE_REPO[depot_tools]/gsutil.py",
+      "----",
+      "cp",
+      "gs://flutter_configs/codesign_team_id.encrypted",
+      "[CLEANUP]/codesign_team_id.encrypted"
+    ],
+    "infra_step": true,
+    "name": "Setup codesign environment.gsutil download (3)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cloudkms/cloudkms",
+      "decrypt",
+      "-input",
+      "[CLEANUP]/codesign_team_id.encrypted",
+      "-output",
+      "[CLEANUP]/CODESIGN_TEAM_ID",
+      "projects/flutter-infra-staging/locations/global/keyRings/luci/cryptoKeys/flutter-infra"
+    ],
+    "name": "Setup codesign environment.cloudkms get key (3)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cloudkms",
+      "-ensure-file",
+      "infra/tools/luci/cloudkms/${platform} latest",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "Setup codesign environment.ensure_installed (4)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-latest----------\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/cloudkms/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::gsutil]/resources/gsutil_smart_retry.py",
+      "--",
+      "RECIPE_REPO[depot_tools]/gsutil.py",
+      "----",
+      "cp",
+      "gs://flutter_configs/codesign_app_specific_password.encrypted",
+      "[CLEANUP]/codesign_app_specific_password.encrypted"
+    ],
+    "infra_step": true,
+    "name": "Setup codesign environment.gsutil download (4)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cloudkms/cloudkms",
+      "decrypt",
+      "-input",
+      "[CLEANUP]/codesign_app_specific_password.encrypted",
+      "-output",
+      "[CLEANUP]/CODESIGN_APP_SPECIFIC_PASSWORD",
+      "projects/flutter-infra-staging/locations/global/keyRings/luci/cryptoKeys/flutter-infra"
+    ],
+    "name": "Setup codesign environment.cloudkms get key (4)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cloudkms",
+      "-ensure-file",
+      "infra/tools/luci/cloudkms/${platform} latest",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "Setup codesign environment.ensure_installed (5)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-latest----------\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/cloudkms/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::gsutil]/resources/gsutil_smart_retry.py",
+      "--",
+      "RECIPE_REPO[depot_tools]/gsutil.py",
+      "----",
+      "cp",
+      "gs://flutter_configs/codesign_app_store_id.encrypted",
+      "[CLEANUP]/codesign_app_store_id.encrypted"
+    ],
+    "infra_step": true,
+    "name": "Setup codesign environment.gsutil download (5)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cloudkms/cloudkms",
+      "decrypt",
+      "-input",
+      "[CLEANUP]/codesign_app_store_id.encrypted",
+      "-output",
+      "[CLEANUP]/CODESIGN_APP_STORE_ID",
+      "projects/flutter-infra-staging/locations/global/keyRings/luci/cryptoKeys/flutter-infra"
+    ],
+    "name": "Setup codesign environment.cloudkms get key (5)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "Setup keychain"
+  },
+  {
+    "cmd": [
+      "chmod",
+      "755",
+      "RECIPE_MODULE[flutter::signing]/resources/setup_keychain.dart"
+    ],
+    "infra_step": true,
+    "name": "Setup keychain.Set execute permission",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "RECIPE_MODULE[flutter::signing]/resources/setup_keychain.dart"
+    ],
+    "env": {
+      "CODESIGN_APP_SPECIFIC_PASSWORD": "[CLEANUP]/CODESIGN_APP_SPECIFIC_PASSWORD",
+      "CODESIGN_APP_STORE_ID": "[CLEANUP]/CODESIGN_APP_STORE_ID",
+      "CODESIGN_PATH": "[CLEANUP]/tmp_tmp_1/codesign",
+      "CODESIGN_TEAM_ID": "[CLEANUP]/CODESIGN_TEAM_ID",
+      "FLUTTER_P12": "[CLEANUP]/FLUTTER_P12",
+      "FLUTTER_P12_PASSWORD": "[CLEANUP]/FLUTTER_P12_PASSWORD",
+      "P12_SUFFIX_FILEPATH": "[CLEANUP]/flutter.p12",
+      "SETUP_KEYCHAIN_LOGS_PATH": "[CLEANUP]/setup_keychain_logs.txt"
+    },
+    "name": "run keychain setup script",
+    "~followup_annotations": [
+      "@@@STEP_FAILURE@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::gsutil]/resources/gsutil_smart_retry.py",
+      "--",
+      "RECIPE_REPO[depot_tools]/gsutil.py",
+      "----",
+      "cp",
+      "-r",
+      "[CLEANUP]/setup_keychain_logs.txt",
+      "gs://flutter_tmp_logs/0/setup_keychain_logs_00000000-0000-0000-0000-000000001337.txt"
+    ],
+    "env": {
+      "CODESIGN_APP_SPECIFIC_PASSWORD": "[CLEANUP]/CODESIGN_APP_SPECIFIC_PASSWORD",
+      "CODESIGN_APP_STORE_ID": "[CLEANUP]/CODESIGN_APP_STORE_ID",
+      "CODESIGN_PATH": "[CLEANUP]/tmp_tmp_1/codesign",
+      "CODESIGN_TEAM_ID": "[CLEANUP]/CODESIGN_TEAM_ID",
+      "FLUTTER_P12": "[CLEANUP]/FLUTTER_P12",
+      "FLUTTER_P12_PASSWORD": "[CLEANUP]/FLUTTER_P12_PASSWORD",
+      "P12_SUFFIX_FILEPATH": "[CLEANUP]/flutter.p12",
+      "SETUP_KEYCHAIN_LOGS_PATH": "[CLEANUP]/setup_keychain_logs.txt"
+    },
+    "infra_step": true,
+    "name": "gsutil upload debug logs to 0/setup_keychain_logs_00000000-0000-0000-0000-000000001337.txt",
+    "~followup_annotations": [
+      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/0/setup_keychain_logs_00000000-0000-0000-0000-000000001337.txt@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "RECIPE_MODULE[flutter::signing]/resources/setup_keychain.dart"
+    ],
+    "env": {
+      "CODESIGN_APP_SPECIFIC_PASSWORD": "[CLEANUP]/CODESIGN_APP_SPECIFIC_PASSWORD",
+      "CODESIGN_APP_STORE_ID": "[CLEANUP]/CODESIGN_APP_STORE_ID",
+      "CODESIGN_PATH": "[CLEANUP]/tmp_tmp_1/codesign",
+      "CODESIGN_TEAM_ID": "[CLEANUP]/CODESIGN_TEAM_ID",
+      "FLUTTER_P12": "[CLEANUP]/FLUTTER_P12",
+      "FLUTTER_P12_PASSWORD": "[CLEANUP]/FLUTTER_P12_PASSWORD",
+      "P12_SUFFIX_FILEPATH": "[CLEANUP]/flutter.p12",
+      "SETUP_KEYCHAIN_LOGS_PATH": "[CLEANUP]/setup_keychain_logs.txt"
+    },
+    "name": "run keychain setup script (2)",
+    "~followup_annotations": [
+      "@@@STEP_FAILURE@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::gsutil]/resources/gsutil_smart_retry.py",
+      "--",
+      "RECIPE_REPO[depot_tools]/gsutil.py",
+      "----",
+      "cp",
+      "-r",
+      "[CLEANUP]/setup_keychain_logs.txt",
+      "gs://flutter_tmp_logs/0/setup_keychain_logs_00000000-0000-0000-0000-00000000133a.txt"
+    ],
+    "env": {
+      "CODESIGN_APP_SPECIFIC_PASSWORD": "[CLEANUP]/CODESIGN_APP_SPECIFIC_PASSWORD",
+      "CODESIGN_APP_STORE_ID": "[CLEANUP]/CODESIGN_APP_STORE_ID",
+      "CODESIGN_PATH": "[CLEANUP]/tmp_tmp_1/codesign",
+      "CODESIGN_TEAM_ID": "[CLEANUP]/CODESIGN_TEAM_ID",
+      "FLUTTER_P12": "[CLEANUP]/FLUTTER_P12",
+      "FLUTTER_P12_PASSWORD": "[CLEANUP]/FLUTTER_P12_PASSWORD",
+      "P12_SUFFIX_FILEPATH": "[CLEANUP]/flutter.p12",
+      "SETUP_KEYCHAIN_LOGS_PATH": "[CLEANUP]/setup_keychain_logs.txt"
+    },
+    "infra_step": true,
+    "name": "gsutil upload debug logs to 0/setup_keychain_logs_00000000-0000-0000-0000-00000000133a.txt",
+    "~followup_annotations": [
+      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/0/setup_keychain_logs_00000000-0000-0000-0000-00000000133a.txt@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "RECIPE_MODULE[flutter::signing]/resources/setup_keychain.dart"
+    ],
+    "env": {
+      "CODESIGN_APP_SPECIFIC_PASSWORD": "[CLEANUP]/CODESIGN_APP_SPECIFIC_PASSWORD",
+      "CODESIGN_APP_STORE_ID": "[CLEANUP]/CODESIGN_APP_STORE_ID",
+      "CODESIGN_PATH": "[CLEANUP]/tmp_tmp_1/codesign",
+      "CODESIGN_TEAM_ID": "[CLEANUP]/CODESIGN_TEAM_ID",
+      "FLUTTER_P12": "[CLEANUP]/FLUTTER_P12",
+      "FLUTTER_P12_PASSWORD": "[CLEANUP]/FLUTTER_P12_PASSWORD",
+      "P12_SUFFIX_FILEPATH": "[CLEANUP]/flutter.p12",
+      "SETUP_KEYCHAIN_LOGS_PATH": "[CLEANUP]/setup_keychain_logs.txt"
+    },
+    "name": "run keychain setup script (3)",
+    "~followup_annotations": [
+      "@@@STEP_FAILURE@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::gsutil]/resources/gsutil_smart_retry.py",
+      "--",
+      "RECIPE_REPO[depot_tools]/gsutil.py",
+      "----",
+      "cp",
+      "-r",
+      "[CLEANUP]/setup_keychain_logs.txt",
+      "gs://flutter_tmp_logs/0/setup_keychain_logs_00000000-0000-0000-0000-00000000133d.txt"
+    ],
+    "env": {
+      "CODESIGN_APP_SPECIFIC_PASSWORD": "[CLEANUP]/CODESIGN_APP_SPECIFIC_PASSWORD",
+      "CODESIGN_APP_STORE_ID": "[CLEANUP]/CODESIGN_APP_STORE_ID",
+      "CODESIGN_PATH": "[CLEANUP]/tmp_tmp_1/codesign",
+      "CODESIGN_TEAM_ID": "[CLEANUP]/CODESIGN_TEAM_ID",
+      "FLUTTER_P12": "[CLEANUP]/FLUTTER_P12",
+      "FLUTTER_P12_PASSWORD": "[CLEANUP]/FLUTTER_P12_PASSWORD",
+      "P12_SUFFIX_FILEPATH": "[CLEANUP]/flutter.p12",
+      "SETUP_KEYCHAIN_LOGS_PATH": "[CLEANUP]/setup_keychain_logs.txt"
+    },
+    "infra_step": true,
+    "name": "gsutil upload debug logs to 0/setup_keychain_logs_00000000-0000-0000-0000-00000000133d.txt",
+    "~followup_annotations": [
+      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/0/setup_keychain_logs_00000000-0000-0000-0000-00000000133d.txt@@@"
+    ]
+  },
+  {
+    "failure": {
+      "failure": {},
+      "humanReason": "Step('run keychain setup script (3)') (retcode: 1)"
+    },
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/signing/examples/code_sign.expected/mac_require_signing.json b/recipe_modules/signing/examples/code_sign.expected/mac_require_signing.json
index b9a40bf..d2f98a6 100644
--- a/recipe_modules/signing/examples/code_sign.expected/mac_require_signing.json
+++ b/recipe_modules/signing/examples/code_sign.expected/mac_require_signing.json
@@ -409,7 +409,7 @@
       "cp",
       "-r",
       "[CLEANUP]/setup_keychain_logs.txt",
-      "gs://flutter_tmp_logs/0/setup_keychain_logs.txt"
+      "gs://flutter_tmp_logs/0/setup_keychain_logs_00000000-0000-0000-0000-000000001337.txt"
     ],
     "env": {
       "CODESIGN_APP_SPECIFIC_PASSWORD": "[CLEANUP]/CODESIGN_APP_SPECIFIC_PASSWORD",
@@ -422,9 +422,9 @@
       "SETUP_KEYCHAIN_LOGS_PATH": "[CLEANUP]/setup_keychain_logs.txt"
     },
     "infra_step": true,
-    "name": "gsutil upload debug logs to 0/setup_keychain_logs.txt",
+    "name": "gsutil upload debug logs to 0/setup_keychain_logs_00000000-0000-0000-0000-000000001337.txt",
     "~followup_annotations": [
-      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/0/setup_keychain_logs.txt@@@"
+      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/0/setup_keychain_logs_00000000-0000-0000-0000-000000001337.txt@@@"
     ]
   },
   {
diff --git a/recipe_modules/signing/examples/code_sign.expected/no_signing_identity.json b/recipe_modules/signing/examples/code_sign.expected/no_signing_identity.json
index b9a40bf..d2f98a6 100644
--- a/recipe_modules/signing/examples/code_sign.expected/no_signing_identity.json
+++ b/recipe_modules/signing/examples/code_sign.expected/no_signing_identity.json
@@ -409,7 +409,7 @@
       "cp",
       "-r",
       "[CLEANUP]/setup_keychain_logs.txt",
-      "gs://flutter_tmp_logs/0/setup_keychain_logs.txt"
+      "gs://flutter_tmp_logs/0/setup_keychain_logs_00000000-0000-0000-0000-000000001337.txt"
     ],
     "env": {
       "CODESIGN_APP_SPECIFIC_PASSWORD": "[CLEANUP]/CODESIGN_APP_SPECIFIC_PASSWORD",
@@ -422,9 +422,9 @@
       "SETUP_KEYCHAIN_LOGS_PATH": "[CLEANUP]/setup_keychain_logs.txt"
     },
     "infra_step": true,
-    "name": "gsutil upload debug logs to 0/setup_keychain_logs.txt",
+    "name": "gsutil upload debug logs to 0/setup_keychain_logs_00000000-0000-0000-0000-000000001337.txt",
     "~followup_annotations": [
-      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/0/setup_keychain_logs.txt@@@"
+      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/0/setup_keychain_logs_00000000-0000-0000-0000-000000001337.txt@@@"
     ]
   },
   {
diff --git a/recipe_modules/signing/examples/code_sign.py b/recipe_modules/signing/examples/code_sign.py
index 4becc34..dee1dab 100644
--- a/recipe_modules/signing/examples/code_sign.py
+++ b/recipe_modules/signing/examples/code_sign.py
@@ -32,3 +32,12 @@
       'no_signing_identity', api.platform.name('mac'),
       api.properties(expected_result=False)
   )
+  yield api.test(
+      'failing_keychain',
+      api.platform.name('mac'),
+      api.properties(expected_result=True),
+      api.step_data('run keychain setup script', retcode=1),
+      api.step_data('run keychain setup script (2)', retcode=1),
+      api.step_data('run keychain setup script (3)', retcode=1),
+      status='FAILURE'
+  )
diff --git a/recipe_modules/signing/resources/setup_keychain.dart b/recipe_modules/signing/resources/setup_keychain.dart
index e2a14e7..3d969be 100755
--- a/recipe_modules/signing/resources/setup_keychain.dart
+++ b/recipe_modules/signing/resources/setup_keychain.dart
@@ -153,29 +153,7 @@
             'successfully found a Flutter identity in the $keychainName keychain',
           );
           if (identities.contains('CSSMERR_TP_NOT_TRUSTED')) {
-            _verifyCert(allowNonzero: true);
-            // Try to delete the Developer ID Certification Authority certificate and add it again
-            _security(<String>[
-              'delete-certificate',
-              '-c',
-              'Developer ID Certification Authority',
-              '-t',
-              keychainName,
-            ]);
-
-            await _downloadAndImportAppleCert(
-              'DeveloperIDG2CA',
-              codesignPath,
-              keychainName,
-            );
-
-            _security(<String>[
-              'unlock-keychain',
-              '-p',
-              keychainPassword,
-              keychainName,
-            ]);
-            _verifyCert();
+            await _verifyCertWithRetries();
           }
           return 0;
         }
@@ -222,7 +200,22 @@
     return result.stdout as String;
   }
 
-  void _verifyCert({bool allowNonzero = false}) {
+  Future<void> _verifyCertWithRetries() async {
+    // Verify the certificate is valid. If it isn't, check again after n seconds.
+    int sleepSeconds = 2;
+    for (int attempt = 0; attempt < totalRetryAttempts; attempt++) {
+      final String results = _verifyCert(allowNonzero: true);
+      if (!results.contains('CSSMERR_TP_NOT_TRUSTED')) {
+        return;
+      }
+
+      await Future<void>.delayed(Duration(seconds: sleepSeconds));
+      sleepSeconds *= sleepSeconds;
+    }
+    _verifyCert();
+  }
+
+  String _verifyCert({bool allowNonzero = false}) {
     // Find the FLUTTER.IO LLC certificate and convert it to a .pem file.
     final String certContents = _security(const <String>[
       'find-certificate',
@@ -240,7 +233,7 @@
 
     // Verify the cert. This will log the certificate chain and trust
     // evaluation results.
-    _security(<String>[
+    final String results = _security(<String>[
       'verify-cert',
       '-c',
       tempCertFile.absolute.path,
@@ -249,6 +242,7 @@
       '-vvv',
     ], allowNonzero: allowNonzero);
     tempCertFile.deleteSync();
+    return results;
   }
 
   Future<void> _downloadAndImportAppleCert(
diff --git a/recipes/engine_v2/builder.expected/mac_release_candidate.json b/recipes/engine_v2/builder.expected/mac_release_candidate.json
index ec4b68c..adbb640 100644
--- a/recipes/engine_v2/builder.expected/mac_release_candidate.json
+++ b/recipes/engine_v2/builder.expected/mac_release_candidate.json
@@ -4277,7 +4277,7 @@
       "cp",
       "-r",
       "[CLEANUP]/setup_keychain_logs.txt",
-      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt"
+      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-00000000133a.txt"
     ],
     "cwd": "[CACHE]/builder/src/flutter",
     "env": {
@@ -4334,9 +4334,9 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "gsutil upload debug logs to 8945511751514863184/setup_keychain_logs.txt",
+    "name": "gsutil upload debug logs to 8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-00000000133a.txt",
     "~followup_annotations": [
-      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt@@@"
+      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-00000000133a.txt@@@"
     ]
   },
   {
@@ -5196,7 +5196,7 @@
       "cp",
       "-r",
       "[CLEANUP]/flutter_logs_dir",
-      "gs://flutter_logs/engine/abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd/builder/00000000-0000-0000-0000-00000000133a"
+      "gs://flutter_logs/engine/abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd/builder/00000000-0000-0000-0000-00000000133d"
     ],
     "infra_step": true,
     "luci_context": {
@@ -5214,7 +5214,7 @@
     "name": "process logs (2).gsutil upload logs abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LINK@archive logs@https://console.cloud.google.com/storage/browser/flutter_logs/engine/abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd/builder/00000000-0000-0000-0000-00000000133a@@@"
+      "@@@STEP_LINK@archive logs@https://console.cloud.google.com/storage/browser/flutter_logs/engine/abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd/builder/00000000-0000-0000-0000-00000000133d@@@"
     ]
   },
   {
@@ -5252,7 +5252,7 @@
     "cmd": [],
     "name": "log links (2)",
     "~followup_annotations": [
-      "@@@STEP_LINK@myfile.txt@https://storage.googleapis.com/flutter_logs/engine/abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd/builder/00000000-0000-0000-0000-00000000133a/myfile.txt@@@"
+      "@@@STEP_LINK@myfile.txt@https://storage.googleapis.com/flutter_logs/engine/abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd/builder/00000000-0000-0000-0000-00000000133d/myfile.txt@@@"
     ]
   },
   {
diff --git a/recipes/engine_v2/engine_v2.expected/codesign_release_branch.json b/recipes/engine_v2/engine_v2.expected/codesign_release_branch.json
index 651871e..0d69ad4 100644
--- a/recipes/engine_v2/engine_v2.expected/codesign_release_branch.json
+++ b/recipes/engine_v2/engine_v2.expected/codesign_release_branch.json
@@ -2428,7 +2428,7 @@
       "cp",
       "-r",
       "[CLEANUP]/setup_keychain_logs.txt",
-      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt"
+      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-00000000133a.txt"
     ],
     "env": {
       "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
@@ -2474,10 +2474,10 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "Global generators.gsutil upload debug logs to 8945511751514863184/setup_keychain_logs.txt",
+    "name": "Global generators.gsutil upload debug logs to 8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-00000000133a.txt",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt@@@"
+      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-00000000133a.txt@@@"
     ]
   },
   {
diff --git a/recipes/ios_usb_dependencies/ios_usb_dependencies_release.expected/with_codesigning.json b/recipes/ios_usb_dependencies/ios_usb_dependencies_release.expected/with_codesigning.json
index 7065e62..8907f47 100644
--- a/recipes/ios_usb_dependencies/ios_usb_dependencies_release.expected/with_codesigning.json
+++ b/recipes/ios_usb_dependencies/ios_usb_dependencies_release.expected/with_codesigning.json
@@ -1378,7 +1378,7 @@
       "cp",
       "-r",
       "[CLEANUP]/setup_keychain_logs.txt",
-      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt"
+      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-000000001337.txt"
     ],
     "env": {
       "ARTIFACT_HUB_REPOSITORY": "artifactregistry://us-maven.pkg.dev/artifact-foundry-prod/maven-3p",
@@ -1419,9 +1419,9 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "gsutil upload debug logs to 8945511751514863184/setup_keychain_logs.txt",
+    "name": "gsutil upload debug logs to 8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-000000001337.txt",
     "~followup_annotations": [
-      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt@@@"
+      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-000000001337.txt@@@"
     ]
   },
   {
@@ -2717,7 +2717,7 @@
       "cp",
       "-r",
       "[CLEANUP]/setup_keychain_logs.txt",
-      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt"
+      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-00000000133a.txt"
     ],
     "env": {
       "ARTIFACT_HUB_REPOSITORY": "artifactregistry://us-maven.pkg.dev/artifact-foundry-prod/maven-3p",
@@ -2758,9 +2758,9 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "gsutil upload debug logs to 8945511751514863184/setup_keychain_logs.txt (2)",
+    "name": "gsutil upload debug logs to 8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-00000000133a.txt",
     "~followup_annotations": [
-      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt@@@"
+      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-00000000133a.txt@@@"
     ]
   },
   {
@@ -4056,7 +4056,7 @@
       "cp",
       "-r",
       "[CLEANUP]/setup_keychain_logs.txt",
-      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt"
+      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-00000000133d.txt"
     ],
     "env": {
       "ARTIFACT_HUB_REPOSITORY": "artifactregistry://us-maven.pkg.dev/artifact-foundry-prod/maven-3p",
@@ -4097,9 +4097,9 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "gsutil upload debug logs to 8945511751514863184/setup_keychain_logs.txt (3)",
+    "name": "gsutil upload debug logs to 8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-00000000133d.txt",
     "~followup_annotations": [
-      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt@@@"
+      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-00000000133d.txt@@@"
     ]
   },
   {
@@ -5395,7 +5395,7 @@
       "cp",
       "-r",
       "[CLEANUP]/setup_keychain_logs.txt",
-      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt"
+      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-000000001340.txt"
     ],
     "env": {
       "ARTIFACT_HUB_REPOSITORY": "artifactregistry://us-maven.pkg.dev/artifact-foundry-prod/maven-3p",
@@ -5436,9 +5436,9 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "gsutil upload debug logs to 8945511751514863184/setup_keychain_logs.txt (4)",
+    "name": "gsutil upload debug logs to 8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-000000001340.txt",
     "~followup_annotations": [
-      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt@@@"
+      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-000000001340.txt@@@"
     ]
   },
   {
@@ -6734,7 +6734,7 @@
       "cp",
       "-r",
       "[CLEANUP]/setup_keychain_logs.txt",
-      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt"
+      "gs://flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-000000001343.txt"
     ],
     "env": {
       "ARTIFACT_HUB_REPOSITORY": "artifactregistry://us-maven.pkg.dev/artifact-foundry-prod/maven-3p",
@@ -6775,9 +6775,9 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "gsutil upload debug logs to 8945511751514863184/setup_keychain_logs.txt (5)",
+    "name": "gsutil upload debug logs to 8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-000000001343.txt",
     "~followup_annotations": [
-      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs.txt@@@"
+      "@@@STEP_LINK@gsutil.upload@https://console.cloud.google.com/storage/browser/flutter_tmp_logs/8945511751514863184/setup_keychain_logs_00000000-0000-0000-0000-000000001343.txt@@@"
     ]
   },
   {