118 lines
4.7 KiB
YAML
118 lines
4.7 KiB
YAML
name: Assemble GA source deployment
|
|
|
|
# Windows publication still follows the existing release SOP.
|
|
# This workflow assembles source + a prebuilt component, never private source.
|
|
"on":
|
|
workflow_dispatch:
|
|
inputs:
|
|
platform:
|
|
description: Desktop component platform
|
|
required: true
|
|
type: choice
|
|
options: [windows, macos, linux]
|
|
component_url:
|
|
description: Public HTTPS URL of the exe, signed app ZIP, or AppImage
|
|
required: true
|
|
type: string
|
|
component_sha256:
|
|
description: Expected SHA256 from the Desktop component build
|
|
required: true
|
|
type: string
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
assemble:
|
|
runs-on: ${{ inputs.platform == 'macos' && 'macos-14' || 'ubuntu-24.04' }}
|
|
timeout-minutes: 20
|
|
env:
|
|
PLATFORM: ${{ inputs.platform }}
|
|
COMPONENT_URL: ${{ inputs.component_url }}
|
|
COMPONENT_SHA256: ${{ inputs.component_sha256 }}
|
|
steps:
|
|
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd
|
|
with:
|
|
persist-credentials: false
|
|
- name: Fetch fixed component and export GA source
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
[[ "$COMPONENT_URL" == https://* ]]
|
|
[[ "$COMPONENT_SHA256" =~ ^[0-9a-fA-F]{64}$ ]]
|
|
mkdir -p staging/GenericAgent out
|
|
curl --fail --location --retry 3 --proto '=https' --proto-redir '=https' \
|
|
--output component.bin "$COMPONENT_URL"
|
|
python3 - <<'PY'
|
|
import hashlib, os
|
|
from pathlib import Path
|
|
actual = hashlib.sha256(Path('component.bin').read_bytes()).hexdigest()
|
|
assert actual == os.environ['COMPONENT_SHA256'].lower(), 'Component SHA256 mismatch'
|
|
PY
|
|
git archive HEAD | tar -x -C staging/GenericAgent
|
|
mkdir -p staging/GenericAgent/frontends
|
|
- name: Install component into source tree
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
FRONTENDS=staging/GenericAgent/frontends
|
|
case "$PLATFORM" in
|
|
windows)
|
|
cp component.bin "$FRONTENDS/GenericAgent.exe"
|
|
;;
|
|
macos)
|
|
# Reject archive traversal; ditto preserves app modes, links and signature.
|
|
python3 - <<'PY'
|
|
import zipfile
|
|
from pathlib import PurePosixPath
|
|
with zipfile.ZipFile('component.bin') as archive:
|
|
for name in archive.namelist():
|
|
path = PurePosixPath(name)
|
|
assert not path.is_absolute() and '..' not in path.parts and '\\' not in name, name
|
|
assert path.parts and path.parts[0] in ('GenericAgent.app', '__MACOSX'), name
|
|
PY
|
|
ditto -x -k component.bin "$FRONTENDS"
|
|
test -d "$FRONTENDS/GenericAgent.app"
|
|
rm -rf "$FRONTENDS/__MACOSX"
|
|
codesign --verify --deep --strict "$FRONTENDS/GenericAgent.app"
|
|
;;
|
|
linux)
|
|
cp component.bin "$FRONTENDS/GenericAgent.AppImage"
|
|
chmod +x "$FRONTENDS/GenericAgent.AppImage"
|
|
;;
|
|
esac
|
|
python3 - <<'PY'
|
|
import json, os
|
|
from pathlib import Path
|
|
record = {'ga_commit': os.environ['GITHUB_SHA'], 'platform': os.environ['PLATFORM'],
|
|
'component_url': os.environ['COMPONENT_URL'], 'component_sha256': os.environ['COMPONENT_SHA256'].lower()}
|
|
Path('staging/GenericAgent/DESKTOP_COMPONENT.json').write_text(json.dumps(record, indent=2) + '\n')
|
|
PY
|
|
- name: Archive and verify deployment
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
NAME="GenericAgent-Source-$PLATFORM"
|
|
if [[ "$PLATFORM" == macos ]]; then
|
|
ditto -c -k --sequesterRsrc --keepParent staging/GenericAgent "out/$NAME.zip"
|
|
ditto -x -k "out/$NAME.zip" "$RUNNER_TEMP/deployment-verify"
|
|
codesign --verify --deep --strict "$RUNNER_TEMP/deployment-verify/GenericAgent/frontends/GenericAgent.app"
|
|
elif [[ "$PLATFORM" == windows ]]; then
|
|
(cd staging && zip -qr "../out/$NAME.zip" GenericAgent)
|
|
else
|
|
tar -czf "out/$NAME.tar.gz" -C staging GenericAgent
|
|
fi
|
|
python3 - <<'PY'
|
|
import hashlib
|
|
from pathlib import Path
|
|
for path in list(Path('out').iterdir()):
|
|
digest = hashlib.sha256(path.read_bytes()).hexdigest()
|
|
path.with_name(path.name + '.sha256').write_text(digest + ' ' + path.name + '\n')
|
|
PY
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: ga-source-${{ inputs.platform }}
|
|
path: out/*
|
|
if-no-files-found: error
|
|
retention-days: 30
|