GroundSeg SLSA3 release #79
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: GroundSeg SLSA3 release | |
on: | |
workflow_dispatch: | |
inputs: | |
release_channel: | |
description: 'Release channel' | |
required: true | |
type: choice | |
options: | |
- nobuild | |
- promote | |
- edge | |
- canary | |
- latest | |
to_canary: | |
description: 'Also push build to canary channel (if edge)' | |
required: false | |
type: boolean | |
default: false | |
version_server: | |
description: 'Staging or production version server' | |
required: true | |
type: choice | |
options: | |
- staging.version.groundseg.app | |
- version.groundseg.app | |
permissions: read-all | |
env: | |
VERSION_AUTH: ${{ secrets.VERSION_AUTH }} | |
RCLONE_CONFIG: ${{ secrets.RCLONE_CONFIG }} | |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
jobs: | |
args: | |
runs-on: ubuntu-latest | |
outputs: | |
commit-date: ${{ steps.ldflags.outputs.commit-date }} | |
commit: ${{ steps.ldflags.outputs.commit }} | |
version: ${{ steps.ldflags.outputs.version }} | |
tree-state: ${{ steps.ldflags.outputs.tree-state }} | |
channel: ${{ steps.channel.outputs.value }} | |
bin-tag: ${{ steps.channel.outputs.bin-tag }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- id: ldflags | |
run: | | |
COMMIT_DATE=$(git log --date=iso8601-strict -1 --pretty=%ct) | |
COMMIT=$GITHUB_SHA | |
VERSION=$(git describe --tags --always --dirty | cut -c2-) | |
TREE_STATE=$(if git diff --quiet; then echo "clean"; else echo "dirty"; fi) | |
echo "commit-date=$COMMIT_DATE" >> "$GITHUB_OUTPUT" | |
echo "commit=$COMMIT" >> "$GITHUB_OUTPUT" | |
echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
echo "tree-state=$TREE_STATE" >> "$GITHUB_OUTPUT" | |
- id: channel | |
run: | | |
CHANNEL="${{ github.event.inputs.release_channel }}" | |
if [ "$CHANNEL" = "latest" ]; then | |
BIN_TAG=$(echo ${{ github.ref_name }} | cut -d'-' -f1 | sed 's@/@.@g') | |
else | |
BIN_TAG=$(echo ${{ github.ref_name }} | sed 's@/@.@g') | |
fi | |
echo "value=$CHANNEL" >> "$GITHUB_OUTPUT" | |
echo "bin-tag=$BIN_TAG" >> "$GITHUB_OUTPUT" | |
frontend-build: | |
needs: args | |
if: ${{ github.event.inputs.release_channel != 'nobuild' && github.event.inputs.release_channel != 'promote' }} | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Build Frontend | |
run: | | |
cd ./ui | |
docker build -t web-builder -f builder.Dockerfile . | |
container_id=$(docker create web-builder) | |
docker cp $container_id:/webui/build ./web | |
rm -rf ../goseg/web | |
mv web ../goseg/ | |
docker build -t web-builder -f gallseg.Dockerfile . | |
container_id=$(docker create web-builder) | |
git clone https://github.com/Native-Planet/globber | |
cd globber | |
docker cp $container_id:/webui/build ./web | |
./glob.sh web | |
hash=$(ls -1 -c . | head -1 | sed "s/glob-\\([a-z0-9\\.]*\\).glob/\\1/") | |
mkdir -p /tmp/groundseg/version/glob | |
mv glob-*.glob "/tmp/groundseg/version/glob/gallseg-${{ github.event.inputs.release_channel }}-${hash}.glob" | |
echo "$hash" > /tmp/groundseg/version/glob/hash.txt | |
- name: Upload artifacts | |
uses: actions/upload-artifact@v4 | |
with: | |
name: build-outputs | |
path: | | |
/tmp/groundseg/version/glob | |
- name: Upload web files | |
uses: actions/upload-artifact@v4 | |
with: | |
name: web-files | |
path: goseg/web/ | |
backend-build: | |
if: ${{ github.event.inputs.release_channel != 'promote' }} | |
needs: [args, frontend-build] | |
runs-on: ubuntu-latest | |
outputs: | |
hashes: ${{ steps.hash.outputs.hashes }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Download web directory | |
uses: actions/download-artifact@v4 | |
with: | |
name: web-files | |
path: goseg/web | |
- name: Setup Go | |
uses: actions/setup-go@v4 | |
with: | |
go-version: '1.23.2' | |
- name: Build binaries | |
env: | |
VERSION: ${{ needs.args.outputs.version }} | |
COMMIT: ${{ needs.args.outputs.commit }} | |
COMMIT_DATE: ${{ needs.args.outputs.commit-date }} | |
TREE_STATE: ${{ needs.args.outputs.tree-state }} | |
run: | | |
cd goseg | |
for arch in amd64 arm64; do | |
GO111MODULE=on CGO_ENABLED=0 GOARCH=$arch go build -o ../groundseg_${arch}_${{ needs.args.outputs.channel }}_${{ needs.args.outputs.bin-tag }} \ | |
-trimpath \ | |
-tags=netgo \ | |
-ldflags="-X main.Version=${VERSION} -X main.Commit=${COMMIT} -X main.CommitDate=${COMMIT_DATE} -X main.TreeState=${TREE_STATE}" . | |
done | |
- name: Generate hashes | |
id: hash | |
run: | | |
ls -la groundseg_*_${{ needs.args.outputs.channel }}_${{ needs.args.outputs.bin-tag }} | |
HASH_OUTPUT=$(sha256sum groundseg_*_${{ needs.args.outputs.channel }}_${{ needs.args.outputs.bin-tag }} | tee /dev/stderr | base64 -w0) | |
echo "Hash base64: $HASH_OUTPUT" >&2 | |
echo "hashes=$HASH_OUTPUT" >> "$GITHUB_OUTPUT" | |
- name: Upload binaries | |
uses: actions/upload-artifact@v4 | |
with: | |
name: binaries | |
path: groundseg_*_${{ needs.args.outputs.channel }}_${{ needs.args.outputs.bin-tag }} | |
provenance: | |
if: ${{ github.event.inputs.release_channel != 'promote' }} | |
needs: [backend-build] | |
permissions: | |
actions: read | |
id-token: write | |
contents: write | |
uses: slsa-framework/slsa-github-generator/.github/workflows/[email protected] | |
with: | |
base64-subjects: "${{ needs.backend-build.outputs.hashes }}" | |
promote: | |
needs: [args] | |
if: ${{ github.event.inputs.release_channel == 'promote' }} | |
runs-on: ubuntu-latest | |
steps: | |
- name: Promote version data | |
run: | | |
DEBIAN_FRONTEND=noninteractive sudo apt update | |
DEBIAN_FRONTEND=noninteractive sudo apt install -y jq | |
VERSION_SERVER="${{ github.event.inputs.version_server }}" | |
VERSION_DATA=$(curl -s -H "https://${VERSION_SERVER}/") | |
EDGE_VALUES=$(echo "$VERSION_DATA" | jq -r '.groundseg.edge.groundseg') | |
for key in amd64_url arm64_url slsa_url; do | |
VALUE=$(echo "$EDGE_VALUES" | jq -r ".$key") | |
echo "Setting $key URL to $VALUE" | |
curl -X PUT -H "X-Api-Key: ${VERSION_AUTH}" -H 'Content-Type: application/json' \ | |
"https://${VERSION_SERVER}/modify/groundseg/latest/groundseg/${key}/payload" \ | |
-d "{\"value\":\"$VALUE\"}" | |
done | |
for key in amd64_sha256 arm64_sha256 major minor patch; do | |
VALUE=$(echo "$EDGE_VALUES" | jq -r ".$key") | |
echo "Setting $key to $VALUE" | |
curl -X PUT -H "X-Api-Key: ${VERSION_AUTH}" -H 'Content-Type: application/json' \ | |
"https://${VERSION_SERVER}/modify/groundseg/latest/groundseg/${key}/${VALUE}" \ | |
-d "{\"value\":\"$VALUE\"}" | |
done | |
- name: Update GitHub Release | |
if: ${{ github.event.inputs.version_server == 'version.groundseg.app' }} | |
env: | |
GH_TOKEN: ${{ github.token }} | |
TAG: ${{ needs.args.outputs.bin-tag }} | |
run: | | |
gh api \ | |
--method PATCH \ | |
"/repos/${{ github.repository }}/releases/tags/${TAG}-edge" \ | |
-f prerelease=false | |
deploy: | |
needs: [args, backend-build, provenance] | |
if: ${{ github.event.inputs.release_channel != 'nobuild' && github.event.inputs.release_channel != 'promote' }} | |
runs-on: ubuntu-latest | |
steps: | |
- name: Download binaries | |
uses: actions/download-artifact@v4 | |
with: | |
name: binaries | |
- name: Download blobs | |
uses: actions/download-artifact@v4 | |
with: | |
name: build-outputs | |
path: artifacts | |
- name: Deploy Files | |
run: | | |
### π² πππ‘π ππ ππ‘πππππ’ π² | |
### prepare environment | |
mkdir -p ~/.config/rclone/ | |
echo "${{ env.RCLONE_CONFIG }}" > ~/.config/rclone/rclone.conf | |
DEBIAN_FRONTEND=noninteractive sudo apt update | |
DEBIAN_FRONTEND=noninteractive sudo apt install rclone jq -y | |
# | |
# copy files into bucket | |
# | |
### copy binaries into bucket | |
for arch in amd64 arm64; do | |
rclone -vvv --config ~/.config/rclone/rclone.conf copy groundseg_${arch}_${{ needs.args.outputs.channel }}_${{ needs.args.outputs.bin-tag }} r2:groundseg/bin | |
done | |
# | |
### copy glob into bucket | |
if [ -d "artifacts/version/glob" ]; then | |
GLOB_HASH=$(cat artifacts/version/glob/hash.txt) | |
rclone -vvv --config ~/.config/rclone/rclone.conf copy artifacts/version/glob/gallseg-${GLOB_HASH}.glob r2:groundseg/glob | |
fi | |
# | |
### copy provenance into bucket | |
cp ./provenance/*.jsonl groundseg_${{ needs.args.outputs.bin-tag }}_${{ needs.args.outputs.channel }}.jsonl | |
rclone -vvv --config ~/.config/rclone/rclone.conf copy groundseg_${{ needs.args.outputs.bin-tag }}_${{ needs.args.outputs.channel }}.jsonl r2:groundseg/bin | |
# | |
# update version server | |
# | |
VERSION_SERVER="${{ github.event.inputs.version_server }}" | |
# | |
### binaries and provenance | |
for arch in amd64 arm64; do | |
curl -X PUT -H "X-Api-Key: ${VERSION_AUTH}" -H 'Content-Type: application/json' \ | |
"https://${VERSION_SERVER}/modify/groundseg/${{ needs.args.outputs.channel }}/groundseg/${arch}_url/payload" \ | |
-d "{\"value\":\"https://files.native.computer/bin/groundseg_${arch}_${{ needs.args.outputs.channel }}_${{ needs.args.outputs.bin-tag }}\"}" | |
done | |
curl -X PUT -H "X-Api-Key: ${VERSION_AUTH}" -H 'Content-Type: application/json' \ | |
"https://${VERSION_SERVER}/modify/groundseg/${{ needs.args.outputs.channel }}/groundseg/slsa_url/payload" \ | |
-d "{\"value\":\"https://files.native.computer/bin/groundseg_${{ needs.args.outputs.bin-tag }}_${{ needs.args.outputs.channel }}.jsonl\"}" | |
if [ "${{ github.event.inputs.to_canary }} == "true" ]; then | |
curl -X PUT -H "X-Api-Key: ${VERSION_AUTH}" -H 'Content-Type: application/json' \ | |
"https://${VERSION_SERVER}/modify/groundseg/canary/groundseg/slsa_url/payload" \ | |
-d "{\"value\":\"https://files.native.computer/bin/groundseg_${{ needs.args.outputs.bin-tag }}_${{ needs.args.outputs.channel }}.jsonl\"}" | |
fi | |
# | |
# get hashes | |
AMD64_BIN="groundseg_amd64_${{ needs.args.outputs.channel }}_${{ needs.args.outputs.bin-tag }}" | |
ARM64_BIN="groundseg_arm64_${{ needs.args.outputs.channel }}_${{ needs.args.outputs.bin-tag }}" | |
AMDSHA=$(sha256sum "$AMD64_BIN" | awk '{print $1}') | |
ARMSHA=$(sha256sum "$ARM64_BIN" | awk '{print $1}') | |
curl -X PUT -H "X-Api-Key: ${{ env.VERSION_AUTH }}" \ | |
"https://${{ github.event.inputs.version_server }}/modify/groundseg/${{ needs.args.outputs.channel }}/groundseg/amd64_sha256/$AMDSHA" | |
curl -X PUT -H "X-Api-Key: ${{ env.VERSION_AUTH }}" \ | |
"https://${{ github.event.inputs.version_server }}/modify/groundseg/${{ needs.args.outputs.channel }}/groundseg/arm64_sha256/$ARMSHA" | |
# | |
### update canary if needed | |
if [ "${{ github.event.inputs.to_canary }}" = "true" ] && [ "${{ github.event.inputs.release_channel }}" = "edge" ]; then | |
for arch in amd64 arm64; do | |
curl -X PUT -H "X-Api-Key: ${VERSION_AUTH}" -H 'Content-Type: application/json' \ | |
"https://${VERSION_SERVER}/modify/groundseg/canary/groundseg/${arch}_url/payload" \ | |
-d "{\"value\":\"https://files.native.computer/bin/groundseg_${arch}_${{ needs.args.outputs.channel }}_${{ needs.args.outputs.bin-tag }}\"}" | |
done | |
curl -X PUT -H "X-Api-Key: ${{ env.VERSION_AUTH }}" \ | |
"https://${{ github.event.inputs.version_server }}/modify/groundseg/canary/groundseg/amd64_sha256/$AMDSHA" | |
curl -X PUT -H "X-Api-Key: ${{ env.VERSION_AUTH }}" \ | |
"https://${{ github.event.inputs.version_server }}/modify/groundseg/canary/groundseg/arm64_sha256/$ARMSHA" | |
fi | |
# | |
### update semver | |
VERSION=$(echo "${{ needs.args.outputs.bin-tag }}" | sed 's/-rc[0-9]*//') | |
MAJOR=$(echo "$VERSION" | cut -d'.' -f1 | sed 's/v//') | |
MINOR=$(echo "$VERSION" | cut -d'.' -f2) | |
PATCH=$(echo "$VERSION" | cut -d'.' -f3) | |
is_number() { | |
[[ "$1" =~ ^[0-9]+$ ]] | |
} | |
if is_number "$MAJOR" && is_number "$MINOR" && is_number "$PATCH"; then | |
echo "All version components are valid numbers. Sending to version server..." | |
curl -X PUT -H "X-Api-Key: ${{ env.VERSION_AUTH }}" \ | |
"https://${{ github.event.inputs.version_server }}/modify/groundseg/${{ needs.args.outputs.channel }}/groundseg/major/$MAJOR" | |
curl -X PUT -H "X-Api-Key: ${{ env.VERSION_AUTH }}" \ | |
"https://${{ github.event.inputs.version_server }}/modify/groundseg/${{ needs.args.outputs.channel }}/groundseg/minor/$MINOR" | |
curl -X PUT -H "X-Api-Key: ${{ env.VERSION_AUTH }}" \ | |
"https://${{ github.event.inputs.version_server }}/modify/groundseg/${{ needs.args.outputs.channel }}/groundseg/patch/$PATCH" | |
if [ "${{ github.event.inputs.to_canary }}" = "true" ] && [ "${{ github.event.inputs.release_channel }}" = "edge" ]; then | |
curl -X PUT -H "X-Api-Key: ${{ env.VERSION_AUTH }}" \ | |
"https://${{ github.event.inputs.version_server }}/modify/groundseg/canary/groundseg/major/$MAJOR" | |
curl -X PUT -H "X-Api-Key: ${{ env.VERSION_AUTH }}" \ | |
"https://${{ github.event.inputs.version_server }}/modify/groundseg/canary/groundseg/minor/$MINOR" | |
curl -X PUT -H "X-Api-Key: ${{ env.VERSION_AUTH }}" \ | |
"https://${{ github.event.inputs.version_server }}/modify/groundseg/canary/groundseg/patch/$PATCH" | |
fi | |
else | |
echo "Skipping version server semver update." | |
echo "Major: $MAJOR, Minor: $MINOR, Patch: $PATCH" | |
fi | |
- name: Create Release | |
if: ${{ github.event.inputs.release_channel == 'latest' && github.event.inputs.version_server == 'version.groundseg.app' && github.event.inputs.release_channel != 'promote' }} | |
id: create_release | |
uses: actions/create-release@v1 | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
with: | |
tag_name: ${{ needs.args.outputs.bin-tag }}-${{ needs.args.outputs.channel }} | |
release_name: Release ${{ needs.args.outputs.bin-tag }} (${{ needs.args.outputs.channel }}) | |
draft: false | |
prerelease: ${{ contains(needs.args.outputs.channel, 'canary') }} | |
- name: Upload Release Assets | |
if: ${{ github.event.inputs.release_channel == 'latest' && github.event.inputs.version_server == 'version.groundseg.app' && github.event.inputs.release_channel != 'promote' }} | |
uses: actions/upload-release-asset@v1 | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
with: | |
upload_url: ${{ steps.create_release.outputs.upload_url }} | |
asset_path: ./groundseg_*_${{ needs.args.outputs.bin-tag }}_${{ needs.args.outputs.channel }} | |
asset_name: groundseg_${{ matrix.arch }}_${{ needs.args.outputs.bin-tag }}_${{ needs.args.outputs.channel }} | |
asset_content_type: application/octet-stream | |
- name: Upload Provenance to Release | |
if: ${{ github.event.inputs.release_channel == 'latest' && github.event.inputs.version_server == 'version.groundseg.app' && github.event.inputs.release_channel != 'promote' }} | |
uses: actions/upload-release-asset@v1 | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
with: | |
upload_url: ${{ steps.create_release.outputs.upload_url }} | |
asset_path: ./provenance/*.jsonl | |
asset_name: groundseg_${{ needs.args.outputs.bin-tag }}_${{ needs.args.outputs.channel }}.jsonl | |
asset_content_type: application/json |