name: Cloud Verify on: pull_request: types: [opened, synchronize, reopened, ready_for_review, converted_to_draft] paths: - cloud/** - src/packages/process-host/** - .github/workflows/cloud-*.yml - .github/actions/cloud-sql-rollout-lease/** - .github/actions/setup-pnpm/** push: branches: [main] paths: - cloud/** - src/packages/process-host/** - .github/workflows/cloud-*.yml - .github/actions/cloud-sql-rollout-lease/** - .github/actions/setup-pnpm/** permissions: contents: read concurrency: group: cloud-verify-${{ github.ref }} cancel-in-progress: true defaults: run: working-directory: cloud jobs: # Public-repository hosted runners preserve Blacksmith allowance for macOS. security: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true name: Secret scan runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 with: fetch-depth: 1 - name: Pull Gitleaks image id: gitleaks-image background: true run: docker pull zricethezav/gitleaks@sha256:cdbb7c955abce02001a9f6c9f602fb195b7fadc1e812065883f695d1eeaba854 - name: Pull TruffleHog image id: trufflehog-image background: true run: docker pull trufflesecurity/trufflehog@sha256:5dc064868ba7933601b5cbaea6954954d524ddd5dc6222a9667acea70068bf7d # Scan every ancestor of HEAD without downloading unrelated branch/tag histories. - name: Fetch complete scan history working-directory: . run: | git fetch --no-tags --unshallow origin "$GITHUB_SHA" test "$(git rev-parse --is-shallow-repository)" = false - wait: [gitleaks-image, trufflehog-image] - name: Scan Cloud history reachable from HEAD with Gitleaks id: history-scan background: true run: >- docker run --rm --volume "${GITHUB_WORKSPACE}:/repo:ro" zricethezav/gitleaks@sha256:cdbb7c955abce02001a9f6c9f602fb195b7fadc1e812065883f695d1eeaba854 git /repo --config /repo/cloud/.gitleaks.toml --log-opts="HEAD -- cloud :(glob).github/workflows/cloud-*.yml .github/actions/cloud-sql-rollout-lease" - name: Scan the single-commit Cloud snapshot with TruffleHog run: >- docker run --rm --volume "${GITHUB_WORKSPACE}:/repo:ro" trufflesecurity/trufflehog@sha256:5dc064868ba7933601b5cbaea6954954d524ddd5dc6222a9667acea70068bf7d filesystem /repo --no-verification --fail --include-paths=/repo/cloud/.trufflehog-include-paths.txt --exclude-paths=/repo/cloud/.trufflehog-exclude-paths.txt - wait: history-scan # Compile without Postgres: no database access occurs here, avoiding ~13s service startup. build: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - uses: ./.github/actions/setup-pnpm with: package-json-file: cloud/package.json - uses: actions/setup-node@v4 with: node-version: 24 check-latest: true - run: pnpm install --frozen-lockfile - name: Audit production and development dependencies run: pnpm audit --json > security-dependencies.json - uses: actions/upload-artifact@v4 if: always() with: name: cloud-dependency-audit path: cloud/security-dependencies.json retention-days: 30 - run: pnpm build - run: pnpm typecheck containers: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true name: Container security (${{ matrix.app }}) runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: app: [relay, push, connector] env: APP: ${{ matrix.app }} TRIVY_IMAGE: aquasec/trivy:0.76.1@sha256:790fd66d1697395d8693d1acaa1ea702406a20f109b6fc7bac8db623eca6c06c steps: - uses: actions/checkout@v4 - name: Build or resolve the runtime image run: | set -euo pipefail IMAGE="orca-cloud-security:$APP" docker build --platform linux/amd64 \ --file "apps/$APP/Dockerfile" --tag "$IMAGE" . echo "IMAGE=$IMAGE" >> "$GITHUB_ENV" - name: Smoke test the nonroot Node runtime run: | docker run --rm --platform linux/amd64 --entrypoint sh "$IMAGE" -ec ' test "$(id -u)" -ne 0 ! command -v npm ! command -v pnpm module=app if test "$1" = push; then module=push-server; fi if test "$1" = connector; then module=connector-server; fi node --input-type=module -e "await import(\"./apps/$1/dist/$module.js\")" ' sh "$APP" - name: Scan every severity and retain the complete inventory run: | mkdir -p security-reports docker run --rm --volume /var/run/docker.sock:/var/run/docker.sock \ --volume "$PWD/security-reports:/reports" "$TRIVY_IMAGE" image \ --platform linux/amd64 --scanners vuln --ignorefile '' \ --format json --output /reports/vulnerabilities.json "$IMAGE" docker run --rm --volume "$PWD/security-reports:/reports" "$TRIVY_IMAGE" convert \ --format cyclonedx --output /reports/sbom.cdx.json /reports/vulnerabilities.json - name: Reject available fixes run: | jq '(.Results[]?.Vulnerabilities) |= ((. // []) | map(select(.FixedVersion != null and .FixedVersion != "")))' \ security-reports/vulnerabilities.json > security-reports/fixable.json docker run --rm --volume "$PWD:/repo:ro" "$TRIVY_IMAGE" convert \ --ignorefile '' --show-suppressed --exit-code 1 \ /repo/security-reports/fixable.json - uses: actions/upload-artifact@v4 if: always() with: name: cloud-container-security-${{ matrix.app }} path: cloud/security-reports/ retention-days: 30 # Run tests beside build; pretest hooks compile their own workspace dependencies. test: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true runs-on: ubuntu-22.04 services: postgres: image: postgres:16-alpine env: POSTGRES_DB: orca_relay_test POSTGRES_PASSWORD: relay_test POSTGRES_USER: relay_test ports: - 5432:5432 options: >- --health-cmd "pg_isready -U relay_test -d orca_relay_test" --health-interval 5s --health-timeout 5s --health-retries 10 env: ORCA_BACKGROUND_LAUNCH: '1' ORCA_PUSH_TEST_DATABASE_URL: postgres://relay_test:relay_test@127.0.0.1:5432/orca_relay_test ORCA_CONNECTOR_TEST_DATABASE_URL: postgres://relay_test:relay_test@127.0.0.1:5432/orca_relay_test ORCA_CLOUD_DATABASE_TEST_URL: postgres://relay_test:relay_test@127.0.0.1:5432/orca_relay_test ORCA_RELAY_TEST_POSTGRES_URL: postgres://relay_test:relay_test@127.0.0.1:5432/orca_relay_test steps: - uses: actions/checkout@v4 - uses: ./.github/actions/setup-pnpm with: package-json-file: cloud/package.json - uses: actions/setup-node@v4 with: node-version: 24 check-latest: true - run: pnpm install --frozen-lockfile - run: pnpm test