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
234 changes: 234 additions & 0 deletions .github/workflows/evaos-beta-local-signed-dmg-manifest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
name: Register evaOS Beta Local-Signed DMG Manifest

on:
Comment thread
coderabbitai[bot] marked this conversation as resolved.
workflow_dispatch:
inputs:
local_signed_dmg_fallback_ack:
description: 'Type evaos-local-signed-dmg to acknowledge these release assets were locally Developer ID signed, notarized, stapled, and Gatekeeper validated.'
required: true
type: string
tag:
description: 'Existing non-dev evaOS beta release tag whose finalized assets are already attached to the GitHub prerelease.'
required: true
type: string
source_ci_run_id:
description: 'Build and Release run id that produced the staged macOS artifacts.'
required: true
type: string
source_ci_head_sha:
description: 'Commit SHA used by the staged Build and Release run.'
required: true
type: string
source_ci_conclusion:
description: 'Conclusion of the staged Build and Release run.'
required: true
default: failure
type: choice
options:
- failure
- cancelled
- success
source_ci_head_branch:
description: 'Branch used by the staged Build and Release run.'
required: true
default: evaos/beta-rc-20260612
type: string
source_artifact_names:
description: 'Comma-separated source artifact names from the staged run. Use macos-build-arm64 for macos-arm64 releases.'
required: true
default: macos-build-arm64
type: string
fallback_reason:
description: 'Concrete reason for local DMG finalization.'
required: true
default: ci-dmg-codesign-timeout
type: string
local_finalization_proof_ref:
description: 'Non-secret issue, run, or artifact reference containing local signing/notarization/stapling proof.'
required: true
type: string
dmg_notary_submission_ids:
description: 'Comma-separated Apple notary submission ids for the finalized DMGs.'
required: true
type: string
release_target_platforms:
description: 'Release target platforms for asset verification. Use macos-arm64 on beta RC refs that include arm64-only verification support.'
required: false
default: macos-arm64
type: choice
options:
- macos
- macos-arm64
- all
Comment thread
coderabbitai[bot] marked this conversation as resolved.

concurrency:
group: evaos-beta-local-signed-dmg-manifest-${{ github.event.inputs.tag || github.run_id }}
cancel-in-progress: false

permissions:
actions: read
Comment thread
coderabbitai[bot] marked this conversation as resolved.
contents: read

env:
EVAOS_RELEASE_TARGET_PLATFORMS: ${{ inputs.release_target_platforms || 'macos-arm64' }}

