Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/retry-cosign-sign.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"build-push-docker-manifest": minor
---

feat: retry `cosign sign` on failure (5 attempts, 20s apart by default) to absorb
transient GitHub OIDC/Fulcio errors. Configurable via `cosign-sign-attempts` and
`cosign-sign-retry-interval-seconds`.
33 changes: 31 additions & 2 deletions actions/build-push-docker-manifest/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ inputs:
description: "OIDC issuer for cosign"
required: false
default: "https://token.actions.githubusercontent.com"
cosign-sign-attempts:
required: false
description: |
How many times to attempt `cosign sign` before failing. Absorbs transient
errors such as the GitHub OIDC token endpoint returning a non-JSON body
("fetching ambient OIDC credentials: invalid character ...").
default: "5"
cosign-sign-retry-interval-seconds:
required: false
description: "Seconds to wait between `cosign sign` attempts."
default: "20"
docker-manifest-sign:
required: false
description: "Sign the docker manifest"
Expand Down Expand Up @@ -474,11 +485,29 @@ runs:

- name: Sign Docker Manifest using GH OIDC
if: inputs.docker-manifest-sign == 'true'
shell: sh
shell: bash
env:
MANIFEST_NAME_WITH_DIGEST:
${{ steps.inspect-docker-manifest.outputs.manifest-name-with-digest }}
run: cosign sign "${MANIFEST_NAME_WITH_DIGEST}" --yes
ATTEMPTS: ${{ inputs.cosign-sign-attempts }}
INTERVAL: ${{ inputs.cosign-sign-retry-interval-seconds }}
run: |
set -uo pipefail

# Retry to absorb transient OIDC/Fulcio/Rekor errors. Signing the same
# digest again is safe: it only adds another signature.
for (( attempt = 1; attempt <= ATTEMPTS; attempt++ )); do
if cosign sign "${MANIFEST_NAME_WITH_DIGEST}" --yes; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: do we want to add an exponencial backoff or some delay? trying it in sequence can lead to same fail if underlying service is going through a "hiccup"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. the input already defines it: cosign-sign-retry-interval-seconds

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that if cosign will be failing all our attempts we better fail the CI then and look how we can work it around another way (use other tool?). We can't wait an additional 5-10 minutes in CI because it'd be on the path of all the entire auto-CD pipeline in main.

exit 0
fi
if (( attempt < ATTEMPTS )); then
echo "::warning::cosign sign failed (attempt ${attempt}/${ATTEMPTS}); retrying in ${INTERVAL}s..."
sleep "${INTERVAL}"
fi
done

echo "::error::cosign sign failed after ${ATTEMPTS} attempts for ${MANIFEST_NAME_WITH_DIGEST}"
exit 1

- name: Verify Docker image signature
if:
Expand Down
Loading