Files
probo/.github/workflows/release-probod.yaml
Bryan Frimin e83f9e3a2e Update build targets for compliance portal app
Add the complianceportal Go embed target, wire it into CI and
release workflows, and document the new build entry point.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-21 15:44:15 +02:00

370 lines
14 KiB
YAML

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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v6
with:
submodules: recursive
- uses: "runs-on/action@d141ef83eb66d096ce8afc767e09115a65c63b60" # 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 compliance-portal"
run: |
npm --workspace @probo/compliance-portal run check
NODE_ENV=production npm --workspace @probo/compliance-portal run build
- uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7
with:
name: "frontend-apps"
path: |
apps/console/dist/
apps/compliance-portal/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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v6
with:
submodules: recursive
- uses: "runs-on/action@d141ef83eb66d096ce8afc767e09115a65c63b60" # 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/complianceportal/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@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:
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v6
- uses: "runs-on/action@d141ef83eb66d096ce8afc767e09115a65c63b60" # v2
- uses: "docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5" # v4.1.0
- uses: "docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee" # v4.2.0
with:
registry: artifact.probo.inc
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
- 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=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}" \
--build-arg "BASE_IMAGE=artifact.probo.inc/dockerhub/library/ubuntu@sha256:c4a8d5503dfb2a3eb8ab5f807da5bc69a85730fb49b5cfca2330194ebcc41c7b" \
--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 "artifact.probo.inc/probo/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@d141ef83eb66d096ce8afc767e09115a65c63b60" # v2
- uses: "docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5" # v4.1.0
- uses: "docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee" # v4.2.0
with:
registry: artifact.probo.inc
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
- uses: "sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6" # v4.1.2
- name: "Log in to Harbor with cosign"
env:
HARBOR_USERNAME: ${{ secrets.HARBOR_USERNAME }}
HARBOR_PASSWORD: ${{ secrets.HARBOR_PASSWORD }}
run: |
echo "${HARBOR_PASSWORD}" | cosign login artifact.probo.inc \
--username "${HARBOR_USERNAME}" \
--password-stdin
- name: "Compute image tag"
id: tag
run: |
VERSION="${GITHUB_REF_NAME##*/v}"
echo "image_tag=v${VERSION}" >> "$GITHUB_OUTPUT"
- name: "Create and push manifest"
env:
IMAGE_TAG: ${{ steps.tag.outputs.image_tag }}
run: |
docker buildx imagetools create \
--tag "artifact.probo.inc/probo/probo:${IMAGE_TAG}" \
--tag "artifact.probo.inc/probo/probo:latest" \
"artifact.probo.inc/probo/probo:${IMAGE_TAG}-amd64" \
"artifact.probo.inc/probo/probo:${IMAGE_TAG}-arm64"
- name: "Get manifest digest"
id: digest
env:
IMAGE_TAG: ${{ steps.tag.outputs.image_tag }}
run: |
DIGEST=$(docker buildx imagetools inspect "artifact.probo.inc/probo/probo:${IMAGE_TAG}" --format '{{json .Manifest.Digest}}' | jq -r)
if [ -z "${DIGEST}" ] || [ "${DIGEST}" = "null" ]; then
echo "Failed to resolve manifest digest for artifact.probo.inc/probo/probo:${IMAGE_TAG}"
exit 1
fi
echo "digest=${DIGEST}" >> "$GITHUB_OUTPUT"
- name: "Sign Docker manifest"
env:
DIGEST: ${{ steps.digest.outputs.digest }}
IMAGE_TAG: ${{ steps.tag.outputs.image_tag }}
run: |
IMAGE="artifact.probo.inc/probo/probo"
cosign sign "${IMAGE}@${DIGEST}" --yes
cosign sign "${IMAGE}:${IMAGE_TAG}" --yes
cosign sign "${IMAGE}:latest" --yes
- name: "Verify Docker signature"
env:
DIGEST: ${{ steps.digest.outputs.digest }}
run: |
cosign verify \
--certificate-identity-regexp '^https://github.com/getprobo/probo/.github/workflows/release-probod.yaml@refs/tags/probod/v' \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"artifact.probo.inc/probo/probo@${DIGEST}"
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v6
with:
fetch-depth: 0
submodules: recursive
- uses: "runs-on/action@d141ef83eb66d096ce8afc767e09115a65c63b60" # v2
- uses: "sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6" # v4.1.2
- 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@a1948c3f048ba23858d222213b7c278aabede763" # v4.1.1
with:
subject-path: "archives/*.tar.gz, archives/*.zip"
sbom-path: "sbom.json"
- name: "Attest build provenance for archives"
uses: "actions/attest@a1948c3f048ba23858d222213b7c278aabede763" # v4.1.1
with:
subject-path: "archives/*.tar.gz, archives/*.zip"
- name: "Attest Docker image SBOM"
uses: "actions/attest@a1948c3f048ba23858d222213b7c278aabede763" # v4.1.1
with:
subject-name: "artifact.probo.inc/probo/probo"
subject-digest: ${{ needs.docker-manifest.outputs.digest }}
sbom-path: "sbom.json"
- name: "Trivy scan Docker image"
uses: "aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25" # 0.36.0
with:
image-ref: "artifact.probo.inc/probo/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@8aad20d150bbac5944a9f9d289da16a4b0d87c1e" # v4.36.2
if: always()
with:
sarif_file: "trivy-results.sarif"
ref: "refs/heads/main"
sha: ${{ github.sha }}
category: "trivy-docker-image"
- name: "Compose release notes"
env:
IMAGE_TAG: ${{ needs.docker-manifest.outputs.image_tag }}
run: |
VERSION="${GITHUB_REF_NAME##*/v}"
awk -v ver="$VERSION" '
/^## \[/ { if (found) exit; if ($0 ~ "\\[" ver "\\]") found=1 }
found
' cmd/probod/CHANGELOG.md > release-notes.md
cat >> release-notes.md << EOF
## Docker Images
- \`artifact.probo.inc/probo/probo:${IMAGE_TAG}\` (multi-arch: linux/amd64, linux/arm64)
- \`artifact.probo.inc/probo/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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7
with:
name: "sbom"
path: "sbom.json"
retention-days: 30