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