Generate MCP types before complianceportal, stub apps/trust dist for embed, fix domains section indent, and start the compose stack only after bin/probod is built. Signed-off-by: Bryan Frimin <bryan@probo.com>
370 lines
14 KiB
YAML
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/mcp/v1
|
|
go generate ./pkg/server/api/console/v1
|
|
go generate ./pkg/server/api/complianceportal/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
|