Skip to content
Open
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
63 changes: 63 additions & 0 deletions .github/workflows/deploy-prod-1-propose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
# 2. Provision compose file update via Phala Cloud API → get compose hash
# 3. Propose addComposeHash(hash) to Safe multisig on Base
# 4. Create draft GitHub release with deployment context for Phase 2
# 5. Create/advance the release-line branch (release/vX.Y) for hotfixes
#
# Release-line branches (CPL-358): each tagged prod release lands its commit on a
# minor-version branch release/vX.Y. All patch releases on a line share one branch,
# giving hotfixes to a shipped version a stable home that never moves as main
# advances. See architectureDocs/deployment/vm-code-upgrade.md ("Release-line branches & hotfixes").
#
# Image provenance (DR-1b): Each image is signed with Sigstore (cosign keyless).
# To verify:
Expand Down Expand Up @@ -549,3 +555,60 @@ jobs:
--title "${{ github.ref_name }}" \
--generate-notes \
--target "${{ github.sha }}"

# Land the released commit on a minor-version release-line branch (release/vX.Y)
# so hotfixes to a shipped version have a stable home that never moves as main
# advances (CPL-358). All patch releases on a line (v1.2.0, v1.2.1, ...) share
# one branch. Runs only for tag pushes; workflow_dispatch re-provisions an
# existing release and has no tag to key a line off.
create-release-branch:
needs: [create-draft-release]
if: ${{ github.ref_type == 'tag' }}
runs-on: self-hosted
permissions:
contents: write # push the release-line branch
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.sha }}
fetch-depth: 0 # need history to test fast-forward against an existing branch

- name: Create or advance the release-line branch
env:
TAG: ${{ github.ref_name }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail

# Derive release/vMAJOR.MINOR from the tag. Prefix-match tolerates
# pre-release suffixes (v1.2.0-rc1 → release/v1.2), keeping the whole
# 1.2 line on one branch.
if [[ ! "$TAG" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+) ]]; then
echo "::notice::Tag '$TAG' is not vMAJOR.MINOR.PATCH — skipping release-branch creation."
exit 0
fi
BRANCH="release/v${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
echo "Release-line branch: $BRANCH (tag $TAG @ $SHA)"

if git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null 2>&1; then
# Branch exists — an earlier patch release on this line, or a branch
# already carrying hotfix commits. Only fast-forward it to the tagged
# commit; never force-push, which would discard those hotfix commits.
# Compare against FETCH_HEAD: `git fetch` always writes it, whereas the
# origin/$BRANCH remote-tracking ref may not exist under checkout's
# narrow fetch refspec.
git fetch origin "$BRANCH"
if git merge-base --is-ancestor FETCH_HEAD "$SHA"; then
echo "Fast-forwarding $BRANCH to $SHA"
if ! git push origin "$SHA:refs/heads/$BRANCH"; then
echo "::warning::Failed to push $BRANCH to $SHA (branch may have moved). Leaving it untouched."
fi
else
echo "::warning::$BRANCH has diverged from $SHA (likely carries hotfix commits). Leaving it untouched — reconcile manually if this release should advance the line."
fi
else
echo "Creating $BRANCH at $SHA"
if ! git push origin "$SHA:refs/heads/$BRANCH"; then
echo "::warning::Failed to create $BRANCH at $SHA."
fi
fi
Comment thread
Copilot marked this conversation as resolved.
21 changes: 21 additions & 0 deletions architectureDocs/deployment/vm-code-upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,27 @@ If the CVM boots before the whitelist tx is finalized, the KMS will reject the k
the CVM cannot serve traffic. The diagram shows the whitelist flowing into the key issuance check
to reflect this dependency.

## Release-line branches & hotfixes

Every tagged production release (`v*` push → **Deploy Prod 1: Propose Compose Hash**) also
lands its commit on a minor-version **release-line branch** `release/vMAJOR.MINOR` (created by the
`create-release-branch` job). All patch releases on a line (`v1.2.0`, `v1.2.1`, …) share one
branch, so a shipped version has a stable home that does not move as `main` advances.

To ship a hotfix to a released version without dragging in unreleased work from `main`:

1. Fetch and branch from the release line:
`git fetch origin && git switch -c release/v1.2 origin/release/v1.2` (or from the tag:
`git fetch origin --tags && git switch --detach v1.2.3`).
2. Apply the fix (cherry-pick from `main` where possible so the fix also lands there).
3. Tag the patch and push: `git tag v1.2.4 && git push origin v1.2.4` — this re-runs the prod
propose workflow for the hotfix commit.
4. The `create-release-branch` job **fast-forwards** `release/v1.2` to the hotfix commit. It never
force-pushes: if the branch has diverged from the tagged commit it is left untouched and the run
logs a warning, so hotfix commits already on the branch are never discarded.

Don't forget to forward-port the fix to `main` if you branched from the tag directly.

## Rollback

To roll back, redeploy the previous image (whose compose-hash is already whitelisted). No
Expand Down
Loading