The 'Sign artifacts' step failed on alpha.7 with 'Error while loading the secret key file' (exit 2): minisign downloaded and ran, but the reconstructed key file was unparseable. A minisign secret key is two lines (comment + base64 blob); Gitea/act_runner secret storage mangles the embedded newline, collapsing it to one line. Decode the secret as base64 (single-line, mangling-proof) with auto-detect fallback to a raw two-line key. Fails loudly with the fix command if the secret is neither form. Requires re-storing MINISIGN_SECRET_KEY as: base64 < secret.key | tr -d '\n' Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
162 lines
7.6 KiB
YAML
162 lines
7.6 KiB
YAML
name: Build Host Agent (Rust)
|
|
|
|
# Rust agent ships on its own tag namespace (agent-v*) so it never collides
|
|
# with the legacy Go pipeline (v*.*.*). Artifacts publish to the CDN /alpha/
|
|
# channel — /host-agent/latest/ stays on the Go build until cutover.
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'agent-v*'
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
|
|
env:
|
|
# Override the macOS toolchain names in corrosion-host-agent/.cargo/config.toml
|
|
# (real env beats the config [env] table).
|
|
CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER: musl-gcc
|
|
CC_x86_64_unknown_linux_musl: musl-gcc
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Get version from tag
|
|
id: version
|
|
run: echo "VERSION=${GITHUB_REF#refs/tags/agent-v}" >> $GITHUB_OUTPUT
|
|
|
|
- name: Verify tag matches Cargo.toml
|
|
run: |
|
|
CARGO_VERSION=$(grep '^version' corrosion-host-agent/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
|
|
if [ "${{ steps.version.outputs.VERSION }}" != "$CARGO_VERSION" ]; then
|
|
echo "Tag agent-v${{ steps.version.outputs.VERSION }} does not match Cargo.toml version $CARGO_VERSION"
|
|
exit 1
|
|
fi
|
|
|
|
# The Asgard runner executes jobs in a bare node:20-bullseye container
|
|
# (no Rust, no sudo, runs as root) — bootstrap the toolchain per-run,
|
|
# same pattern as actions/setup-go in the Go pipeline.
|
|
- name: Install Rust + cross toolchains
|
|
run: |
|
|
apt-get update -qq
|
|
apt-get install -y -qq build-essential musl-tools gcc-mingw-w64-x86-64 curl
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal
|
|
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
|
|
"$HOME/.cargo/bin/rustup" target add x86_64-unknown-linux-musl x86_64-pc-windows-gnu
|
|
|
|
- name: Build Linux AMD64 (static musl)
|
|
run: |
|
|
cd corrosion-host-agent
|
|
cargo build --release --target x86_64-unknown-linux-musl
|
|
mkdir -p bin
|
|
cp target/x86_64-unknown-linux-musl/release/corrosion-host-agent bin/corrosion-host-agent-linux-amd64
|
|
chmod +x bin/corrosion-host-agent-linux-amd64
|
|
|
|
- name: Build Windows AMD64 (mingw)
|
|
run: |
|
|
cd corrosion-host-agent
|
|
cargo build --release --target x86_64-pc-windows-gnu
|
|
cp target/x86_64-pc-windows-gnu/release/corrosion-host-agent.exe bin/corrosion-host-agent-windows-amd64.exe
|
|
|
|
- name: Generate checksums
|
|
run: |
|
|
cd corrosion-host-agent/bin
|
|
sha256sum corrosion-host-agent-linux-amd64 > checksums.txt
|
|
sha256sum corrosion-host-agent-windows-amd64.exe >> checksums.txt
|
|
cat checksums.txt
|
|
|
|
- name: Sign artifacts (minisign)
|
|
env:
|
|
MINISIGN_SECRET_KEY: ${{ secrets.MINISIGN_SECRET_KEY }}
|
|
run: |
|
|
if [ -z "$MINISIGN_SECRET_KEY" ]; then
|
|
echo "::error::MINISIGN_SECRET_KEY secret is not set — refusing to publish unsigned agent artifacts."
|
|
exit 1
|
|
fi
|
|
# minisign isn't packaged for bullseye — fetch the official static binary.
|
|
curl -sSL https://github.com/jedisct1/minisign/releases/download/0.12/minisign-0.12-linux.tar.gz -o /tmp/minisign.tgz
|
|
tar -xzf /tmp/minisign.tgz -C /tmp
|
|
MINISIGN="$(find /tmp -type f -name minisign -path '*linux*' | head -1)"
|
|
chmod +x "$MINISIGN"
|
|
"$MINISIGN" -v
|
|
# A minisign secret key file is TWO lines (comment + base64 blob). CI
|
|
# secret storage mangles embedded newlines, collapsing it to one line
|
|
# so minisign can't load it. Preferred form: store the secret
|
|
# base64-encoded (single line) — we decode it here. Auto-detect so a
|
|
# correctly-stored raw two-line key still works.
|
|
if printf '%s' "$MINISIGN_SECRET_KEY" | base64 -d 2>/dev/null | head -1 | grep -q "untrusted comment:"; then
|
|
printf '%s' "$MINISIGN_SECRET_KEY" | base64 -d > /tmp/sign.key
|
|
else
|
|
printf '%s\n' "$MINISIGN_SECRET_KEY" > /tmp/sign.key
|
|
fi
|
|
if ! head -1 /tmp/sign.key | grep -q "untrusted comment:"; then
|
|
echo "::error::MINISIGN_SECRET_KEY is neither base64 of a minisign key nor a raw two-line key file. Store it as: base64 < your-secret.key | tr -d '\n'"
|
|
rm -f /tmp/sign.key
|
|
exit 1
|
|
fi
|
|
cd corrosion-host-agent/bin
|
|
# Passwordless key (-W generated); feed empty stdin so it never blocks.
|
|
for f in corrosion-host-agent-linux-amd64 corrosion-host-agent-windows-amd64.exe checksums.txt; do
|
|
"$MINISIGN" -S -s /tmp/sign.key -m "$f" -x "$f.minisig" < /dev/null
|
|
done
|
|
rm -f /tmp/sign.key
|
|
echo "signed: $(ls *.minisig)"
|
|
|
|
- name: Create Release
|
|
env:
|
|
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
run: |
|
|
API_URL="${{ github.server_url }}/api/v1"
|
|
REPO="${{ github.repository }}"
|
|
VERSION="agent-v${{ steps.version.outputs.VERSION }}"
|
|
|
|
RESPONSE=$(curl -s -X POST \
|
|
-H "Authorization: token ${RELEASE_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"tag_name\": \"${VERSION}\", \"name\": \"Corrosion Host Agent ${VERSION}\", \"body\": \"Rust host agent release ${VERSION}\", \"draft\": false, \"prerelease\": true}" \
|
|
"${API_URL}/repos/${REPO}/releases")
|
|
RELEASE_ID=$(echo "$RESPONSE" | grep -o '"id":[0-9]*' | head -1 | grep -o '[0-9]*')
|
|
|
|
for f in corrosion-host-agent-linux-amd64 corrosion-host-agent-linux-amd64.minisig \
|
|
corrosion-host-agent-windows-amd64.exe corrosion-host-agent-windows-amd64.exe.minisig \
|
|
checksums.txt checksums.txt.minisig; do
|
|
curl -s -X POST \
|
|
-H "Authorization: token ${RELEASE_TOKEN}" \
|
|
-H "Content-Type: application/octet-stream" \
|
|
--data-binary @corrosion-host-agent/bin/$f \
|
|
"${API_URL}/repos/${REPO}/releases/${RELEASE_ID}/assets?name=$f"
|
|
done
|
|
|
|
- name: Upload to CDN (alpha channel)
|
|
run: |
|
|
CDN_URL="https://cdn.corrosionmgmt.com"
|
|
VERSION="${{ steps.version.outputs.VERSION }}"
|
|
|
|
for f in corrosion-host-agent-linux-amd64 corrosion-host-agent-linux-amd64.minisig \
|
|
corrosion-host-agent-windows-amd64.exe corrosion-host-agent-windows-amd64.exe.minisig \
|
|
checksums.txt checksums.txt.minisig; do
|
|
curl -s -X POST \
|
|
-F "file=@corrosion-host-agent/bin/$f" \
|
|
"${CDN_URL}/host-agent/alpha/$f"
|
|
curl -s -X POST \
|
|
-F "file=@corrosion-host-agent/bin/$f" \
|
|
"${CDN_URL}/host-agent/${VERSION}/$f"
|
|
done
|
|
|
|
echo "CDN upload complete: ${CDN_URL}/host-agent/alpha/"
|
|
|
|
- name: Build Summary
|
|
run: |
|
|
echo "## Corrosion Host Agent (Rust) Build Complete" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "**Version:** ${{ steps.version.outputs.VERSION }}" >> $GITHUB_STEP_SUMMARY
|
|
echo "**Commit:** ${GITHUB_SHA:0:7}" >> $GITHUB_STEP_SUMMARY
|
|
echo "**Channel:** alpha (latest/ untouched until cutover)" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "### Built Artifacts:" >> $GITHUB_STEP_SUMMARY
|
|
echo "- Linux AMD64 static musl ($(stat -c%s corrosion-host-agent/bin/corrosion-host-agent-linux-amd64) bytes)" >> $GITHUB_STEP_SUMMARY
|
|
echo "- Windows AMD64 mingw ($(stat -c%s corrosion-host-agent/bin/corrosion-host-agent-windows-amd64.exe) bytes)" >> $GITHUB_STEP_SUMMARY
|
|
echo "- SHA256 checksums" >> $GITHUB_STEP_SUMMARY
|