Skip to content

fix: accept any unix socket in checkDockerHost #109

fix: accept any unix socket in checkDockerHost

fix: accept any unix socket in checkDockerHost #109

Workflow file for this run

name: Release

Check failure on line 1 in .github/workflows/release.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/release.yml

Invalid workflow file

(Line: 511, Col: 14): Unexpected symbol: 'build-squid'''. Located at position 9 within expression: needs[''build-squid''].outputs.digest
on:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type'
required: true
type: choice
options:
- patch
- minor
- major
default: patch
concurrency:
group: release
cancel-in-progress: false # Never cancel an in-progress release
permissions:
contents: write # Required for creating releases, pushing version commits and tags
packages: write # Required for pushing to GHCR
id-token: write # Required for cosign keyless signing
jobs:
bump-version:
name: Bump Version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.bump.outputs.version }}
version_number: ${{ steps.bump.outputs.version_number }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4
with:
fetch-depth: 0
fetch-tags: true
- name: Verify branch
if: github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/heads/v')
run: |
echo "::error::Release should be triggered on main or a maintenance branch (v*.x), got: ${{ github.ref }}"
exit 1
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: '22'
- name: Bump version
id: bump
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Derive current version from git tags (authoritative source),
# not package.json which may be stale on main since we can't
# push version-bump commits to protected branches.
LATEST_TAG=$(git tag --sort=-version:refname | grep '^v[0-9]' | head -n1 || echo "v0.0.0")
LATEST_VERSION=${LATEST_TAG#v}
echo "Latest version from git tags: $LATEST_VERSION"
# Sync package.json to latest tag version before bumping
npm version "$LATEST_VERSION" --no-git-tag-version --allow-same-version
# Bump to next version
npm version ${{ inputs.bump }} --no-git-tag-version
VERSION=$(node -p "require('./package.json').version")
# Check if this tag already exists (idempotent retry support)
if git rev-parse "v$VERSION" >/dev/null 2>&1; then
echo "Tag v$VERSION already exists, reusing it"
echo "version=v$VERSION" >> $GITHUB_OUTPUT
echo "version_number=$VERSION" >> $GITHUB_OUTPUT
exit 0
fi
# Create a commit with the bumped version and tag it.
# Only push the tag — branch protection prevents pushing to main.
# Downstream jobs checkout by tag, so they get the correct package.json.
git add package.json package-lock.json
git commit -m "$VERSION"
git tag "v$VERSION"
git push origin "v$VERSION"
echo "version=v$VERSION" >> $GITHUB_OUTPUT
echo "version_number=$VERSION" >> $GITHUB_OUTPUT
echo "Bumped to v$VERSION (${{ inputs.bump }})"
build-squid:
name: Build Squid Image
runs-on: ubuntu-latest
needs: bump-version
outputs:
digest: ${{ steps.build_squid.outputs.digest }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4
with:
ref: ${{ needs.bump-version.outputs.version }}
- name: Log in to GitHub Container Registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Set up QEMU
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0
with:
platforms: arm64
- name: Install cosign
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
- name: Build and push Squid image
id: build_squid
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5
with:
context: ./containers/squid
push: true
platforms: linux/amd64,linux/arm64
tags: |
ghcr.io/${{ github.repository }}/squid:${{ needs.bump-version.outputs.version_number }}
ghcr.io/${{ github.repository }}/squid:latest
cache-from: type=gha,scope=squid
cache-to: type=gha,mode=max,scope=squid
- name: Sign Squid image with cosign
run: |
cosign sign --yes \
ghcr.io/${{ github.repository }}/squid@${{ steps.build_squid.outputs.digest }}
- name: Generate SBOM for Squid image
uses: anchore/sbom-action@28d71544de8eaf1b958d335707167c5f783590ad # v0.22.2
with:
image: ghcr.io/${{ github.repository }}/squid@${{ steps.build_squid.outputs.digest }}
format: spdx-json
output-file: squid-sbom.spdx.json
- name: Attest SBOM for Squid image
run: |
cosign attest --yes \
--predicate squid-sbom.spdx.json \
--type spdxjson \
ghcr.io/${{ github.repository }}/squid@${{ steps.build_squid.outputs.digest }}
build-agent:
name: Build Agent Image
runs-on: ubuntu-latest
needs: bump-version
outputs:
digest: ${{ steps.build_agent.outputs.digest }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4
with:
ref: ${{ needs.bump-version.outputs.version }}
- name: Log in to GitHub Container Registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Set up QEMU
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0
with:
platforms: arm64
- name: Install cosign
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
- name: Build and push Agent image
id: build_agent
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5
with:
context: ./containers/agent
push: true
platforms: linux/amd64,linux/arm64
tags: |
ghcr.io/${{ github.repository }}/agent:${{ needs.bump-version.outputs.version_number }}
ghcr.io/${{ github.repository }}/agent:latest
# Disable cache for agent image to ensure security-critical packages
# (like libcap2-bin for capability dropping) are always freshly installed
no-cache: true
- name: Sign Agent image with cosign
run: |
cosign sign --yes \
ghcr.io/${{ github.repository }}/agent@${{ steps.build_agent.outputs.digest }}
- name: Generate SBOM for Agent image
uses: anchore/sbom-action@28d71544de8eaf1b958d335707167c5f783590ad # v0.22.2
with:
image: ghcr.io/${{ github.repository }}/agent@${{ steps.build_agent.outputs.digest }}
format: spdx-json
output-file: agent-sbom.spdx.json
- name: Attest SBOM for Agent image
run: |
cosign attest --yes \
--predicate agent-sbom.spdx.json \
--type spdxjson \
ghcr.io/${{ github.repository }}/agent@${{ steps.build_agent.outputs.digest }}
build-api-proxy:
name: Build API Proxy Image
runs-on: ubuntu-latest
needs: bump-version
outputs:
digest: ${{ steps.build_api_proxy.outputs.digest }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4
with:
ref: ${{ needs.bump-version.outputs.version }}
- name: Log in to GitHub Container Registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Set up QEMU
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0
with:
platforms: arm64
- name: Install cosign
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
- name: Build and push API Proxy image
id: build_api_proxy
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5
with:
context: ./containers/api-proxy
push: true
platforms: linux/amd64,linux/arm64
tags: |
ghcr.io/${{ github.repository }}/api-proxy:${{ needs.bump-version.outputs.version_number }}
ghcr.io/${{ github.repository }}/api-proxy:latest
cache-from: type=gha,scope=api-proxy
cache-to: type=gha,mode=max,scope=api-proxy
- name: Sign API Proxy image with cosign
run: |
cosign sign --yes \
ghcr.io/${{ github.repository }}/api-proxy@${{ steps.build_api_proxy.outputs.digest }}
- name: Generate SBOM for API Proxy image
uses: anchore/sbom-action@28d71544de8eaf1b958d335707167c5f783590ad # v0.22.2
with:
image: ghcr.io/${{ github.repository }}/api-proxy@${{ steps.build_api_proxy.outputs.digest }}
format: spdx-json
output-file: api-proxy-sbom.spdx.json
- name: Attest SBOM for API Proxy image
run: |
cosign attest --yes \
--predicate api-proxy-sbom.spdx.json \
--type spdxjson \
ghcr.io/${{ github.repository }}/api-proxy@${{ steps.build_api_proxy.outputs.digest }}
build-cli-proxy:
name: Build CLI Proxy Image
runs-on: ubuntu-latest
needs: bump-version
outputs:
digest: ${{ steps.build_cli_proxy.outputs.digest }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4
with:
ref: ${{ needs.bump-version.outputs.version }}
- name: Log in to GitHub Container Registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Set up QEMU
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0
with:
platforms: arm64
- name: Install cosign
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
- name: Build and push CLI Proxy image
id: build_cli_proxy
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5
with:
context: ./containers/cli-proxy
push: true
platforms: linux/amd64,linux/arm64
tags: |
ghcr.io/${{ github.repository }}/cli-proxy:${{ needs.bump-version.outputs.version_number }}
ghcr.io/${{ github.repository }}/cli-proxy:latest
cache-from: type=gha,scope=cli-proxy
cache-to: type=gha,mode=max,scope=cli-proxy
- name: Sign CLI Proxy image with cosign
run: |
cosign sign --yes \
ghcr.io/${{ github.repository }}/cli-proxy@${{ steps.build_cli_proxy.outputs.digest }}
- name: Generate SBOM for CLI Proxy image
uses: anchore/sbom-action@28d71544de8eaf1b958d335707167c5f783590ad # v0.22.2
with:
image: ghcr.io/${{ github.repository }}/cli-proxy@${{ steps.build_cli_proxy.outputs.digest }}
format: spdx-json
output-file: cli-proxy-sbom.spdx.json
- name: Attest SBOM for CLI Proxy image
run: |
cosign attest --yes \
--predicate cli-proxy-sbom.spdx.json \
--type spdxjson \
ghcr.io/${{ github.repository }}/cli-proxy@${{ steps.build_cli_proxy.outputs.digest }}
# Build agent-act image with catthehacker/ubuntu:act-24.04 base for GitHub Actions parity
# amd64-only: catthehacker/ubuntu:act-24.04 does not publish arm64 manifests
build-agent-act:
name: Build Agent-Act Image
runs-on: ubuntu-latest
needs: bump-version
outputs:
digest: ${{ steps.build_agent_act.outputs.digest }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4
with:
ref: ${{ needs.bump-version.outputs.version }}
- name: Log in to GitHub Container Registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Install cosign
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
- name: Build and push Agent-Act image
id: build_agent_act
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5
with:
context: ./containers/agent
push: true
platforms: linux/amd64
tags: |
ghcr.io/${{ github.repository }}/agent-act:${{ needs.bump-version.outputs.version_number }}
ghcr.io/${{ github.repository }}/agent-act:latest
build-args: |
BASE_IMAGE=ghcr.io/catthehacker/ubuntu:act-24.04
no-cache: true
- name: Sign Agent-Act image with cosign
run: |
cosign sign --yes \
ghcr.io/${{ github.repository }}/agent-act@${{ steps.build_agent_act.outputs.digest }}
- name: Generate SBOM for Agent-Act image
uses: anchore/sbom-action@28d71544de8eaf1b958d335707167c5f783590ad # v0.22.2
with:
image: ghcr.io/${{ github.repository }}/agent-act@${{ steps.build_agent_act.outputs.digest }}
format: spdx-json
output-file: agent-act-sbom.spdx.json
- name: Attest SBOM for Agent-Act image
continue-on-error: true # Don't block release if Rekor is unavailable
run: |
# Retry with exponential backoff - agent-act's large image size
# can cause OIDC token expiry or Rekor timeouts
for attempt in 1 2 3; do
echo "Attempt $attempt of 3..."
if cosign attest --yes \
--predicate agent-act-sbom.spdx.json \
--type spdxjson \
ghcr.io/${{ github.repository }}/agent-act@${{ steps.build_agent_act.outputs.digest }}; then
echo "SBOM attestation succeeded on attempt $attempt"
exit 0
fi
if [ "$attempt" -lt 3 ]; then
sleep_time=$((30 * attempt))
echo "Attempt $attempt failed, retrying in ${sleep_time}s..."
sleep "$sleep_time"
fi
done
echo "::warning::SBOM attestation for agent-act failed after 3 attempts (Rekor may be unavailable)"
exit 1
release:
name: Create Release
runs-on: ubuntu-latest
needs: [bump-version, build-squid, build-agent, build-api-proxy, build-cli-proxy, build-agent-act]
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4
with:
ref: ${{ needs.bump-version.outputs.version }} # Checkout the version tag
fetch-depth: 0 # Full history for tag listing and changelog generation
fetch-tags: true
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: '22'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build TypeScript
run: npm run build
- name: Create esbuild bundle
run: |
node scripts/build-bundle.mjs
echo "=== Bundle size ==="
ls -lh release/awf-bundle.js
echo "=== Bundle smoke test ==="
node release/awf-bundle.js --version
node release/awf-bundle.js --help | head -5
- name: Install pkg for binary creation
run: npm install -g pkg
- name: Create binaries
run: |
mkdir -p release
# Create standalone executables for Linux (x64 and arm64)
pkg . \
--targets node18-linux-x64 \
--output release/awf-linux-x64
pkg . \
--targets node18-linux-arm64 \
--output release/awf-linux-arm64
# Create standalone executables for macOS (x64 and arm64)
pkg . \
--targets node18-macos-x64 \
--output release/awf-darwin-x64
pkg . \
--targets node18-macos-arm64 \
--output release/awf-darwin-arm64
# Verify the binaries were created
echo "=== Contents of release directory ==="
ls -lh release/
echo "=== Verifying binaries ==="
for bin in awf-linux-x64 awf-linux-arm64 awf-darwin-x64 awf-darwin-arm64; do
test -f "release/$bin" && echo "✓ Binary exists at release/$bin" || echo "✗ Binary NOT found: $bin"
file "release/$bin"
done
- name: Smoke test binary (x64)
run: |
npx tsx scripts/ci/smoke-test-binary.ts \
release/awf-linux-x64 \
${{ needs.bump-version.outputs.version_number }}
- name: Verify arm64 binary is valid ELF
run: |
file release/awf-linux-arm64 | grep -q "ELF 64-bit LSB" || { echo "ERROR: arm64 binary is not a valid ELF"; exit 1; }
file release/awf-linux-arm64 | grep -qi "aarch64\|arm" || { echo "ERROR: arm64 binary is not for ARM architecture"; exit 1; }
echo "✓ arm64 binary is a valid ELF for ARM64"
- name: Verify macOS binaries are valid Mach-O
run: |
file release/awf-darwin-x64 | grep -q "Mach-O 64-bit" || { echo "ERROR: macOS x64 binary is not a valid Mach-O"; exit 1; }
file release/awf-darwin-x64 | grep -qi "x86_64" || { echo "ERROR: macOS x64 binary is not for x86_64 architecture"; exit 1; }
echo "✓ macOS x64 binary is a valid Mach-O for x86_64"
file release/awf-darwin-arm64 | grep -q "Mach-O 64-bit" || { echo "ERROR: macOS arm64 binary is not a valid Mach-O"; exit 1; }
file release/awf-darwin-arm64 | grep -qi "arm64" || { echo "ERROR: macOS arm64 binary is not for ARM64 architecture"; exit 1; }
echo "✓ macOS arm64 binary is a valid Mach-O for ARM64"
- name: Create tarball for npm package
run: |
npm pack
mv *.tgz release/awf.tgz
- name: Generate containers list
run: |
mkdir -p release
printf '%s\n' \
'ghcr.io/${{ github.repository }}/squid@${{ needs[''build-squid''].outputs.digest }}' \
'ghcr.io/${{ github.repository }}/agent@${{ needs[''build-agent''].outputs.digest }}' \
'ghcr.io/${{ github.repository }}/agent-act@${{ needs[''build-agent-act''].outputs.digest }}' \
'ghcr.io/${{ github.repository }}/api-proxy@${{ needs[''build-api-proxy''].outputs.digest }}' \
'ghcr.io/${{ github.repository }}/cli-proxy@${{ needs[''build-cli-proxy''].outputs.digest }}' \
> release/containers.txt
echo "Generated containers.txt:"
cat release/containers.txt
- name: Generate checksums
run: |
cd release
sha256sum * > checksums.txt
- name: Get previous release tag
id: previous_tag
run: |
set -euo pipefail
CURRENT_TAG="${{ needs.bump-version.outputs.version }}"
# Use git tags directly (more reliable than gh release list)
# Get the most recent tag that is not the current tag
PREVIOUS_TAG=$(git tag --sort=-version:refname | grep -v "^${CURRENT_TAG}$" | head -n1 || echo "")
echo "previous_tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT
echo "Previous tag: $PREVIOUS_TAG (current: $CURRENT_TAG)"
- name: Generate changelog from commits
id: changelog
run: |
set -euo pipefail
CURRENT_TAG="${{ needs.bump-version.outputs.version }}"
PREVIOUS_TAG="${{ steps.previous_tag.outputs.previous_tag }}"
echo "Generating changelog from $PREVIOUS_TAG to $CURRENT_TAG"
# Generate changelog using GitHub's API
if [ -n "$PREVIOUS_TAG" ]; then
CHANGELOG=$(gh api repos/${{ github.repository }}/releases/generate-notes \
-f tag_name="$CURRENT_TAG" \
-f previous_tag_name="$PREVIOUS_TAG" \
--jq '.body' 2>/dev/null || echo "")
else
# First release - try API without previous tag
CHANGELOG=$(gh api repos/${{ github.repository }}/releases/generate-notes \
-f tag_name="$CURRENT_TAG" \
--jq '.body' 2>/dev/null || echo "")
fi
# If API call failed, fall back to git log
if [ -z "$CHANGELOG" ]; then
echo "GitHub API failed, falling back to git log"
if [ -n "$PREVIOUS_TAG" ]; then
CHANGELOG=$(git log --oneline --pretty=format:"* %s (%h)" "$PREVIOUS_TAG..HEAD" 2>/dev/null || echo "* Initial release")
else
# First release - get all commits (no arbitrary limit)
CHANGELOG=$(git log --oneline --pretty=format:"* %s (%h)" 2>/dev/null || echo "* Initial release")
fi
fi
# Write changelog to file for multiline handling
echo "$CHANGELOG" > changelog_body.md
# Validate changelog was generated
if [ ! -s changelog_body.md ]; then
echo "Error: Changelog generation failed or produced empty output"
exit 1
fi
echo "Changelog generated successfully ($(wc -l < changelog_body.md) lines)"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Generate CLI help output
id: cli_help
run: |
set -euo pipefail
# Generate CLI help from the built binary
node dist/cli.js --help > cli_help.txt
# Validate CLI help was generated
if [ ! -s cli_help.txt ]; then
echo "Error: CLI help generation failed or produced empty output"
exit 1
fi
echo "CLI help generated ($(wc -l < cli_help.txt) lines):"
cat cli_help.txt
- name: Create Release Notes
id: release_notes
env:
VERSION: ${{ needs.bump-version.outputs.version }}
VERSION_NUMBER: ${{ needs.bump-version.outputs.version_number }}
REPOSITORY: ${{ github.repository }}
run: |
set -euo pipefail
# Use Node.js script for safe template substitution
# (avoids shell injection issues with special characters)
node scripts/generate-release-notes.js \
changelog_body.md \
cli_help.txt \
release_notes.md
# Validate output was generated
if [ ! -s release_notes.md ]; then
echo "Error: Release notes generation failed"
exit 1
fi
# Cleanup temp files
rm -f changelog_body.md cli_help.txt
echo "Release notes preview (first 20 lines):"
head -20 release_notes.md
- name: Create GitHub Release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
tag_name: ${{ needs.bump-version.outputs.version }}
name: Release ${{ needs.bump-version.outputs.version }}
body_path: release_notes.md
draft: false
prerelease: ${{ contains(needs.bump-version.outputs.version, 'alpha') || contains(needs.bump-version.outputs.version, 'beta') || contains(needs.bump-version.outputs.version, 'rc') }}
files: |
release/awf-linux-x64
release/awf-linux-arm64
release/awf-darwin-x64
release/awf-darwin-arm64
release/awf-bundle.js
release/awf.tgz
release/containers.txt
release/checksums.txt
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload artifacts (for debugging)
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
if: always()
with:
name: release-artifacts
path: release/
retention-days: 7