0.14.0 #44
Workflow file for this run
This file contains hidden or 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: Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*.*.*' # Trigger on version tags like v1.0.0, v0.1.0, etc. | |
| workflow_dispatch: # Allow manual triggers | |
| permissions: | |
| contents: write # Required for creating releases | |
| packages: write # Required for pushing to GHCR | |
| id-token: write # Required for cosign keyless signing | |
| jobs: | |
| build-and-release: | |
| name: Build and Release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 | |
| - 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: Extract version from tag | |
| id: version_early | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| VERSION=$(node -p "require('./package.json').version") | |
| echo "version=v$VERSION" >> $GITHUB_OUTPUT | |
| echo "version_number=$VERSION" >> $GITHUB_OUTPUT | |
| else | |
| VERSION="${GITHUB_REF#refs/tags/}" | |
| VERSION_NUMBER="${VERSION#v}" | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "version_number=$VERSION_NUMBER" >> $GITHUB_OUTPUT | |
| fi | |
| - 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 Squid image | |
| id: build_squid | |
| uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 | |
| with: | |
| context: ./containers/squid | |
| push: true | |
| tags: | | |
| ghcr.io/${{ github.repository }}/squid:${{ steps.version_early.outputs.version_number }} | |
| ghcr.io/${{ github.repository }}/squid:latest | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| - 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 }} | |
| - name: Build and push Agent image | |
| id: build_agent | |
| uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 | |
| with: | |
| context: ./containers/agent | |
| push: true | |
| tags: | | |
| ghcr.io/${{ github.repository }}/agent:${{ steps.version_early.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 agent-act image with catthehacker/ubuntu:act-24.04 base for GitHub Actions parity | |
| - name: Build and push Agent-Act image | |
| id: build_agent_act | |
| uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 | |
| with: | |
| context: ./containers/agent | |
| push: true | |
| tags: | | |
| ghcr.io/${{ github.repository }}/agent-act:${{ steps.version_early.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 | |
| run: | | |
| cosign attest --yes \ | |
| --predicate agent-act-sbom.spdx.json \ | |
| --type spdxjson \ | |
| ghcr.io/${{ github.repository }}/agent-act@${{ steps.build_agent_act.outputs.digest }} | |
| - name: Install pkg for binary creation | |
| run: npm install -g pkg | |
| - name: Create binaries | |
| run: | | |
| mkdir -p release | |
| # Create standalone executable for Linux | |
| pkg . \ | |
| --targets node18-linux-x64 \ | |
| --output release/awf-linux-x64 | |
| # Verify the binary was created | |
| echo "=== Contents of release directory ===" | |
| ls -lh release/ | |
| echo "=== Verifying binary ===" | |
| test -f release/awf-linux-x64 && echo "✓ Binary exists at release/awf-linux-x64" || echo "✗ Binary NOT found!" | |
| file release/awf-linux-x64 | |
| - name: Smoke test binary | |
| run: | | |
| npx tsx scripts/ci/smoke-test-binary.ts \ | |
| release/awf-linux-x64 \ | |
| ${{ steps.version_early.outputs.version_number }} | |
| - name: Create tarball for npm package | |
| run: | | |
| npm pack | |
| mv *.tgz release/awf.tgz | |
| - name: Generate checksums | |
| run: | | |
| cd release | |
| sha256sum * > checksums.txt | |
| - name: Get previous release tag | |
| id: previous_tag | |
| run: | | |
| set -euo pipefail | |
| CURRENT_TAG="${{ steps.version_early.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="${{ steps.version_early.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: ${{ steps.version_early.outputs.version }} | |
| VERSION_NUMBER: ${{ steps.version_early.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@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1 | |
| with: | |
| tag_name: ${{ steps.version_early.outputs.version }} | |
| name: Release ${{ steps.version_early.outputs.version }} | |
| body_path: release_notes.md | |
| draft: false | |
| prerelease: ${{ contains(steps.version_early.outputs.version, 'alpha') || contains(steps.version_early.outputs.version, 'beta') || contains(steps.version_early.outputs.version, 'rc') }} | |
| files: | | |
| release/awf-linux-x64 | |
| release/awf.tgz | |
| 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 |