Skip to content

Commit 68b62dc

Browse files
authored
feat(MMQA-1951): add new action to download segment analytics contracts (#296)
* feat: add new action to download segment analytics contracts from private repo * feat: add new action to download segment analytics contracts
1 parent 7e0d74b commit 68b62dc

1 file changed

Lines changed: 169 additions & 0 deletions

File tree

  • .github/actions/download-analytics-contract
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
name: Download analytics contract
2+
description: >
3+
Resolve and download a deployed analytics contract release using a short-lived OIDC token.
4+
The calling workflow must grant id-token: write.
5+
6+
inputs:
7+
token-exchange-url:
8+
description: URL used to exchange the GitHub OIDC token.
9+
required: true
10+
target-repository:
11+
description: Private repository containing the analytics contract releases.
12+
required: true
13+
asset-name:
14+
description: Platform contract asset to download.
15+
required: true
16+
release-tag:
17+
description: Exact analytics contract release tag. Empty selects the newest published release.
18+
required: false
19+
default: ''
20+
output-directory:
21+
description: Directory where manifest.json and the platform contract are written.
22+
required: true
23+
24+
outputs:
25+
release-tag:
26+
description: Selected analytics contract release tag.
27+
value: ${{ steps.resolve-release.outputs.release-tag }}
28+
release-url:
29+
description: Selected analytics contract release URL.
30+
value: ${{ steps.resolve-release.outputs.release-url }}
31+
asset-digest:
32+
description: SHA-256 digest advertised for the downloaded asset.
33+
value: ${{ steps.resolve-release.outputs.asset-digest }}
34+
manifest-path:
35+
description: Absolute path to the downloaded manifest.
36+
value: ${{ steps.download-release.outputs.manifest-path }}
37+
asset-path:
38+
description: Absolute path to the downloaded platform asset.
39+
value: ${{ steps.download-release.outputs.asset-path }}
40+
41+
runs:
42+
using: composite
43+
steps:
44+
- name: Get read token
45+
id: contract-token
46+
uses: MetaMask/github-tools/.github/actions/get-token@v1
47+
with:
48+
token-exchange-url: ${{ inputs.token-exchange-url }}
49+
target-repository: ${{ inputs.target-repository }}
50+
permissions: |
51+
contents: read
52+
53+
- name: Resolve release
54+
id: resolve-release
55+
shell: bash
56+
env:
57+
GH_TOKEN: ${{ steps.contract-token.outputs.token }}
58+
TARGET_REPOSITORY: ${{ inputs.target-repository }}
59+
REQUESTED_TAG: ${{ inputs.release-tag }}
60+
ASSET_NAME: ${{ inputs.asset-name }}
61+
run: |
62+
set -euo pipefail
63+
64+
if [ -n "${REQUESTED_TAG}" ]; then
65+
RELEASE="$(
66+
gh api \
67+
"repos/${TARGET_REPOSITORY}/releases/tags/${REQUESTED_TAG}"
68+
)"
69+
else
70+
RELEASE_PAGES="$(
71+
gh api \
72+
--paginate \
73+
--slurp \
74+
"repos/${TARGET_REPOSITORY}/releases?per_page=100"
75+
)"
76+
RELEASE="$(
77+
jq '
78+
[
79+
.[][]
80+
| select(.draft == false)
81+
| select(.prerelease == false)
82+
| select(.tag_name | startswith("analytics-contracts-"))
83+
]
84+
| sort_by(.published_at)
85+
| last
86+
' <<< "${RELEASE_PAGES}"
87+
)"
88+
fi
89+
90+
TAG="$(jq -r '.tag_name // empty' <<< "${RELEASE}")"
91+
RELEASE_URL="$(jq -r '.html_url // empty' <<< "${RELEASE}")"
92+
DRAFT="$(jq -r '(.draft == true)' <<< "${RELEASE}")"
93+
PRERELEASE="$(jq -r '(.prerelease == true)' <<< "${RELEASE}")"
94+
ASSET_DIGEST="$(
95+
jq -r --arg asset "${ASSET_NAME}" '
96+
.assets[]
97+
| select(.name == $asset)
98+
| .digest // empty
99+
' <<< "${RELEASE}"
100+
)"
101+
102+
if [ -z "${TAG}" ] || [[ "${TAG}" != analytics-contracts-* ]]; then
103+
echo "No matching analytics contract release was found." >&2
104+
exit 1
105+
fi
106+
107+
if [ "${DRAFT}" = "true" ] || [ "${PRERELEASE}" = "true" ]; then
108+
echo "Release ${TAG} is not published." >&2
109+
exit 1
110+
fi
111+
112+
if ! [[ "${ASSET_DIGEST}" =~ ^sha256:[0-9a-f]{64}$ ]]; then
113+
echo "Release ${TAG} has no valid ${ASSET_NAME} SHA-256 digest." >&2
114+
exit 1
115+
fi
116+
117+
{
118+
echo "release-tag=${TAG}"
119+
echo "release-url=${RELEASE_URL}"
120+
echo "asset-digest=${ASSET_DIGEST}"
121+
} >> "${GITHUB_OUTPUT}"
122+
123+
- name: Download release
124+
id: download-release
125+
shell: bash
126+
env:
127+
GH_TOKEN: ${{ steps.contract-token.outputs.token }}
128+
TARGET_REPOSITORY: ${{ inputs.target-repository }}
129+
RELEASE_TAG: ${{ steps.resolve-release.outputs.release-tag }}
130+
ASSET_NAME: ${{ inputs.asset-name }}
131+
OUTPUT_DIRECTORY: ${{ inputs.output-directory }}
132+
EXPECTED_DIGEST: ${{ steps.resolve-release.outputs.asset-digest }}
133+
run: |
134+
set -euo pipefail
135+
if [[ "${OUTPUT_DIRECTORY}" != /* ]]; then
136+
OUTPUT_DIRECTORY="${GITHUB_WORKSPACE}/${OUTPUT_DIRECTORY}"
137+
fi
138+
mkdir -p "${OUTPUT_DIRECTORY}"
139+
OUTPUT_DIRECTORY="$(cd "${OUTPUT_DIRECTORY}" && pwd)"
140+
141+
MANIFEST_PATH="${OUTPUT_DIRECTORY}/manifest.json"
142+
ASSET_PATH="${OUTPUT_DIRECTORY}/${ASSET_NAME}"
143+
rm -f -- "${MANIFEST_PATH}" "${ASSET_PATH}"
144+
145+
gh release download "${RELEASE_TAG}" \
146+
--repo "${TARGET_REPOSITORY}" \
147+
--pattern manifest.json \
148+
--pattern "${ASSET_NAME}" \
149+
--dir "${OUTPUT_DIRECTORY}" \
150+
--clobber
151+
152+
if [ ! -f "${MANIFEST_PATH}" ] || [ ! -f "${ASSET_PATH}" ]; then
153+
echo "Release did not contain manifest.json and ${ASSET_NAME}." >&2
154+
exit 1
155+
fi
156+
157+
ACTUAL_DIGEST="$(
158+
sha256sum "${ASSET_PATH}" | awk '{ print "sha256:" $1 }'
159+
)"
160+
161+
if [ "${ACTUAL_DIGEST}" != "${EXPECTED_DIGEST}" ]; then
162+
echo "Downloaded ${ASSET_NAME} digest does not match the release digest." >&2
163+
exit 1
164+
fi
165+
166+
{
167+
echo "manifest-path=${MANIFEST_PATH}"
168+
echo "asset-path=${ASSET_PATH}"
169+
} >> "${GITHUB_OUTPUT}"

0 commit comments

Comments
 (0)