Split release into per-track packages

Each shippable artifact (prb, probod server group, probod-bootstrap,
@probo/n8n-nodes-probo, @probo/cookie-banner) now has its own version
file, its own CHANGELOG.md, its own annotated-tag scheme of the form
<track>/v<version>, and its own GitHub Actions release workflow. The
unified release.yaml is removed; the unified CHANGELOG.md becomes a
short index pointing at each per-track file, with the prior history
preserved in CHANGELOG.archive.md.

Probod's CHANGELOG carries the post-split monorepo releases (0.174.0
through 0.181.0) so the server-group history stays continuous and the
probod docker image keeps its existing version line.

contrib/claude/release.md is split into contrib/claude/release/ with
one entrypoint per track plus a README that drives the agent: detect
which tracks have user-facing commits since their last tag and skip
tracks with no relevant changes, so a release request never tags an
unchanged track. The cookie-banner and n8n-node entrypoints add an
explicit npm run build step after the version bump (build.mjs bakes
package.json's version into __SDK_VERSION__) so compile errors and
package-lock.json updates are caught before tagging.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2026-05-05 16:03:46 +02:00
parent 5e55c888c4
commit ac526fb54d
25 changed files with 4599 additions and 3957 deletions

View File

@@ -0,0 +1,87 @@
name: "Release cookie-banner"
on:
push:
tags:
- "@probo/cookie-banner/v*"
permissions:
contents: "read"
jobs:
publish:
name: "publish"
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 ci"
- name: "Verify package.json version matches tag"
run: |
TAG_VERSION="${GITHUB_REF_NAME##*/v}"
PKG_VERSION="$(node -p "require('./packages/cookie-banner/package.json').version")"
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
echo "tag version ($TAG_VERSION) does not match package.json version ($PKG_VERSION)" >&2
exit 1
fi
- run: "npm --workspace @probo/cookie-banner run build"
- uses: "anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610" # v0.24.0
with:
path: ./packages/cookie-banner
format: cyclonedx-json
output-file: packages/cookie-banner/sbom.json
- uses: "anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2" # v7.4.0
with:
path: ./packages/cookie-banner
fail-build: true
severity-cutoff: critical
- name: "Generate checksums for dist files"
run: |
cd packages/cookie-banner/dist
find . -type f | while read file; do
echo "$(sha256sum "$file" | head -c 64) $file"
done > ../checksums.txt
- run: "npm --workspace @probo/cookie-banner publish --access public --dry-run"
- run: "npm --workspace @probo/cookie-banner publish --access public"
- uses: "actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e" # v4
with:
subject-path: "packages/cookie-banner/dist/**"
sbom-path: "packages/cookie-banner/sbom.json"
- uses: "actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32" # v4
with:
subject-path: "packages/cookie-banner/dist/**"
- 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 packages/cookie-banner/CHANGELOG.md \
$PRERELEASE_FLAG \
packages/cookie-banner/sbom.json packages/cookie-banner/checksums.txt
- uses: "actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f" # v7
with:
name: "cookie-banner-sbom"
path: |
packages/cookie-banner/sbom.json
packages/cookie-banner/checksums.txt
retention-days: 30

View File

@@ -0,0 +1,87 @@
name: "Release n8n node"
on:
push:
tags:
- "@probo/n8n-nodes-probo/v*"
permissions:
contents: "read"
jobs:
publish:
name: "publish"
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 ci"
- name: "Verify package.json version matches tag"
run: |
TAG_VERSION="${GITHUB_REF_NAME##*/v}"
PKG_VERSION="$(node -p "require('./packages/n8n-node/package.json').version")"
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
echo "tag version ($TAG_VERSION) does not match package.json version ($PKG_VERSION)" >&2
exit 1
fi
- run: "npm --workspace @probo/n8n-nodes-probo run build"
- 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"
run: |
cd packages/n8n-node/dist
find . -type f | while read file; do
echo "$(sha256sum "$file" | head -c 64) $file"
done > ../checksums.txt
- 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/**"
- 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 packages/n8n-node/CHANGELOG.md \
$PRERELEASE_FLAG \
packages/n8n-node/sbom.json packages/n8n-node/checksums.txt
- uses: "actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f" # v7
with:
name: "npm-sbom"
path: |
packages/n8n-node/sbom.json
packages/n8n-node/checksums.txt
retention-days: 30

245
.github/workflows/release-prb.yaml vendored Normal file
View File

@@ -0,0 +1,245 @@
name: "Release prb"
on:
push:
tags:
- "prb/v*"
permissions:
contents: "read"
jobs:
build-binary:
name: "binary (${{ matrix.goos }}/${{ matrix.goarch }})"
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"
- name: "Build binary"
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}'" \
-gcflags="-e" -o "dist/prb${EXT}" ./cmd/prb/main.go
- name: "Create archive"
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
PRB_DIR="prb_${OS}_${ARCH}"
mkdir -p "staging/${PRB_DIR}"
cp "dist/prb${EXT}" README.md LICENSE cmd/prb/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: "archive-${{ matrix.goos }}-${{ matrix.goarch }}"
path: "archives/"
retention-days: 1
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"
attestations: "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 SBOM"
uses: "anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610" # v0.24.0
with:
path: ./cmd/prb
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: "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 cmd/prb/CHANGELOG.md \
$PRERELEASE_FLAG \
archives/* sbom.json
- uses: "actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f" # v7
with:
name: "sbom"
path: "sbom.json"
retention-days: 30
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}"

View File

@@ -0,0 +1,149 @@
name: "Release probod-bootstrap"
on:
push:
tags:
- "probod-bootstrap/v*"
permissions:
contents: "read"
jobs:
build-binary:
name: "binary (${{ matrix.goos }}/${{ matrix.goarch }})"
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"
- name: "Build binary"
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}'" \
-gcflags="-e" -o "dist/probod-bootstrap${EXT}" ./cmd/probod-bootstrap/main.go
- name: "Create archive"
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
DIR="probod-bootstrap_${OS}_${ARCH}"
mkdir -p "staging/${DIR}"
cp "dist/probod-bootstrap${EXT}" README.md LICENSE cmd/probod-bootstrap/CHANGELOG.md "staging/${DIR}/"
if [ "$GOOS" = "windows" ]; then
(cd staging && zip -r "../archives/${DIR}.zip" "${DIR}")
else
tar -czf "archives/${DIR}.tar.gz" -C staging "${DIR}"
fi
- uses: "actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f" # v7
with:
name: "archive-${{ matrix.goos }}-${{ matrix.goarch }}"
path: "archives/"
retention-days: 1
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"
attestations: "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 SBOM"
uses: "anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610" # v0.24.0
with:
path: ./cmd/probod-bootstrap
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: "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 cmd/probod-bootstrap/CHANGELOG.md \
$PRERELEASE_FLAG \
archives/* sbom.json
- uses: "actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f" # v7
with:
name: "sbom"
path: "sbom.json"
retention-days: 30

340
.github/workflows/release-probod.yaml vendored Normal file
View File

@@ -0,0 +1,340 @@
name: "Release probod"
on:
push:
tags:
- "probod/v*"
permissions:
contents: "read"
jobs:
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-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}"
BOOTSTRAP_VERSION="$(cat cmd/probod-bootstrap/VERSION)"
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 -X 'main.version=${BOOTSTRAP_VERSION}'" \
-gcflags="-e" -o "dist/probod-bootstrap${EXT}" ./cmd/probod-bootstrap/main.go
- name: "Create archive"
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}" \
README.md LICENSE cmd/probod/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
- 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:
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:
username: "gearnode"
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- 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: "Compute image tag"
id: tag
run: |
VERSION="${GITHUB_REF_NAME##*/v}"
echo "image_tag=probod-v${VERSION}" >> "$GITHUB_OUTPUT"
- name: "Build and push Docker image"
env:
PLATFORM: ${{ matrix.platform }}
ARCH: ${{ matrix.arch }}
IMAGE_TAG: ${{ steps.tag.outputs.image_tag }}
run: |
docker buildx build \
--platform "${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:${IMAGE_TAG}-${ARCH}" \
--push \
.
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 }}
image_tag: ${{ steps.tag.outputs.image_tag }}
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: "Compute image tag"
id: tag
run: |
VERSION="${GITHUB_REF_NAME##*/v}"
echo "image_tag=probod-v${VERSION}" >> "$GITHUB_OUTPUT"
- name: "Create and push manifest"
env:
IMAGE_TAG: ${{ steps.tag.outputs.image_tag }}
run: |
docker buildx imagetools create \
--tag "ghcr.io/getprobo/probo:${IMAGE_TAG}" \
--tag "ghcr.io/getprobo/probo:latest" \
"ghcr.io/getprobo/probo:${IMAGE_TAG}-amd64" \
"ghcr.io/getprobo/probo:${IMAGE_TAG}-arm64"
- name: "Get manifest digest"
id: digest
env:
IMAGE_TAG: ${{ steps.tag.outputs.image_tag }}
run: |
DIGEST=$(docker buildx imagetools inspect "ghcr.io/getprobo/probo:${IMAGE_TAG}" --format '{{json .Manifest.Digest}}' | jq -r)
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"
- name: "Sign Docker manifest"
env:
DIGEST: ${{ steps.digest.outputs.digest }}
run: cosign sign "ghcr.io/getprobo/probo@${DIGEST}" --yes
github-release:
name: "github-release"
needs: [build-binary, docker-manifest]
runs-on: "runs-on=${{ github.run_id }}/runner=2cpu-linux-x64/extras=s3-cache"
permissions:
contents: "write"
id-token: "write"
attestations: "write"
security-events: "write"
steps:
- uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6
with:
fetch-depth: 0
submodules: recursive
- 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 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"
- name: "Trivy scan Docker image"
uses: "aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1" # 0.35.0
with:
image-ref: "ghcr.io/getprobo/probo:${{ needs.docker-manifest.outputs.image_tag }}"
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: "Compose release notes"
env:
IMAGE_TAG: ${{ needs.docker-manifest.outputs.image_tag }}
run: |
cp cmd/probod/CHANGELOG.md release-notes.md
cat >> release-notes.md << EOF
## Docker Images
- \`ghcr.io/getprobo/probo:${IMAGE_TAG}\` (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/* sbom.json
- uses: "actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f" # v7
with:
name: "sbom"
path: "sbom.json"
retention-days: 30

View File

@@ -1,602 +0,0 @@
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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # 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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7
with:
name: "binary-${{ matrix.goos }}-${{ matrix.goarch }}"
path: "dist/"
retention-days: 1
- uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # 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@4907a6ddec9925e35a0a9e82d7399ccc52663121" # v4.1.0
with:
username: "gearnode"
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- uses: "docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121" # v4.1.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@4907a6ddec9925e35a0a9e82d7399ccc52663121" # v4.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: "sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003" # v4.1.1
- 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@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003" # v4.1.1
- 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@4907a6ddec9925e35a0a9e82d7399ccc52663121" # v4.1.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@ed142fd0673e97e23eac54620cfb913e5ce36c25" # 0.36.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: "Print Trivy findings"
if: always()
run: |
jq -r '.runs[] | (.results // [])[] | .message.text' trivy-results.sarif
- 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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e" # 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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e" # 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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # 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

3043
CHANGELOG.archive.md Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -22,15 +22,21 @@ DOCKER_BUILD= DOCKER_BUILDKIT=1 $(DOCKER) build $(DOCKER_BUILD_FLAGS)
DOCKER_COMPOSE= $(DOCKER) compose -f compose.yaml $(DOCKER_COMPOSE_FLAGS) DOCKER_COMPOSE= $(DOCKER) compose -f compose.yaml $(DOCKER_COMPOSE_FLAGS)
VERSION= 0.181.0 PRB_VERSION= $(shell cat cmd/prb/VERSION)
LDFLAGS= -ldflags "-X 'main.version=$(VERSION)' -X 'main.env=prod'" PROBOD_VERSION= $(shell cat cmd/probod/VERSION)
PROBOD_BOOTSTRAP_VERSION=$(shell cat cmd/probod-bootstrap/VERSION)
PRB_LDFLAGS= -ldflags "-X 'main.version=$(PRB_VERSION)'"
PROBOD_LDFLAGS= -ldflags "-X 'main.version=$(PROBOD_VERSION)' -X 'main.env=prod'"
PROBOD_BOOTSTRAP_LDFLAGS=-ldflags "-X 'main.version=$(PROBOD_BOOTSTRAP_VERSION)'"
GCFLAGS= -gcflags="-e" GCFLAGS= -gcflags="-e"
CGO_ENABLED?= 0 CGO_ENABLED?= 0
GOOS?= GOOS?=
GO_BASE= CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) go GO_BASE= CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) go
GO_BUILD= $(GO_BASE) build $(LDFLAGS) $(GCFLAGS) GO_BUILD= $(GO_BASE) build $(GCFLAGS)
GO_GENERATE= $(GO_BASE) generate GO_GENERATE= $(GO_BASE) generate
GO_TEST= $(GO_BASE) tool gotestsum -- $(TEST_FLAGS) GO_TEST= $(GO_BASE) tool gotestsum -- $(TEST_FLAGS)
GO_VET= $(GO_BASE) vet GO_VET= $(GO_BASE) vet
@@ -44,7 +50,7 @@ E2E_COVER_DIR ?= $(CURDIR)/coverage/e2e
DOCKER_IMAGE_NAME= ghcr.io/getprobo/probo DOCKER_IMAGE_NAME= ghcr.io/getprobo/probo
DOCKER_TAG_NAME?= latest DOCKER_TAG_NAME?= latest
GENERATED= pkg/server/api/connect/v1/schema/schema.go \ PROBOD_BIN_DEPS= pkg/server/api/connect/v1/schema/schema.go \
pkg/server/api/connect/v1/types/types.go \ pkg/server/api/connect/v1/types/types.go \
pkg/server/api/console/v1/schema/schema.go \ pkg/server/api/console/v1/schema/schema.go \
pkg/server/api/console/v1/types/types.go \ pkg/server/api/console/v1/types/types.go \
@@ -52,8 +58,7 @@ GENERATED= pkg/server/api/connect/v1/schema/schema.go \
pkg/server/api/trust/v1/types/types.go \ pkg/server/api/trust/v1/types/types.go \
pkg/server/api/mcp/v1/server/server.go \ pkg/server/api/mcp/v1/server/server.go \
pkg/server/api/mcp/v1/types/types.go \ pkg/server/api/mcp/v1/types/types.go \
apps/console/dist/index.html \
EMBEDDED= apps/console/dist/index.html \
apps/trust/dist/index.html \ apps/trust/dist/index.html \
@probo/emails @probo/emails
@@ -67,9 +72,8 @@ PRB_SRC= cmd/prb/main.go
PROBOD_BOOTSTRAP_BIN= bin/probod-bootstrap PROBOD_BOOTSTRAP_BIN= bin/probod-bootstrap
PROBOD_BOOTSTRAP_SRC= cmd/probod-bootstrap/main.go PROBOD_BOOTSTRAP_SRC= cmd/probod-bootstrap/main.go
ifdef WITH_APPS ifndef SKIP_APPS
GENERATED += relay PROBOD_BIN_EXTRA_DEPS += \
EMBEDDED += \
@probo/console \ @probo/console \
@probo/trust @probo/trust
endif endif
@@ -87,7 +91,7 @@ lint-go: vet go-fmt go-fix go-lint
lint-js: npm-lint lint-js: npm-lint
.PHONY: vet .PHONY: vet
vet: generate embed vet: generate apps/console/dist/index.html apps/trust/dist/index.html @probo/emails
$(GO_VET) ./... $(GO_VET) ./...
.PHONY: npm-lint .PHONY: npm-lint
@@ -104,7 +108,7 @@ go-fmt:
fi fi
.PHONY: go-fix .PHONY: go-fix
go-fix: generate embed go-fix: generate apps/console/dist/index.html apps/trust/dist/index.html @probo/emails
@output="$$($(GO_BASE) fix -diff -omitzero=false ./apps/... ./cmd/... ./packages/... ./pkg/... ./e2e/...)"; \ @output="$$($(GO_BASE) fix -diff -omitzero=false ./apps/... ./cmd/... ./packages/... ./pkg/... ./e2e/...)"; \
if [ -n "$$output" ]; then \ if [ -n "$$output" ]; then \
echo "error: 'go fix' suggests changes; please apply them"; \ echo "error: 'go fix' suggests changes; please apply them"; \
@@ -147,7 +151,7 @@ test-e2e: $(PROBOD_BIN) ## Run console e2e tests
GOTESTSUM_FORMAT=testname $(GO_TEST) -count=1 ./e2e/console/... GOTESTSUM_FORMAT=testname $(GO_TEST) -count=1 ./e2e/console/...
bin/probod-coverage: bin/probod-coverage:
CGO_ENABLED=0 $(GO_BUILD) -cover -o $@ $(PROBOD_SRC) CGO_ENABLED=0 $(GO_BUILD) $(PROBOD_LDFLAGS) -cover -o $@ $(PROBOD_SRC)
.PHONY: test-e2e-coverage .PHONY: test-e2e-coverage
test-e2e-coverage: bin/probod-coverage ## Run e2e tests with coverage test-e2e-coverage: bin/probod-coverage ## Run e2e tests with coverage
@@ -208,7 +212,7 @@ sbom-docker: docker-build
sbom: sbom:
$(SYFT) dir:. -o cyclonedx-json \ $(SYFT) dir:. -o cyclonedx-json \
--source-name "probo" \ --source-name "probo" \
--source-version "$(VERSION)" \ --source-version "$(PROBOD_VERSION)" \
> sbom.json > sbom.json
.PHONY: scan-sbom .PHONY: scan-sbom
@@ -235,16 +239,16 @@ docker-build:
$(DOCKER_BUILD) --tag $(DOCKER_IMAGE_NAME):$(DOCKER_TAG_NAME) --file Dockerfile . $(DOCKER_BUILD) --tag $(DOCKER_IMAGE_NAME):$(DOCKER_TAG_NAME) --file Dockerfile .
.PHONY: $(PROBOD_BIN) .PHONY: $(PROBOD_BIN)
$(PROBOD_BIN): generate embed $(PROBOD_BIN): $(PROBOD_BIN_DEPS) $(PROBOD_BIN_EXTRA_DEPS)
$(GO_BUILD) -o $(PROBOD_BIN) $(PROBOD_SRC) $(GO_BUILD) $(PROBOD_LDFLAGS) -o $(PROBOD_BIN) $(PROBOD_SRC)
.PHONY: bin/prb .PHONY: bin/prb
bin/prb: bin/prb:
$(GO_BUILD) -o $(PRB_BIN) $(PRB_SRC) $(GO_BUILD) $(PRB_LDFLAGS) -o $(PRB_BIN) $(PRB_SRC)
.PHONY: $(PROBOD_BOOTSTRAP_BIN) .PHONY: bin/probod-bootstrap
$(PROBOD_BOOTSTRAP_BIN): bin/probod-bootstrap:
$(GO_BUILD) -o $(PROBOD_BOOTSTRAP_BIN) $(PROBOD_BOOTSTRAP_SRC) $(GO_BUILD) $(PROBOD_BOOTSTRAP_LDFLAGS) -o $(PROBOD_BOOTSTRAP_BIN) $(PROBOD_BOOTSTRAP_SRC)
.PHONY: @probo/emails .PHONY: @probo/emails
@probo/emails: @probo/emails:
@@ -287,10 +291,14 @@ pkg/server/api/trust/v1/schema.graphql: pkg/server/api/trust/v1/graphql $(TRUST_
$(NPM) --workspace $@ run build $(NPM) --workspace $@ run build
.PHONY: generate .PHONY: generate
generate: $(GENERATED) generate: pkg/server/api/connect/v1/schema/schema.go \
pkg/server/api/connect/v1/types/types.go \
.PHONY: embed pkg/server/api/console/v1/schema/schema.go \
embed: $(EMBEDDED) pkg/server/api/console/v1/types/types.go \
pkg/server/api/trust/v1/schema/schema.go \
pkg/server/api/trust/v1/types/types.go \
pkg/server/api/mcp/v1/server/server.go \
pkg/server/api/mcp/v1/types/types.go
pkg/server/api/connect/v1/schema/schema.go \ pkg/server/api/connect/v1/schema/schema.go \
pkg/server/api/connect/v1/types/types.go: pkg/server/api/connect/v1/gqlgen.yaml pkg/server/api/connect/v1/graphql $(CONNECT_GQL) pkg/server/api/connect/v1/types/types.go: pkg/server/api/connect/v1/gqlgen.yaml pkg/server/api/connect/v1/graphql $(CONNECT_GQL)
@@ -390,10 +398,6 @@ sandbox-create: ## Create a Lima sandbox VM for this worktree
sandbox-start: ## Start the Lima sandbox VM sandbox-start: ## Start the Lima sandbox VM
./contrib/lima/sandbox.sh start ./contrib/lima/sandbox.sh start
.PHONY: sandbox-boot-logs
sandbox-boot-logs: ## Show the Lima sandbox VM boot logs
./contrib/lima/sandbox.sh boot-logs
.PHONY: sandbox-stop .PHONY: sandbox-stop
sandbox-stop: ## Stop (hibernate) the Lima sandbox VM sandbox-stop: ## Stop (hibernate) the Lima sandbox VM
./contrib/lima/sandbox.sh stop ./contrib/lima/sandbox.sh stop

11
cmd/prb/CHANGELOG.md Normal file
View File

@@ -0,0 +1,11 @@
# Changelog
All notable changes to the `prb` CLI will be documented in this file.
## Unreleased
## [0.173.0] - 2026-04-27
### Changed
- First per-package release. Prior history is in the archived monorepo [CHANGELOG.archive.md](../../CHANGELOG.archive.md).

1
cmd/prb/VERSION Normal file
View File

@@ -0,0 +1 @@
0.173.0

View File

@@ -0,0 +1,11 @@
# Changelog
All notable changes to `probod-bootstrap` will be documented in this file.
## Unreleased
## [0.1.0] - 2026-04-27
### Added
- First independent release. Generates a `probod` configuration file from environment variables. Previously shipped without a version string and bundled with the monorepo `vX.Y.Z` tag.

View File

@@ -0,0 +1 @@
0.1.0

View File

@@ -23,10 +23,20 @@ import (
"go.probo.inc/probo/pkg/bootstrap" "go.probo.inc/probo/pkg/bootstrap"
) )
var (
version string = "unknown"
)
func main() { func main() {
outputPath := flag.String("output", "/etc/probod/config.yml", "output path for the generated config file") outputPath := flag.String("output", "/etc/probod/config.yml", "output path for the generated config file")
showVersion := flag.Bool("version", false, "print version and exit")
flag.Parse() flag.Parse()
if *showVersion {
fmt.Println(version)
return
}
builder := bootstrap.NewBuilder(nil) builder := bootstrap.NewBuilder(nil)
cfg, err := builder.Build() cfg, err := builder.Build()

152
cmd/probod/CHANGELOG.md Normal file
View File

@@ -0,0 +1,152 @@
# Changelog
All notable changes to `probod` (the server, including the bundled `@probo/console`, `@probo/trust`, and `@probo/ui` frontends) will be documented in this file.
## Unreleased
## [0.181.0] - 2026-05-05
### Added
- Add SCIM tools to MCP API
- Add SCIM commands to CLI
- Add cookie banner detection page for uncategorised patterns
- Add `last_detected_at` and `last_matched_at` tracking on cookie patterns
- Add `uncategorisedPatterns` GraphQL connection on `CookieBanner`
### Changed
- Accept CIDR ranges in proxy `trusted-proxies` configuration
- Rename `categories` to `consentCategories` on cookie banner API surfaces
- Move cookie management from separate Cookies tab into the Display page
- Filter uncategorised category from cookie banner config and version snapshots
## [0.180.0] - 2026-05-04
### Fixed
- Use natural sort for SOA document export rows
### Added
- Add risk publish to document system
## [0.179.1] - 2026-05-02
### Fixed
- Fix n8n cookieConsentRecord getAll operation
## [0.179.0] - 2026-05-02
### Added
- Add cookie banner operations to n8n node
- Add `excluded` flag to cookie patterns (GraphQL/MCP/CLI/n8n) with source badge in category table
- Validate cookie policy link in banner description
### Changed
- Skip draft cookie banner version for uncategorised-only merges
- Exclude uncategorised category from consent contract
- Run cookie detection regardless of banner state
- Stop bumping cookie banner version on no-op updates
- Exclude translations from cookie banner version snapshots
- Allow clearing optional fields in n8n cookie updates
- Bump `@probo/cookie-banner` to 0.2.0
### Fixed
- Clear pending cookie-consent queue before stopping on 404
## [0.178.0] - 2026-05-01
### Added
- Add MCP tools for cookie banner, category, pattern, version, and consent records
- Add CLI commands for cookie banner, category, pattern, and consent records
### Fixed
- Fix auditor access to processing activities
- Fix contract end date field cut off in Add Person dialog
## [0.177.1] - 2026-04-30
### Fixed
- Reveal cookie banner sidebar entry in IAM organizations
- Render cookie-consent placeholders when no prior consent exists
- Fix cookie-consent placeholder sizing for absolutely or sticky positioned elements
- Allow OIDC and magic-link sessions to assume password-only organizations
## [0.177.0] - 2026-04-30
### Added
- Add cookie patterns to group detected cookies by URL prefix, with auto-detection worker and console management
- Add `DurationInput` component to `@probo/ui`
### Changed
- Refactor cookie banner forms to react-hook-form
- Store cookie durations as `max_age_seconds`
- Update `@probo/cookie-banner` public exports and bump to 0.1.0
### Fixed
- Filter browser-extension cookies from detection
## [0.176.1] - 2026-04-29
### Fixed
- Fix empty text nodes in generated documents
## [0.176.0] - 2026-04-29
### Added
- Add vendor publish to document system, replacing snapshot mode
## [0.175.0] - 2026-04-29
### Added
- Add processing activity, DPIA and TIA publish to document system, replacing snapshot mode
### Changed
- Introspect OAuth2 refresh tokens per RFC 7662, honoring `token_type_hint`
- Invalidate other sessions on password change and all sessions on password reset
- Use forwarded headers for SCIM event client IP when running behind a load balancer
- Extract client IP from rightmost entry of `X-Forwarded-For` and `Forwarded` headers
- Update avatar initials colors
## [0.174.0] - 2026-04-28
### Added
- Add agent run supervisor with checkpoint persistence and resume across restarts
- Add finding and obligation publish to document system, replacing snapshot mode
- Add `--state` and `--contract-ended` filters to CLI/MCP/GraphQL user list
- Add Notion workspace name resolver for access review
- Add `X-SDK-Version` header to cookie banner SDK requests
### Changed
- Rename `excludeContractEnded` to `contractEnded` (two-way) across MCP, GraphQL, CLI, frontend
- Remove auditor's ability to publish SoA
- Request Google customer directory scope for access-review name sync
### Fixed
- Fix copy-paste in rich editor
- Fix long cookie name display and label colors in cookie banner
- Fix suspension checkpoint fallback in nested and parallel agent execution
## [0.173.0] - 2026-04-27
### Changed
- First per-package release. Prior history is in the archived monorepo [CHANGELOG.archive.md](../../CHANGELOG.archive.md).

1
cmd/probod/VERSION Normal file
View File

@@ -0,0 +1 @@
0.181.0

View File

@@ -1,149 +0,0 @@
# Release
This guide describes how to cut a new release. The outcome is a single
commit on `main` plus a Git tag; CI handles everything else (binaries,
Docker images, npm packages, signatures).
## Steps
### 1. Pull the latest main
Ensure you are on `main` and have the latest changes before starting:
```shell
git checkout main && git pull origin main
```
### 2. List changes since the last release
Find the latest tag and review every commit since then:
```shell
git log $(git describe --tags --abbrev=0)..HEAD --oneline
```
### 3. Write the changelog entry
Create a new version section in `CHANGELOG.md` from those commits.
Keep the empty `## Unreleased` heading above it.
**Categorize** entries under Keep-a-Changelog sections:
| Section | Use for |
|---------------|------------------------------------------------|
| `### Added` | New features, new commands, new endpoints |
| `### Changed` | Behavioral changes, refactors visible to users |
| `### Fixed` | Bug fixes |
| `### Removed` | Removed features or deprecated code |
**Skip** commits that are not user-facing:
- Style / formatting (`Style`, `Run go fmt/fix`)
- CI-only changes (`Add reviewdog`, `Cache Go modules`)
- Internal refactors (`Move X to contrib/claude`, `Remove deadcode`)
- Documentation-only changes
- Release commits (`Release v…`)
**Only list fixes for pre-existing bugs.** If a "fix" commit repairs something
introduced by another commit in the same release cycle, do NOT list it as a
separate fix. To verify, check whether the affected file or feature existed
at the previous tag:
```shell
git ls-tree <previous-tag> -- path/to/file
```
If the file did not exist at the previous tag, the fix is part of the new
feature and should not appear in `### Fixed`.
**Escape underscores** — wrap identifiers containing underscores in
backticks (e.g., `` `probo_consent` ``) so they are not rendered as
italic in Markdown.
**Summarize** related commits into a single line when appropriate.
For example a series of `Add proboctl X commands` commits becomes
`Add CLI`.
Format: `## [X.Y.Z] - YYYY-MM-DD` (today's date).
Example result:
```markdown
## Unreleased
## [0.144.0] - 2026-03-17
### Added
- Add document viewer with 404 handling for trust center
## [0.143.0] - 2026-03-16
```
### 4. Decide the version bump
The project is in the **0.x** series. Never bump MAJOR.
- Bug fixes only → bump **PATCH**
- New features or non-breaking changes → bump **MINOR**
### 5. Bump version in `GNUmakefile`
Update the `VERSION` variable at the top of `GNUmakefile`:
```makefile
VERSION= 0.144.0
```
### 6. Review with the user
Before committing, show the user the full `CHANGELOG.md` entry and
the new `VERSION` value. Ask them to confirm everything looks good.
Only proceed once they approve.
### 7. Create the release commit
Stage only `CHANGELOG.md` and `GNUmakefile`. The commit message
**must** follow this exact format:
```
Release v<VERSION>
```
No body is needed.
### 8. Create the tag
Tag the release commit with an **annotated** tag. The tag **must**
match `v<VERSION>`:
```shell
git tag -a v<VERSION> -m "v<VERSION>"
```
### 9. Push
Push both the commit and the tag:
```shell
git push origin main --follow-tags
```
CI (`.github/workflows/release.yaml`) triggers on `v*` tags and takes
care of:
- Building binaries via GoReleaser (probod, probod-bootstrap, prb)
- Publishing multi-arch Docker images to `ghcr.io/getprobo/probo`
- Publishing the npm package `@probo/n8n-nodes-probo`
- Generating SBOMs, attestations, and Cosign signatures
## Checklist
1. [ ] Pulled latest `main`
2. [ ] Reviewed commits since last tag
3. [ ] `CHANGELOG.md` — new version section with categorized entries
4. [ ] `GNUmakefile` — `VERSION` bumped
5. [ ] User confirmed changelog and version look good
6. [ ] Commit message is `Release v<VERSION>`
7. [ ] Annotated tag `v<VERSION>` on the release commit
8. [ ] Push commit and tag

View File

@@ -0,0 +1,127 @@
# Release
The repository ships five independently-versioned tracks. Each has its own
version source, its own `CHANGELOG.md`, its own tag pattern, and its own
release workflow. Cutting a release means: bump the version, write a
changelog entry, commit, tag, push.
| Track | Tag pattern | Entrypoint |
| ----------------------- | ------------------------------ | -------------------------------- |
| CLI (`prb`) | `prb/v*` | [prb.md](./prb.md) |
| Server (`probod` group) | `probod/v*` | [probod.md](./probod.md) |
| `probod-bootstrap` | `probod-bootstrap/v*` | [probod-bootstrap.md](./probod-bootstrap.md) |
| `@probo/n8n-nodes-probo` | `@probo/n8n-nodes-probo/v*` | [n8n-nodes-probo.md](./n8n-nodes-probo.md) |
| `@probo/cookie-banner` | `@probo/cookie-banner/v*` | [cookie-banner.md](./cookie-banner.md) |
When the user asks for a release **without specifying a track**, follow
[Step 1](#1-decide-which-tracks-to-release) below to detect which tracks
have user-facing changes since their last tag, then ask the user which of
those tracks to release. **Only release tracks that actually have
user-facing changes.** Never release a track that has no commits since its
last tag.
When the user asks for a release **for a specific track** (e.g. "release
the CLI", "release probod"), open the corresponding entrypoint above and
follow it.
Versions are SemVer in the **0.x** series. Never bump MAJOR.
Bug fixes only -> bump PATCH; new features or non-breaking changes -> bump
MINOR.
## 1. Decide which tracks to release
Before any release, identify which tracks have user-facing commits since
their last tag. A track with zero commits, or only non-user-facing
commits (style, CI, internal refactors, doc-only, release commits) must
**not** be released.
Run this from a clean `main`:
```shell
git checkout main && git pull origin main
```
Then for each track, list commits since its last tag, scoped to that
track's paths:
```shell
# prb
git log $(git describe --tags --abbrev=0 --match='prb/v*')..HEAD --oneline \
-- cmd/prb pkg/cli pkg/cmd
# probod (server group: probod + console + trust + ui)
git log $(git describe --tags --abbrev=0 --match='probod/v*')..HEAD --oneline \
-- cmd/probod apps/console apps/trust packages/ui pkg
# probod-bootstrap
git log $(git describe --tags --abbrev=0 --match='probod-bootstrap/v*')..HEAD --oneline \
-- cmd/probod-bootstrap
# @probo/n8n-nodes-probo
git log $(git describe --tags --abbrev=0 --match='@probo/n8n-nodes-probo/v*')..HEAD --oneline \
-- packages/n8n-node
# @probo/cookie-banner
git log $(git describe --tags --abbrev=0 --match='@probo/cookie-banner/v*')..HEAD --oneline \
-- packages/cookie-banner
```
If a track returns no commits, skip it. If all commits for a track are
non-user-facing, skip it (and tell the user). For each remaining track,
proceed with its entrypoint.
## 2. Writing a changelog entry
Categorize entries under Keep-a-Changelog sections in the relevant track's
`CHANGELOG.md`:
| Section | Use for |
| ------------- | ---------------------------------------------- |
| `### Added` | New features, new commands, new endpoints |
| `### Changed` | Behavioral changes, refactors visible to users |
| `### Fixed` | Bug fixes |
| `### Removed` | Removed features or deprecated code |
**Skip** non-user-facing commits (style/formatting, CI-only, internal
refactors, doc-only, release commits).
**Only list fixes for pre-existing bugs.** If a "fix" commit repairs
something introduced earlier in the same release cycle, do NOT list it as
a separate fix.
**Summarize** related commits into a single line when appropriate.
Format: `## [X.Y.Z] - YYYY-MM-DD` (today's date). Always keep an
`## Unreleased` heading above the latest version.
## 3. Common steps (every track)
After choosing the track and reviewing its commits:
1. Bump the version in the track's source of truth (see the per-track
entrypoint).
2. Write the changelog entry in the track's `CHANGELOG.md`.
3. For npm tracks, run the workspace `build` script after the version
bump (see the per-track entrypoint for why).
4. Show the user the proposed `CHANGELOG.md` diff and the new version.
Wait for confirmation.
5. Commit only the files modified by the version bump and changelog
edit. Subject: `Release <pkg>/v<version>`. No body.
6. Annotated tag: `git tag -a <pkg>/v<version> -m "<pkg>/v<version>"`.
7. Push: `git push origin main --follow-tags`.
CI handles the rest: binary builds, npm publish, Docker image, Homebrew
formula, SBOMs, attestations, GitHub Release.
## Checklist (every track)
1. [ ] Pulled latest `main`
2. [ ] Confirmed the track has user-facing commits since its last tag
3. [ ] Reviewed track-specific commits
4. [ ] Track CHANGELOG entry written, categorized, summarized
5. [ ] Version bumped in the track's source of truth
6. [ ] (npm tracks) Workspace `build` script run successfully after bump
7. [ ] User confirmed changelog and version
8. [ ] Commit message is `Release <pkg>/v<version>`
9. [ ] Annotated tag `<pkg>/v<version>` on the release commit
10. [ ] Pushed commit and tag

View File

@@ -0,0 +1,73 @@
# Release `@probo/cookie-banner`
Entrypoint for releasing the cookie banner SDK. Read
[README.md](./README.md) first for overall flow, changelog rules, and the
non-empty-track guarantee.
## Track facts
- **Tag pattern**: `@probo/cookie-banner/v*`
- **Version source**: `packages/cookie-banner/package.json`
- **Changelog**: `packages/cookie-banner/CHANGELOG.md`
- **Workflow**: `.github/workflows/release-npm-cookie-banner.yaml`
- **Path filter** (for log/scoping): `packages/cookie-banner`
## Important: build script bakes the version
`packages/cookie-banner/build.mjs` reads `version` from `package.json`
and exposes it to the bundle as the `__SDK_VERSION__` define. The SDK
uses this value at runtime (e.g. when calling the Probo REST API), so
the build **must** run after the version bump to make sure the new
version is what gets published. The release CI workflow does run the
build, but we still run it locally as part of the release commit so:
- compile errors are caught before tagging,
- any tracked side-effects (`package-lock.json`, etc.) are part of the
same `Release @probo/cookie-banner/v<version>` commit.
## Steps
1. From a clean `main`, list commits since the last
`@probo/cookie-banner` tag:
```shell
git log $(git describe --tags --abbrev=0 --match='@probo/cookie-banner/v*')..HEAD --oneline \
-- packages/cookie-banner
```
If the list is empty (or contains only non-user-facing commits), do
not release this track.
2. Decide the version bump (PATCH for fixes, MINOR for features).
3. Bump the version using npm so `package.json` and `package-lock.json`
stay consistent:
```shell
npm --workspace @probo/cookie-banner version <X.Y.Z> --no-git-tag-version
```
4. Run the workspace build so `__SDK_VERSION__` is rebuilt from the new
`package.json` and any compile error surfaces before we tag:
```shell
npm --workspace @probo/cookie-banner run build
```
`dist/` is gitignored, so this step does not produce checked-in build
artifacts — but it must succeed for the release to be valid.
5. Write the new entry in `packages/cookie-banner/CHANGELOG.md` following
the rules in [README.md](./README.md#2-writing-a-changelog-entry).
6. Show the user the changelog diff and the new version. Wait for
confirmation.
7. Stage the files modified by the version bump and changelog edit
(typically `packages/cookie-banner/package.json`,
`packages/cookie-banner/CHANGELOG.md`, and `package-lock.json`).
Commit subject: `Release @probo/cookie-banner/v<version>`. No body.
8. Annotated tag:
`git tag -a @probo/cookie-banner/v<version> -m "@probo/cookie-banner/v<version>"`.
9. Push: `git push origin main --follow-tags`.
CI workflow `release-npm-cookie-banner.yaml` verifies the tag matches
`package.json`, runs the build again, publishes to npm with provenance +
SBOM, and creates a GitHub Release.

View File

@@ -0,0 +1,58 @@
# Release `@probo/n8n-nodes-probo`
Entrypoint for releasing the n8n nodes package. Read
[README.md](./README.md) first for overall flow, changelog rules, and the
non-empty-track guarantee.
## Track facts
- **Tag pattern**: `@probo/n8n-nodes-probo/v*` (the `@` and `/` are valid
in Git tag refs)
- **Version source**: `packages/n8n-node/package.json`
- **Changelog**: `packages/n8n-node/CHANGELOG.md`
- **Workflow**: `.github/workflows/release-npm-n8n-node.yaml`
- **Path filter** (for log/scoping): `packages/n8n-node`
## Steps
1. From a clean `main`, list commits since the last
`@probo/n8n-nodes-probo` tag:
```shell
git log $(git describe --tags --abbrev=0 --match='@probo/n8n-nodes-probo/v*')..HEAD --oneline \
-- packages/n8n-node
```
If the list is empty (or contains only non-user-facing commits), do
not release this track.
2. Decide the version bump (PATCH for fixes, MINOR for features).
3. Bump the version using npm so `package.json` and `package-lock.json`
stay consistent:
```shell
npm --workspace @probo/n8n-nodes-probo version <X.Y.Z> --no-git-tag-version
```
4. Run the workspace build to confirm it succeeds with the new version
(and to surface any compile errors before we tag):
```shell
npm --workspace @probo/n8n-nodes-probo run build
```
5. Write the new entry in `packages/n8n-node/CHANGELOG.md` following the
rules in [README.md](./README.md#2-writing-a-changelog-entry).
6. Show the user the changelog diff and the new version. Wait for
confirmation.
7. Stage the files modified by the version bump and changelog edit
(typically `packages/n8n-node/package.json`,
`packages/n8n-node/CHANGELOG.md`, and `package-lock.json`). Commit
subject: `Release @probo/n8n-nodes-probo/v<version>`. No body.
8. Annotated tag:
`git tag -a @probo/n8n-nodes-probo/v<version> -m "@probo/n8n-nodes-probo/v<version>"`.
9. Push: `git push origin main --follow-tags`.
CI workflow `release-npm-n8n-node.yaml` verifies the tag matches
`package.json`, publishes to npm with provenance + SBOM, and creates a
GitHub Release.

View File

@@ -0,0 +1,42 @@
# Release `prb` (CLI)
Entrypoint for releasing the `prb` CLI. Read [README.md](./README.md)
first for overall flow, changelog rules, and the
non-empty-track guarantee.
## Track facts
- **Tag pattern**: `prb/v*`
- **Version source**: `cmd/prb/VERSION` (contains only `X.Y.Z`)
- **Changelog**: `cmd/prb/CHANGELOG.md`
- **Workflow**: `.github/workflows/release-prb.yaml`
- **Path filter** (for log/scoping): `cmd/prb pkg/cli pkg/cmd`
## Steps
1. From a clean `main`, list commits since the last `prb` tag:
```shell
git log $(git describe --tags --abbrev=0 --match='prb/v*')..HEAD --oneline \
-- cmd/prb pkg/cli pkg/cmd
```
If the list is empty (or contains only non-user-facing commits), do
not release this track.
2. Decide the version bump (PATCH for fixes, MINOR for features).
3. Bump the version in `cmd/prb/VERSION` (the file contains a single
`X.Y.Z` line — no trailing newline conventions beyond what is already
there).
4. Write the new entry in `cmd/prb/CHANGELOG.md` following the rules in
[README.md](./README.md#2-writing-a-changelog-entry).
5. Show the user the changelog diff and the new version. Wait for
confirmation.
6. Stage only `cmd/prb/VERSION` and `cmd/prb/CHANGELOG.md`. Commit
subject: `Release prb/v<version>`. No body.
7. Annotated tag: `git tag -a prb/v<version> -m "prb/v<version>"`.
8. Push: `git push origin main --follow-tags`.
CI workflow `release-prb.yaml` builds binaries for 9 OS/arch targets,
publishes a GitHub Release, and updates the Homebrew formula at
`getprobo/homebrew-tap`.

View File

@@ -0,0 +1,44 @@
# Release `probod-bootstrap`
Entrypoint for releasing `probod-bootstrap`. Read [README.md](./README.md)
first for overall flow, changelog rules, and the non-empty-track
guarantee.
## Track facts
- **Tag pattern**: `probod-bootstrap/v*`
- **Version source**: `cmd/probod-bootstrap/VERSION` (contains only `X.Y.Z`)
- **Changelog**: `cmd/probod-bootstrap/CHANGELOG.md`
- **Workflow**: `.github/workflows/release-probod-bootstrap.yaml`
- **Path filter** (for log/scoping): `cmd/probod-bootstrap`
## Steps
1. From a clean `main`, list commits since the last `probod-bootstrap`
tag:
```shell
git log $(git describe --tags --abbrev=0 --match='probod-bootstrap/v*')..HEAD --oneline \
-- cmd/probod-bootstrap
```
If the list is empty (or contains only non-user-facing commits), do
not release this track.
2. Decide the version bump (PATCH for fixes, MINOR for features).
3. Bump the version in `cmd/probod-bootstrap/VERSION`.
4. Write the new entry in `cmd/probod-bootstrap/CHANGELOG.md` following
the rules in [README.md](./README.md#2-writing-a-changelog-entry).
5. Show the user the changelog diff and the new version. Wait for
confirmation.
6. Stage only `cmd/probod-bootstrap/VERSION` and
`cmd/probod-bootstrap/CHANGELOG.md`. Commit subject:
`Release probod-bootstrap/v<version>`. No body.
7. Annotated tag:
`git tag -a probod-bootstrap/v<version> -m "probod-bootstrap/v<version>"`.
8. Push: `git push origin main --follow-tags`.
CI workflow `release-probod-bootstrap.yaml` builds binaries for 9 OS/arch
targets and publishes a GitHub Release. Note: the same binary, built
from the tagged ref, is also bundled into the probod Docker image when
`probod/v*` runs.

View File

@@ -0,0 +1,48 @@
# Release `probod` (server group)
Entrypoint for releasing the `probod` server group. Read
[README.md](./README.md) first for overall flow, changelog rules, and the
non-empty-track guarantee.
This track ships `probod`, `@probo/console`, `@probo/trust`, and
`@probo/ui` together as the Docker image and accompanying binary archive.
They share the same version.
## Track facts
- **Tag pattern**: `probod/v*`
- **Version source**: `cmd/probod/VERSION` (contains only `X.Y.Z`)
- **Changelog**: `cmd/probod/CHANGELOG.md` (covers all four components)
- **Workflow**: `.github/workflows/release-probod.yaml`
- **Path filter** (for log/scoping):
`cmd/probod apps/console apps/trust packages/ui pkg`
## Steps
1. From a clean `main`, list commits since the last `probod` tag:
```shell
git log $(git describe --tags --abbrev=0 --match='probod/v*')..HEAD --oneline \
-- cmd/probod apps/console apps/trust packages/ui pkg
```
If the list is empty (or contains only non-user-facing commits), do
not release this track.
2. Decide the version bump (PATCH for fixes, MINOR for features).
3. Bump the version in `cmd/probod/VERSION`.
4. Write the new entry in `cmd/probod/CHANGELOG.md` covering changes
across `probod`, `@probo/console`, `@probo/trust`, and `@probo/ui`.
Follow the rules in
[README.md](./README.md#2-writing-a-changelog-entry).
5. Show the user the changelog diff and the new version. Wait for
confirmation.
6. Stage only `cmd/probod/VERSION` and `cmd/probod/CHANGELOG.md`.
Commit subject: `Release probod/v<version>`. No body.
7. Annotated tag: `git tag -a probod/v<version> -m "probod/v<version>"`.
8. Push: `git push origin main --follow-tags`.
CI workflow `release-probod.yaml` builds the frontends, builds the Go
binaries, builds and pushes the multi-arch image to
`ghcr.io/getprobo/probo:probod-v<version>` (and `:latest`), runs Trivy +
cosign + attestations, and publishes the GitHub Release.

View File

@@ -0,0 +1,11 @@
# Changelog
All notable changes to the `@probo/cookie-banner` SDK will be documented in this file.
## Unreleased
## [0.0.0] - 2026-04-27
### Added
- Initial scaffold of the cookie banner SDK with web components, headless and themed entrypoints, settings link element, Google Consent Mode v2 integration, PostHog consent plugin, Global Privacy Control (GPC) support, internationalization with default translations for English, French, German, and Spanish, and graceful config fetch failure handling.

View File

@@ -0,0 +1,11 @@
# Changelog
All notable changes to the `@probo/n8n-nodes-probo` package will be documented in this file.
## Unreleased
## [0.0.1] - 2026-04-27
### Changed
- First per-package release. Prior history is in the archived monorepo [CHANGELOG.archive.md](../../CHANGELOG.archive.md).