Files
probo/.github/workflows/release.yaml
Émile Ré be1e94da71 Add @probo/cookie-banner SDK package scaffold
Introduce the boilerplate for a new public npm package that will
serve as the cookie consent banner JavaScript SDK. The package
uses esbuild to produce both an IIFE bundle (for script tag
embedding) and an ESM module. Versioning is independent from the
monorepo: CI compares package.json against npm and only publishes
when the version changes.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:31 +04:00

595 lines
23 KiB
YAML

name: "Release"
on:
push:
tags:
- "v*"
permissions:
contents: "read"
jobs:
# ── Build frontend apps ──────────────────────────────────────────────
build-apps:
name: "build-apps"
runs-on: "runs-on=${{ github.run_id }}/runner=4cpu-linux-x64/extras=s3-cache"
permissions:
contents: "read"
steps:
- uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6
with:
submodules: recursive
- uses: "runs-on/action@742bf56072eb4845a0f94b3394673e4903c90ff0" # v2
- uses: "./.github/actions/setup"
with:
go: "false"
- run: "npm --workspace @probo/emails run build"
- run: "make relay"
- name: "Build console"
run: |
npm --workspace @probo/console run check
NODE_ENV=production npm --workspace @probo/console run build
- name: "Build trust"
run: |
npm --workspace @probo/trust run check
NODE_ENV=production npm --workspace @probo/trust run build
- uses: "actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f" # v7
with:
name: "frontend-apps"
path: |
apps/console/dist/
apps/trust/dist/
packages/emails/dist/
retention-days: 1
# ── Build Go binaries (matrix by GOOS/GOARCH) ───────────────────────
build-binary:
name: "binary (${{ matrix.goos }}/${{ matrix.goarch }})"
needs: [build-apps]
runs-on: "runs-on=${{ github.run_id }}/runner=4cpu-linux-x64/extras=s3-cache"
permissions:
contents: "read"
strategy:
fail-fast: false
matrix:
include:
- { goos: linux, goarch: amd64 }
- { goos: linux, goarch: arm64 }
- { goos: darwin, goarch: amd64 }
- { goos: darwin, goarch: arm64 }
- { goos: windows, goarch: amd64 }
- { goos: freebsd, goarch: amd64 }
- { goos: freebsd, goarch: arm64 }
- { goos: openbsd, goarch: amd64 }
- { goos: openbsd, goarch: arm64 }
steps:
- uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6
with:
submodules: recursive
- uses: "runs-on/action@742bf56072eb4845a0f94b3394673e4903c90ff0" # v2
- uses: "./.github/actions/setup"
with:
node: "false"
- uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8
with:
name: "frontend-apps"
- name: "Generate Go code"
run: |
go generate ./pkg/server/api/connect/v1
go generate ./pkg/server/api/console/v1
go generate ./pkg/server/api/trust/v1
go generate ./pkg/server/api/mcp/v1
- name: "Build binaries"
env:
CGO_ENABLED: "0"
GOOS: "${{ matrix.goos }}"
GOARCH: "${{ matrix.goarch }}"
run: |
VERSION="${GITHUB_REF_NAME#v}"
EXT=""
if [ "$GOOS" = "windows" ]; then EXT=".exe"; fi
go build -ldflags "-s -w -X 'main.version=${VERSION}' -X 'main.env=prod'" \
-gcflags="-e" -o "dist/probod${EXT}" ./cmd/probod/main.go
go build -ldflags "-s -w" \
-gcflags="-e" -o "dist/probod-bootstrap${EXT}" ./cmd/probod-bootstrap/main.go
go build -ldflags "-s -w -X 'main.version=${VERSION}'" \
-gcflags="-e" -o "dist/prb${EXT}" ./cmd/prb/main.go
- name: "Create archives"
env:
GOOS: "${{ matrix.goos }}"
GOARCH: "${{ matrix.goarch }}"
run: |
case "$GOOS" in
linux) OS="Linux" ;;
darwin) OS="Darwin" ;;
windows) OS="Windows" ;;
freebsd) OS="Freebsd" ;;
openbsd) OS="Openbsd" ;;
esac
case "$GOARCH" in
amd64) ARCH="x86_64" ;;
*) ARCH="$GOARCH" ;;
esac
EXT=""
if [ "$GOOS" = "windows" ]; then EXT=".exe"; fi
mkdir -p archives
PROBOD_DIR="probod_${OS}_${ARCH}"
mkdir -p "staging/${PROBOD_DIR}"
cp "dist/probod${EXT}" "dist/probod-bootstrap${EXT}" "dist/prb${EXT}" \
README.md LICENSE CHANGELOG.md "staging/${PROBOD_DIR}/"
if [ "$GOOS" = "windows" ]; then
(cd staging && zip -r "../archives/${PROBOD_DIR}.zip" "${PROBOD_DIR}")
else
tar -czf "archives/${PROBOD_DIR}.tar.gz" -C staging "${PROBOD_DIR}"
fi
PRB_DIR="prb_${OS}_${ARCH}"
mkdir -p "staging/${PRB_DIR}"
cp "dist/prb${EXT}" README.md LICENSE CHANGELOG.md "staging/${PRB_DIR}/"
if [ "$GOOS" = "windows" ]; then
(cd staging && zip -r "../archives/${PRB_DIR}.zip" "${PRB_DIR}")
else
tar -czf "archives/${PRB_DIR}.tar.gz" -C staging "${PRB_DIR}"
fi
- uses: "actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f" # v7
with:
name: "binary-${{ matrix.goos }}-${{ matrix.goarch }}"
path: "dist/"
retention-days: 1
- uses: "actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f" # v7
with:
name: "archive-${{ matrix.goos }}-${{ matrix.goarch }}"
path: "archives/"
retention-days: 1
# ── Build Docker images (matrix by architecture) ─────────────────────
build-docker:
name: "docker (${{ matrix.arch }})"
needs: [build-binary]
runs-on: "runs-on=${{ github.run_id }}/runner=${{ matrix.runner }}/extras=s3-cache"
permissions:
contents: "read"
packages: "write"
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
platform: "linux/amd64"
runner: "4cpu-linux-x64"
- arch: arm64
platform: "linux/arm64"
runner: "4cpu-linux-arm64"
steps:
- uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6
- uses: "runs-on/action@742bf56072eb4845a0f94b3394673e4903c90ff0" # v2
- uses: "docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd" # v4.0.0
- uses: "docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2" # v4.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8
with:
name: "binary-linux-${{ matrix.arch }}"
path: "linux/${{ matrix.arch }}"
- name: "Prepare binaries"
run: "chmod +x linux/${{ matrix.arch }}/*"
- name: "Build and push Docker image"
run: |
docker buildx build \
--platform "${{ matrix.platform }}" \
--label "org.opencontainers.image.title=probod" \
--label "org.opencontainers.image.description=Probo compliance management platform" \
--label "org.opencontainers.image.url=https://github.com/getprobo/probo" \
--label "org.opencontainers.image.source=https://github.com/getprobo/probo" \
--label "org.opencontainers.image.version=${{ github.ref_name }}" \
--label "org.opencontainers.image.revision=${{ github.sha }}" \
--label "org.opencontainers.image.licenses=MIT" \
--tag "ghcr.io/getprobo/probo:${{ github.ref_name }}-${{ matrix.arch }}" \
--push \
.
# ── Create multi-arch Docker manifest and sign ──────────────────────
docker-manifest:
name: "docker-manifest"
needs: [build-docker]
runs-on: "runs-on=${{ github.run_id }}/runner=2cpu-linux-x64/extras=s3-cache"
permissions:
packages: "write"
id-token: "write"
outputs:
digest: ${{ steps.digest.outputs.digest }}
steps:
- uses: "runs-on/action@742bf56072eb4845a0f94b3394673e4903c90ff0" # v2
- uses: "docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd" # v4.0.0
- uses: "docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2" # v4.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: "sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad" # v4.0.0
- name: "Create and push manifest"
run: |
docker buildx imagetools create \
--tag "ghcr.io/getprobo/probo:${{ github.ref_name }}" \
--tag "ghcr.io/getprobo/probo:latest" \
"ghcr.io/getprobo/probo:${{ github.ref_name }}-amd64" \
"ghcr.io/getprobo/probo:${{ github.ref_name }}-arm64"
- name: "Get manifest digest"
id: digest
run: |
DIGEST=$(docker buildx imagetools inspect "ghcr.io/getprobo/probo:${{ github.ref_name }}" --format '{{json .Manifest.Digest}}' | jq -r)
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"
- name: "Sign Docker manifest"
run: cosign sign "ghcr.io/getprobo/probo@${{ steps.digest.outputs.digest }}" --yes
# ── Create GitHub release ───────────────────────────────────────────
github-release:
name: "github-release"
needs: [build-binary]
runs-on: "runs-on=${{ github.run_id }}/runner=2cpu-linux-x64/extras=s3-cache"
permissions:
contents: "write"
id-token: "write"
steps:
- uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6
with:
fetch-depth: 0
- uses: "runs-on/action@742bf56072eb4845a0f94b3394673e4903c90ff0" # v2
- uses: "sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad" # v4.0.0
- uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8
with:
pattern: "archive-*"
path: "archives"
merge-multiple: true
- name: "Generate checksums and sign"
run: |
cd archives
sha256sum *.tar.gz *.zip > checksums.txt
cosign sign-blob --bundle="checksums.txt.bundle" checksums.txt --yes
- name: "Generate release notes"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh api "repos/${{ github.repository }}/releases/generate-notes" \
-f tag_name="${{ github.ref_name }}" \
--jq '.body' > release-notes.md
cat >> release-notes.md << EOF
## Docker Images
- \`ghcr.io/getprobo/probo:${{ github.ref_name }}\` (multi-arch: linux/amd64, linux/arm64)
- \`ghcr.io/getprobo/probo:latest\` (multi-arch: linux/amd64, linux/arm64)
EOF
- name: "Create GitHub release"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PRERELEASE_FLAG=""
if echo "${{ github.ref_name }}" | grep -qE '(alpha|beta|rc)'; then
PRERELEASE_FLAG="--prerelease"
fi
gh release delete "${{ github.ref_name }}" --yes 2>/dev/null || true
gh release create "${{ github.ref_name }}" \
--title "${{ github.ref_name }}" \
--notes-file release-notes.md \
$PRERELEASE_FLAG \
archives/*
# ── Security scan, SBOM, and attestations ───────────────────────────
security-scan:
name: "security-scan"
needs: [docker-manifest, github-release]
runs-on: "runs-on=${{ github.run_id }}/runner=2cpu-linux-x64/extras=s3-cache"
permissions:
contents: "write"
packages: "write"
id-token: "write"
attestations: "write"
security-events: "write"
steps:
- uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6
with:
submodules: recursive
- uses: "runs-on/action@742bf56072eb4845a0f94b3394673e4903c90ff0" # v2
- uses: "docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2" # v4.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8
with:
pattern: "archive-*"
path: "archives"
merge-multiple: true
- name: "Scan Docker image with Trivy"
uses: "aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1" # 0.35.0
with:
image-ref: "ghcr.io/getprobo/probo:${{ github.ref_name }}"
format: "sarif"
output: "trivy-results.sarif"
exit-code: 1
ignore-unfixed: true
vuln-type: "os,library"
severity: "CRITICAL,HIGH"
- name: "Upload Trivy scan results"
uses: "github/codeql-action/upload-sarif@6bc82e05fd0ea64601dd4b465378bbcf57de0314" # v4.32.1
if: always()
with:
sarif_file: "trivy-results.sarif"
- name: "Generate SBOM"
uses: "anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610" # v0.24.0
with:
path: ./
format: cyclonedx-json
output-file: sbom.json
- name: "Run vulnerability scan"
uses: "anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2" # v7.4.0
with:
sbom: "sbom.json"
fail-build: true
severity-cutoff: critical
- name: "Attest SBOM for archives"
uses: "actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e" # v4
with:
subject-path: "archives/*.tar.gz, archives/*.zip"
sbom-path: "sbom.json"
- name: "Attest build provenance for archives"
uses: "actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32" # v4
with:
subject-path: "archives/*.tar.gz, archives/*.zip"
- name: "Attest Docker image SBOM"
uses: "actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e" # v4
with:
subject-name: "ghcr.io/getprobo/probo"
subject-digest: ${{ needs.docker-manifest.outputs.digest }}
sbom-path: "sbom.json"
- uses: "actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f" # v7
with:
name: "sbom"
path: "sbom.json"
retention-days: 30
# ── Publish Homebrew formula ────────────────────────────────────────
homebrew:
name: "homebrew"
needs: [github-release]
runs-on: "runs-on=${{ github.run_id }}/runner=2cpu-linux-x64/extras=s3-cache"
permissions:
contents: "read"
steps:
- uses: "runs-on/action@742bf56072eb4845a0f94b3394673e4903c90ff0" # v2
- name: "Download checksums from release"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release download "${{ github.ref_name }}" \
--repo "${{ github.repository }}" \
--pattern "checksums.txt"
- name: "Generate and publish Homebrew formula"
env:
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
run: |
VERSION="${GITHUB_REF_NAME#v}"
TAG="${GITHUB_REF_NAME}"
BASE_URL="https://github.com/${{ github.repository }}/releases/download/${TAG}"
DARWIN_ARM64_SHA=$(grep "prb_Darwin_arm64.tar.gz" checksums.txt | awk '{print $1}')
DARWIN_X86_64_SHA=$(grep "prb_Darwin_x86_64.tar.gz" checksums.txt | awk '{print $1}')
LINUX_ARM64_SHA=$(grep "prb_Linux_arm64.tar.gz" checksums.txt | awk '{print $1}')
LINUX_X86_64_SHA=$(grep "prb_Linux_x86_64.tar.gz" checksums.txt | awk '{print $1}')
cat > prb.rb << RUBY
# typed: false
# frozen_string_literal: true
class Prb < Formula
desc "Probo CLI"
homepage "https://github.com/getprobo/probo"
version "${VERSION}"
license "MIT"
on_macos do
on_arm do
url "${BASE_URL}/prb_Darwin_arm64.tar.gz"
sha256 "${DARWIN_ARM64_SHA}"
end
on_intel do
url "${BASE_URL}/prb_Darwin_x86_64.tar.gz"
sha256 "${DARWIN_X86_64_SHA}"
end
end
on_linux do
on_arm do
url "${BASE_URL}/prb_Linux_arm64.tar.gz"
sha256 "${LINUX_ARM64_SHA}"
end
on_intel do
url "${BASE_URL}/prb_Linux_x86_64.tar.gz"
sha256 "${LINUX_X86_64_SHA}"
end
end
def install
bin.install "prb"
end
test do
assert_match version.to_s, shell_output("#{bin}/prb --version")
end
end
RUBY
CONTENT=$(base64 -w0 prb.rb)
HEAD_OID=$(gh api "repos/getprobo/homebrew-tap/git/ref/heads/main" --jq '.object.sha')
gh api graphql -f query='
mutation($headline: String!, $oid: GitObjectID!, $contents: Base64String!) {
createCommitOnBranch(input: {
branch: {
repositoryNameWithOwner: "getprobo/homebrew-tap"
branchName: "main"
}
message: { headline: $headline }
expectedHeadOid: $oid
fileChanges: {
additions: [{
path: "Formula/prb.rb"
contents: $contents
}]
}
}) {
commit { url }
}
}' \
-f headline="prb ${VERSION}" \
-f oid="${HEAD_OID}" \
-f contents="${CONTENT}"
# ── n8n node release ────────────────────────────────────────────────
n8n-node-release:
name: "n8n-node-release"
needs: [github-release]
runs-on: "ubuntu-latest"
permissions:
contents: write
id-token: write
attestations: write
steps:
- uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6
with:
fetch-depth: 0
submodules: recursive
- uses: "actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f" # v6
with:
node-version-file: ".nvmrc"
cache: "npm"
registry-url: "https://registry.npmjs.org"
scope: "@probo"
- run: "npm install -g npm@latest"
- run: "npm ci"
- run: "npm --workspace @probo/n8n-nodes-probo run build"
- name: "Set package version from git tag"
run: |
VERSION="${GITHUB_REF_NAME#v}"
npm --workspace @probo/n8n-nodes-probo version "$VERSION" --no-git-tag-version
- uses: "anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610" # v0.24.0
with:
path: ./packages/n8n-node
format: cyclonedx-json
output-file: packages/n8n-node/sbom.json
- uses: "anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2" # v7.4.0
with:
path: ./packages/n8n-node
fail-build: true
severity-cutoff: critical
- name: "Generate checksums for dist files"
id: checksum
run: |
cd packages/n8n-node/dist
find . -type f | while read file; do
echo "$(sha256sum "$file" | head -c 64) $file"
done > ../checksums.txt
echo "hashes=$(cat ../checksums.txt | base64 -w0)" >> "$GITHUB_OUTPUT"
- run: "npm --workspace @probo/n8n-nodes-probo publish --access public --dry-run"
- run: "npm --workspace @probo/n8n-nodes-probo publish --access public"
- uses: "actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e" # v4
with:
subject-path: "packages/n8n-node/dist/**"
sbom-path: "packages/n8n-node/sbom.json"
- uses: "actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32" # v4
with:
subject-path: "packages/n8n-node/dist/**"
- uses: "actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f" # v7
with:
name: "npm-sbom"
path: |
packages/n8n-node/sbom.json
packages/n8n-node/checksums.txt
retention-days: 30
# ── Cookie banner SDK release ──────────────────────────────────────
cookie-banner-release:
name: "cookie-banner-release"
needs: [github-release]
runs-on: "ubuntu-latest"
permissions:
contents: write
id-token: write
attestations: write
steps:
- uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6
with:
fetch-depth: 0
submodules: recursive
- uses: "actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f" # v6
with:
node-version-file: ".nvmrc"
cache: "npm"
registry-url: "https://registry.npmjs.org"
scope: "@probo"
- run: "npm install -g npm@latest"
- run: "npm ci"
- name: "Check if publish is needed"
id: check
run: |
LOCAL=$(node -p "require('./packages/cookie-banner/package.json').version")
PUBLISHED=$(npm view @probo/cookie-banner version 2>/dev/null || echo "0.0.0")
echo "local=$LOCAL published=$PUBLISHED"
if [ "$LOCAL" = "$PUBLISHED" ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
fi
- run: "npm --workspace @probo/cookie-banner run build"
if: steps.check.outputs.skip != 'true'
- uses: "anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610" # v0.24.0
if: steps.check.outputs.skip != 'true'
with:
path: ./packages/cookie-banner
format: cyclonedx-json
output-file: packages/cookie-banner/sbom.json
- uses: "anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2" # v7.4.0
if: steps.check.outputs.skip != 'true'
with:
path: ./packages/cookie-banner
fail-build: true
severity-cutoff: critical
- name: "Generate checksums for dist files"
id: checksum
if: steps.check.outputs.skip != 'true'
run: |
cd packages/cookie-banner/dist
find . -type f | while read file; do
echo "$(sha256sum "$file" | head -c 64) $file"
done > ../checksums.txt
echo "hashes=$(cat ../checksums.txt | base64 -w0)" >> "$GITHUB_OUTPUT"
- run: "npm --workspace @probo/cookie-banner publish --access public --dry-run"
if: steps.check.outputs.skip != 'true'
# - run: "npm --workspace @probo/cookie-banner publish --access public"
# if: steps.check.outputs.skip != 'true'
- uses: "actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e" # v4
if: steps.check.outputs.skip != 'true'
with:
subject-path: "packages/cookie-banner/dist/**"
sbom-path: "packages/cookie-banner/sbom.json"
- uses: "actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32" # v4
if: steps.check.outputs.skip != 'true'
with:
subject-path: "packages/cookie-banner/dist/**"
- uses: "actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f" # v7
if: steps.check.outputs.skip != 'true'
with:
name: "cookie-banner-sbom"
path: |
packages/cookie-banner/sbom.json
packages/cookie-banner/checksums.txt
retention-days: 30