jobs:
register-manifest:
name: Register trusted local-signed DMG manifest
runs-on: ubuntu-latest
permissions:
actions: read
# Required only for attaching the trusted manifest back to the GitHub prerelease.
contents: write
steps:
- name: Validate inputs
env:
ACK: ${{ github.event.inputs.local_signed_dmg_fallback_ack }}
TAG: ${{ github.event.inputs.tag }}
PROOF_REF: ${{ github.event.inputs.local_finalization_proof_ref }}
run: |
set -euo pipefail
if [ "$ACK" != "evaos-local-signed-dmg" ]; then
echo "::error::Wrong acknowledgement. Type evaos-local-signed-dmg."
exit 1
fi
if [[ "$TAG" != evaos-beta-* ]]; then
echo "::error::Refusing non-evaOS beta tag: $TAG"
exit 1
fi
if [[ ! "$TAG" =~ ^evaos-beta-[A-Za-z0-9._-]+$ ]]; then
echo "::error::Release tag contains unsupported characters: $TAG"
exit 1
fi
if [[ "$TAG" == *"-dev" || "$TAG" == *"-dev-"* || "$TAG" == *"-dev."* ]]; then
echo "::error::Refusing development beta tag: $TAG"
exit 1
fi
if [ ${#PROOF_REF} -lt 8 ] || [[ "$PROOF_REF" == *"Bearer "* ]] || [[ "$PROOF_REF" == *"token"* ]]; then
echo "::error::local_finalization_proof_ref must be a concrete non-secret reference."
exit 1
fi

- name: Checkout release refs
uses: actions/checkout@v6
with:
fetch-depth: 0
Comment thread
coderabbitai[bot] marked this conversation as resolved.
persist-credentials: false

- name: Download finalized release assets
env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
REPOSITORY: ${{ github.repository }}
TAG: ${{ github.event.inputs.tag }}
run: |
set -euo pipefail
mkdir -p release-assets
case "${EVAOS_RELEASE_TARGET_PLATFORMS}" in
macos)
patterns=(
--pattern "*.dmg"
--pattern "*.zip"
--pattern "latest-mac.yml"
--pattern "latest-arm64-mac.yml"
)
;;
macos-arm64)
patterns=(
--pattern "*arm64*.dmg"
--pattern "*arm64*.zip"
--pattern "latest-arm64-mac.yml"
)
;;
all)
patterns=(
--pattern "*.dmg"
--pattern "*.exe"
--pattern "*.msi"
--pattern "*.deb"
--pattern "*.zip"
--pattern "*.yml"
)
;;
*)
echo "::error::Unsupported EVAOS_RELEASE_TARGET_PLATFORMS: ${EVAOS_RELEASE_TARGET_PLATFORMS}"
exit 1
;;
esac
gh release download "$TAG" \
--repo "$REPOSITORY" \
--dir release-assets \
"${patterns[@]}"
rm -f release-assets/evaos-beta-release-manifest.json
ls -la release-assets

- name: Verify finalized release assets
env:
INCLUDE_WEB_CLI_ASSETS: '0'
MOCK_PRODUCT_NAME: evaOS Workbench
TAG_NAME: ${{ github.event.inputs.tag }}
run: |
set -euo pipefail
VERSION="${TAG_NAME#evaos-beta-}"
VERSION="${VERSION#v}"
INCLUDE_WEB_CLI_ASSETS=0 MOCK_VERSION="$VERSION" bash scripts/verify-release-assets.sh release-assets

- name: Write local-signed fallback manifest
env:
TAG_NAME: ${{ github.event.inputs.tag }}
GITHUB_REPOSITORY: ${{ github.repository }}
EVAOS_BETA_RELEASE_WORKFLOW: Build and Release
EVAOS_BETA_RELEASE_PUBLISH_ENABLED: 'true'
EVAOS_BETA_RELEASE_PROVENANCE_MODE: local-signed-dmg-fallback
EVAOS_BETA_RELEASE_COMMIT: ${{ github.event.inputs.source_ci_head_sha }}
EVAOS_BETA_RELEASE_BRANCH: ${{ github.event.inputs.source_ci_head_branch }}
EVAOS_BETA_LOCAL_DMG_SOURCE_RUN_ID: ${{ github.event.inputs.source_ci_run_id }}
EVAOS_BETA_LOCAL_DMG_SOURCE_WORKFLOW: Build and Release
EVAOS_BETA_LOCAL_DMG_SOURCE_CONCLUSION: ${{ github.event.inputs.source_ci_conclusion }}
EVAOS_BETA_LOCAL_DMG_SOURCE_SHA: ${{ github.event.inputs.source_ci_head_sha }}
EVAOS_BETA_LOCAL_DMG_SOURCE_BRANCH: ${{ github.event.inputs.source_ci_head_branch }}
EVAOS_BETA_LOCAL_DMG_SOURCE_ARTIFACTS: ${{ github.event.inputs.source_artifact_names }}
EVAOS_BETA_LOCAL_DMG_FALLBACK_REASON: ${{ github.event.inputs.fallback_reason }}
EVAOS_BETA_LOCAL_DMG_FINALIZATION_PROOF_REF: ${{ github.event.inputs.local_finalization_proof_ref }}
EVAOS_BETA_LOCAL_DMG_NOTARY_SUBMISSION_IDS: ${{ github.event.inputs.dmg_notary_submission_ids }}
run: node scripts/evaosBetaReleaseGate.js write-manifest release-assets "$TAG_NAME"

