GroundSeg SLSA3 release #61
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 | |
- edge | |
- canary | |
- latest | |
to_canary: | |
description: 'Also push build to canary channel (if edge)' | |
required: false | |
type: boolean | |
default: false | |
version_server: | |
description: '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' }} | |
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: | |
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: | |
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 }}" | |
deploy: | |
needs: [args, backend-build, provenance] | |
if: ${{ github.event.inputs.release_channel != 'nobuild' }} | |
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: | | |
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 | |
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 | |
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 | |
VERSION_SERVER="${{ github.event.inputs.version_server }}" | |
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 | |
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" | |
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" | |
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' }} | |
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' }} | |
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' }} | |
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: provenance.jsonl | |
asset_content_type: application/json |