name: ci on: push: pull_request: permissions: contents: read jobs: verify: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version-file: go.mod cache: true - uses: actions/setup-node@v4 with: node-version: 24 cache: npm cache-dependency-path: web/package-lock.json - name: Check OpenAPI breaking changes if: github.event_name == 'pull_request' run: | git fetch --no-tags origin "${GITHUB_BASE_REF}" --depth=1 git show "origin/${GITHUB_BASE_REF}:openapi/openapi.yaml" > /tmp/openapi-base.yaml go run github.com/oasdiff/oasdiff@v1.29.1 breaking /tmp/openapi-base.yaml openapi/openapi.yaml --fail-on ERR - name: Go format run: test -z "$(gofmt -l cmd internal)" - name: Go vet and test run: | go vet ./... go test -race -coverprofile=coverage.out ./... - name: Generate API types and build web working-directory: web run: | npm ci npm run generate:api npm run typecheck npm run build - name: Validate compose run: docker compose config --quiet - name: Resolve immutable build identity run: | openapi_version="$(awk '/^ version:/{print $2; exit}' openapi/openapi.yaml)" test -n "$openapi_version" echo "PLATFORM_BUILD_VERSION=${openapi_version}-ci.${GITHUB_RUN_NUMBER}" >> "$GITHUB_ENV" echo "PLATFORM_BUILD_COMMIT=${GITHUB_SHA}" >> "$GITHUB_ENV" echo "PLATFORM_BUILD_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_ENV" - name: Build backend image run: >- docker build -f deploy/backend.Dockerfile --build-arg VERSION="$PLATFORM_BUILD_VERSION" --build-arg COMMIT="$PLATFORM_BUILD_COMMIT" --build-arg BUILD_TIME="$PLATFORM_BUILD_TIME" -t data-terminal-cloud-backend:test . - name: Build web image run: >- docker build -f deploy/web.Dockerfile --build-arg VERSION="$PLATFORM_BUILD_VERSION" --build-arg COMMIT="$PLATFORM_BUILD_COMMIT" --build-arg BUILD_TIME="$PLATFORM_BUILD_TIME" -t data-terminal-cloud-web:test . - name: Go vulnerability and license policy run: | go install golang.org/x/vuln/cmd/govulncheck@v1.1.4 go install github.com/google/go-licenses/v2@v2.0.1 govulncheck ./... go-licenses check --ignore data-terminal-cloud ./cmd/... - name: Frontend vulnerability and license policy working-directory: web run: | npm audit --audit-level=high npx --yes license-checker-rseidelsohn@5.0.1 --production --failOn 'GPL-2.0;GPL-3.0;AGPL-1.0;AGPL-3.0;SSPL-1.0;BUSL-1.1' - name: Repository secret scan run: >- docker run --rm -v "$PWD:/src" zricethezav/gitleaks:v8.30.1@sha256:c00b6bd0aeb3071cbcb79009cb16a60dd9e0a7c60e2be9ab65d25e6bc8abbb7f detect --source=/src --config=/src/.gitleaks.toml --no-banner - name: Infrastructure configuration scan run: >- docker run --rm -v "$PWD:/src" aquasec/trivy:0.74.0@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969 config --exit-code 1 --severity HIGH,CRITICAL /src - name: Image vulnerability scan run: | docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy:0.74.0@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969 image --exit-code 1 --ignore-unfixed --severity HIGH,CRITICAL data-terminal-cloud-backend:test docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy:0.74.0@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969 image --exit-code 1 --ignore-unfixed --severity HIGH,CRITICAL data-terminal-cloud-web:test - name: Generate CycloneDX software bills of materials run: | mkdir -p artifacts docker run --rm -v "$PWD:/src" anchore/syft:v1.51.0@sha256:678bfa565b60f747aac0f8e964fe5588a24445b8d0a480e91f6efd70020dfbb0 dir:/src -o cyclonedx-json=/src/artifacts/source.cdx.json docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v "$PWD/artifacts:/artifacts" anchore/syft:v1.51.0@sha256:678bfa565b60f747aac0f8e964fe5588a24445b8d0a480e91f6efd70020dfbb0 data-terminal-cloud-backend:test -o cyclonedx-json=/artifacts/backend-image.cdx.json docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v "$PWD/artifacts:/artifacts" anchore/syft:v1.51.0@sha256:678bfa565b60f747aac0f8e964fe5588a24445b8d0a480e91f6efd70020dfbb0 data-terminal-cloud-web:test -o cyclonedx-json=/artifacts/web-image.cdx.json - name: Record immutable build metadata run: | backend_digest="$(docker image inspect --format='{{.Id}}' data-terminal-cloud-backend:test)" web_digest="$(docker image inspect --format='{{.Id}}' data-terminal-cloud-web:test)" backend_version="$(docker image inspect --format='{{index .Config.Labels "org.opencontainers.image.version"}}' data-terminal-cloud-backend:test)" backend_commit="$(docker image inspect --format='{{index .Config.Labels "org.opencontainers.image.revision"}}' data-terminal-cloud-backend:test)" backend_time="$(docker image inspect --format='{{index .Config.Labels "org.opencontainers.image.created"}}' data-terminal-cloud-backend:test)" web_version="$(docker image inspect --format='{{index .Config.Labels "org.opencontainers.image.version"}}' data-terminal-cloud-web:test)" web_commit="$(docker image inspect --format='{{index .Config.Labels "org.opencontainers.image.revision"}}' data-terminal-cloud-web:test)" web_time="$(docker image inspect --format='{{index .Config.Labels "org.opencontainers.image.created"}}' data-terminal-cloud-web:test)" test "$backend_version" = "$PLATFORM_BUILD_VERSION" test "$web_version" = "$PLATFORM_BUILD_VERSION" test "$backend_commit" = "$GITHUB_SHA" test "$web_commit" = "$GITHUB_SHA" test "$backend_time" = "$PLATFORM_BUILD_TIME" test "$web_time" = "$PLATFORM_BUILD_TIME" jq -n --arg candidate_version "$PLATFORM_BUILD_VERSION" --arg source_commit "$GITHUB_SHA" --arg build_time "$PLATFORM_BUILD_TIME" --arg run_id "$GITHUB_RUN_ID" --arg run_attempt "$GITHUB_RUN_ATTEMPT" --arg backend_digest "$backend_digest" --arg web_digest "$web_digest" '{candidate_version:$candidate_version,source_commit:$source_commit,build_time:$build_time,run_id:$run_id,run_attempt:$run_attempt,backend_image_digest:$backend_digest,web_image_digest:$web_digest}' > artifacts/build-metadata.json - uses: actions/upload-artifact@v4 with: name: security-and-sbom path: artifacts/*