- name: Verify local-signed fallback manifest
env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
EXPECTED_RELEASE_COMMIT: ${{ github.event.inputs.source_ci_head_sha }}
EVAOS_BETA_LOCAL_SIGNED_DMG_FALLBACK_ACK: ${{ github.event.inputs.local_signed_dmg_fallback_ack }}
TAG_NAME: ${{ github.event.inputs.tag }}
run: node scripts/evaosBetaReleaseGate.js verify-manifest release-assets "$TAG_NAME"

- name: Upload trusted manifest artifact
uses: actions/upload-artifact@v4
with:
name: evaos-beta-release-manifest-${{ github.event.inputs.tag }}
path: release-assets/evaos-beta-release-manifest.json
if-no-files-found: error
retention-days: 90

- name: Attach manifest to GitHub prerelease
env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
REPOSITORY: ${{ github.repository }}
TAG: ${{ github.event.inputs.tag }}
run: |
set -euo pipefail
gh release upload "$TAG" release-assets/evaos-beta-release-manifest.json \
--repo "$REPOSITORY" \
--clobber

- name: Summary
env:
RUN_ID: ${{ github.run_id }}
TAG: ${{ github.event.inputs.tag }}
run: |
{
echo "## Registered trusted local-signed DMG manifest"
echo ""
echo "- Tag: \`$TAG\`"
echo "- Manifest artifact: \`evaos-beta-release-manifest-$TAG\`"
echo "- Next: run evaOS Beta RC Canary with \`trusted_manifest_run_id=$RUN_ID\` and \`local_signed_dmg_fallback_ack=evaos-local-signed-dmg\`."
} >> "$GITHUB_STEP_SUMMARY"
32 changes: 25 additions & 7 deletions scripts/verify-release-assets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ ERRORS=0
shopt -s nullglob

case "$RELEASE_TARGET_PLATFORMS" in
all|macos)
all|macos|macos-arm64)
;;
*)
echo "FAIL: unsupported EVAOS_RELEASE_TARGET_PLATFORMS: $RELEASE_TARGET_PLATFORMS"
echo "FAIL: supported values: all, macos"
echo "FAIL: supported values: all, macos, macos-arm64"
exit 1
;;
esac
Expand All @@ -25,6 +25,13 @@ echo "Release target platforms: $RELEASE_TARGET_PLATFORMS"

