diff --git a/actions/attest_image/action.yaml b/actions/attest_image/action.yaml index 07ed2977..2018562b 100644 --- a/actions/attest_image/action.yaml +++ b/actions/attest_image/action.yaml @@ -43,8 +43,8 @@ runs: SUBJECT_DIGEST: ${{ inputs.subject_digest }} IMAGE_REF: ${{ steps.ref.outputs.value }} run: | - # Accept either signer SAN: the reusable workflow under IABTechLab/uid2-shared-actions, or the caller's workflow via the composite path. --owner alone would reject the former (see https://github.com/cli/cli/issues/9045). + # Accept either signer SAN: the reusable workflow under IABTechLab/uid2-shared-actions, or the caller's workflow via the composite path. Certificate identities can differ in repository-name casing, so match them case-insensitively. --owner alone would reject the former (see https://github.com/cli/cli/issues/9045). gh attestation verify \ "oci://${IMAGE_REF}@${SUBJECT_DIGEST}" \ --owner "${{ github.repository_owner }}" \ - --cert-identity-regex "^https://github\.com/(IABTechLab/uid2-shared-actions|${{ github.repository }})/" + --cert-identity-regex "(?i)^https://github\.com/(IABTechLab/uid2-shared-actions|${{ github.repository }})/" diff --git a/actions/attest_image/tests/test_identity_regex.sh b/actions/attest_image/tests/test_identity_regex.sh new file mode 100755 index 00000000..e72091c0 --- /dev/null +++ b/actions/attest_image/tests/test_identity_regex.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Tests the certificate identity policy embedded in ../action.yaml. +set -euo pipefail + +action_file="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/action.yaml" + +python3 - "$action_file" <<'PY' +import re +import sys +from pathlib import Path + +action = Path(sys.argv[1]).read_text() +match = re.search(r'--cert-identity-regex "([^"]+)"', action) +if not match: + raise AssertionError("certificate identity regex not found in action.yaml") + +identity_regex = match.group(1).replace( + "${{ github.repository }}", "IABTechLab/uid2-examples" +) +policy = re.compile(identity_regex) + +accepted = [ + "https://github.com/IABTechLab/uid2-shared-actions/.github/workflows/publish.yaml@refs/tags/v3", + "https://github.com/iabtechlab/uid2-shared-actions/.github/workflows/publish.yaml@refs/tags/v3", + "https://github.com/IABTechLab/uid2-examples/.github/workflows/release.yaml@refs/heads/main", + "https://github.com/iabtechlab/uid2-examples/.github/workflows/release.yaml@refs/heads/main", +] +rejected = [ + "https://github.com/IABTechLab/uid2-shared-actions-malicious/.github/workflows/publish.yaml@refs/tags/v3", + "https://github.com/other-org/uid2-examples/.github/workflows/release.yaml@refs/heads/main", + "https://example.com/IABTechLab/uid2-shared-actions/.github/workflows/publish.yaml@refs/tags/v3", +] + +for identity in accepted: + if not policy.match(identity): + raise AssertionError(f"expected identity to be accepted: {identity}") + +for identity in rejected: + if policy.match(identity): + raise AssertionError(f"expected identity to be rejected: {identity}") + +print("certificate identity regex tests passed") +PY