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
22 changes: 22 additions & 0 deletions .github/scripts/verify-tag-matches-sha.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
# Verifies that a git tag still resolves to the guarded commit SHA that was
# validated by this workflow's guard job, protecting against a force-push/
# retag race between the image build and any subsequent chart-publish or
# release step.
#
# Required env vars: GH_TOKEN, REPO, TAG, GUARDED_SHA
set -euo pipefail

ref_json="$(gh api "repos/${REPO}/git/ref/tags/${TAG}" --jq '[.object.type, .object.sha] | @tsv')"
read -r current_type current_sha <<< "$ref_json"
if [[ "$current_type" == "tag" ]]; then
# Annotated tag: the ref's object.sha is the tag object, not the commit - peel it.
current_sha="$(gh api "repos/${REPO}/git/tags/${current_sha}" --jq .object.sha)"
fi

if [[ "$current_sha" != "$GUARDED_SHA" ]]; then
echo "::error::Tag '${TAG}' now points at ${current_sha}, not the guarded commit ${GUARDED_SHA} (force-pushed?). Refusing to proceed."
exit 1
fi

echo "Tag '${TAG}' still points at the guarded commit ${GUARDED_SHA}."
85 changes: 71 additions & 14 deletions .github/workflows/publish-charts.yaml
Original file line number Diff line number Diff line change
@@ -1,35 +1,81 @@
name: Publish charts

on:
push:
tags:
- 'v*'
workflow_run:
workflows: ["Publish container image"]
types: [completed]

jobs:

guard:
name: Verify image build succeeded
runs-on: ubuntu-latest
# Read-only job: only inspects workflow_run event metadata, no repo/API access needed.
permissions: {}
if: >
github.event.workflow_run.event == 'push' &&
startsWith(github.event.workflow_run.head_branch, 'v')
outputs:
tag: ${{ github.event.workflow_run.head_branch }}
sha: ${{ github.event.workflow_run.head_sha }}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
steps:
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- name: Check image build result
env:
CONCLUSION: ${{ github.event.workflow_run.conclusion }}
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
run: |
# No build-metadata (+...) suffix allowed: this tag is used verbatim as a
# container image tag downstream, and Docker/OCI tags cannot contain '+'.
semver_re='^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*)|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)(\.((0|[1-9][0-9]*)|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*))*)?$'
if ! [[ "$HEAD_BRANCH" =~ $semver_re ]]; then
echo "::error::Tag '$HEAD_BRANCH' is not a valid semver release tag"
exit 1
fi
if [[ "$CONCLUSION" != "success" ]]; then
echo "::error::Image build for tag $HEAD_BRANCH did not succeed (conclusion: $CONCLUSION). Refusing to publish chart."
exit 1
fi
echo "Image build succeeded for tag $HEAD_BRANCH"

publish-ui-chart:
name: Publish UI chart
needs: guard
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ needs.guard.outputs.sha }}
fetch-depth: 0
persist-credentials: false

- name: Verify tag still points at the guarded commit
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ needs.guard.outputs.tag }}
GUARDED_SHA: ${{ needs.guard.outputs.sha }}
REPO: ${{ github.repository }}
run: .github/scripts/verify-tag-matches-sha.sh

- id: run
env:
TAG: ${{ needs.guard.outputs.tag }}
REGISTRY_USERNAME: ${{ github.actor }}
REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
run: |
# Login to the registry:
export registry="ghcr.io"
echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login --username "${{ github.actor }}" --password-stdin "${registry}"
echo "${REGISTRY_PASSWORD}" | helm registry login --username "${REGISTRY_USERNAME}" --password-stdin "${registry}"

Comment thread
coderabbitai[bot] marked this conversation as resolved.
# Get the git version:
export git_version="$(git describe --tags)"
# Get the git version from the tag that triggered the image build:
export git_version="${TAG}"

# Update the image reference in the chart:
export app_version="${git_version}"
export app_image="${registry}/${{ github.repository }}:${app_version}"
export app_image="${registry}/${REPO}:${app_version}"
yq -i '.images.ui = strenv(app_image)' charts/ui/values.yaml

# Package the chart:
Expand All @@ -41,14 +87,25 @@ jobs:
export chart_file="${chart_name}-${chart_version}.tgz"
helm push "${chart_file}" "oci://${registry}/${{ github.repository_owner }}/charts"

- name: Verify tag still points at the guarded commit
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ needs.guard.outputs.tag }}
GUARDED_SHA: ${{ needs.guard.outputs.sha }}
Comment thread
minmzzhang marked this conversation as resolved.
REPO: ${{ github.repository }}
run: .github/scripts/verify-tag-matches-sha.sh

- name: Create GitHub Release
run: |
gh release create "${GITHUB_REF_NAME}" \
--repo "${{ github.repository }}" \
--title "osac-ui ${GITHUB_REF_NAME}" \
gh release create "${TAG}" \
--repo "${REPO}" \
--title "osac-ui ${TAG}" \
--generate-notes \
|| gh release edit "${GITHUB_REF_NAME}" \
--repo "${{ github.repository }}" \
--title "osac-ui ${GITHUB_REF_NAME}"
--verify-tag \
|| gh release edit "${TAG}" \
--repo "${REPO}" \
--title "osac-ui ${TAG}"
Comment thread
minmzzhang marked this conversation as resolved.
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ needs.guard.outputs.tag }}
REPO: ${{ github.repository }}
Loading