assert_evaos_beta_asset_identity() {
local base="$1"
local base_lc expected_name expected_asset expected_compact expected_slug

base_lc="$(printf '%s' "$base" | tr '[:upper:]' '[:lower:]')"
expected_name="$(printf '%s' "$MOCK_PRODUCT_NAME" | tr '[:upper:]' '[:lower:]')"
expected_asset="$(printf '%s' "$MOCK_PRODUCT_ASSET_NAME" | tr '[:upper:]' '[:lower:]')"
expected_compact="${expected_name// /}"
expected_slug="${expected_name// /-}"

case "$base" in
*"AionUi"*|*"AionUI"*|*"Aion-UI"*|*"aion-ui"*|*"aionui"*)
Expand All @@ -34,11 +41,11 @@ assert_evaos_beta_asset_identity() {
;;
esac

case "$base" in
*"evaOS Workbench Beta"*|*"evaOS.Workbench.Beta"*|*"EvaOSWorkbenchBeta"*|*"evaos-workbench-beta"*)
case "$base_lc" in
*"$expected_name"*|*"$expected_asset"*|*"$expected_compact"*|*"$expected_slug"*)
;;
*)
echo "FAIL: beta asset lacks evaOS identity marker: $base"
echo "FAIL: beta asset lacks expected evaOS identity marker ($MOCK_PRODUCT_NAME): $base"
ERRORS=$((ERRORS + 1))
;;
esac
Expand All @@ -47,6 +54,8 @@ assert_evaos_beta_asset_identity() {
REQUIRED_METADATA=(latest-mac.yml)
if [ "$RELEASE_TARGET_PLATFORMS" = "all" ]; then
REQUIRED_METADATA=(latest.yml latest-mac.yml latest-linux.yml latest-linux-arm64.yml)
elif [ "$RELEASE_TARGET_PLATFORMS" = "macos-arm64" ]; then
REQUIRED_METADATA=(latest-arm64-mac.yml)
fi

for f in "${REQUIRED_METADATA[@]}"; do
Expand Down Expand Up @@ -95,7 +104,9 @@ assert_metadata_points_to_existing_file() {
echo "PASS: $metadata_name -> $ref_file"
}

assert_metadata_points_to_existing_file "latest-mac.yml" "(mac-x64|darwin-x64|x64)"
if [ "$RELEASE_TARGET_PLATFORMS" != "macos-arm64" ]; then
assert_metadata_points_to_existing_file "latest-mac.yml" "(mac-x64|darwin-x64|x64)"
fi
if [ "$RELEASE_TARGET_PLATFORMS" = "all" ]; then
assert_metadata_points_to_existing_file "latest.yml" "(win-x64|win32-x64|x64)"
assert_metadata_points_to_existing_file "latest-linux.yml" "(linux|AppImage|deb)"
Expand Down Expand Up @@ -144,6 +155,8 @@ assert_required_glob() {
if [ "$RELEASE_TARGET_PLATFORMS" = "macos" ]; then
assert_required_glob "macOS x64 DMG" "${MOCK_PRODUCT_ASSET_NAME}-*-mac-x64.dmg"
assert_required_glob "macOS arm64 DMG" "${MOCK_PRODUCT_ASSET_NAME}-*-mac-arm64.dmg"
elif [ "$RELEASE_TARGET_PLATFORMS" = "macos-arm64" ]; then
assert_required_glob "macOS arm64 DMG" "${MOCK_PRODUCT_ASSET_NAME}-*-mac-arm64.dmg"
else
REQUIRED_DISTRIBUTABLES=(
"${MOCK_PRODUCT_ASSET_NAME}-${MOCK_VERSION}-win-x64.exe"
Expand All @@ -164,7 +177,7 @@ else
done
fi

if [ "$RELEASE_TARGET_PLATFORMS" = "macos" ]; then
if [ "$RELEASE_TARGET_PLATFORMS" = "macos" ] || [ "$RELEASE_TARGET_PLATFORMS" = "macos-arm64" ]; then
DEFERRED_PLATFORM_FILES=(
"$OUTPUT_DIR"/*.exe
"$OUTPUT_DIR"/*.msi
Expand All @@ -173,6 +186,9 @@ if [ "$RELEASE_TARGET_PLATFORMS" = "macos" ]; then
"$OUTPUT_DIR"/latest-win-arm64.yml
"$OUTPUT_DIR"/latest-linux*.yml
)
if [ "$RELEASE_TARGET_PLATFORMS" = "macos-arm64" ]; then
DEFERRED_PLATFORM_FILES+=("$OUTPUT_DIR"/latest-mac.yml)
fi
for f in "${DEFERRED_PLATFORM_FILES[@]}"; do
[ -e "$f" ] || continue
echo "FAIL: macOS release profile contains deferred Windows/Linux asset or metadata: $(basename "$f")"
Expand All @@ -189,6 +205,8 @@ if [ "$INCLUDE_WEB_CLI_ASSETS" = "1" ]; then
# Web-CLI tarballs + checksums
if [ "$RELEASE_TARGET_PLATFORMS" = "macos" ]; then
WEB_PLATFORMS=(darwin-arm64 darwin-x86_64)
elif [ "$RELEASE_TARGET_PLATFORMS" = "macos-arm64" ]; then
WEB_PLATFORMS=(darwin-arm64)
else
WEB_PLATFORMS=(darwin-arm64 darwin-x86_64 linux-arm64 linux-x86_64 win-x86_64)
fi
Expand Down
Loading