Harden dependency and image security checks

Signed-off-by: Jordan Mecom <jm@squareup.com>
This commit is contained in:
Jordan Mecom
2026-08-20 13:17:37 -07:00
parent cd0d33f085
commit 7ebc8382cc
19 changed files with 664 additions and 393 deletions

View File

@@ -23,22 +23,23 @@ jobs:
timeout-minutes: 15
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
cache: pip
- uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1
- name: Test adapter
working-directory: benchmarks/harbor-buzz-orchestra
run: |
python -m pip install --disable-pip-version-check -e ".[dev]"
pytest -q
ruff check .
bin/uv --directory benchmarks/harbor-buzz-orchestra sync --frozen --extra dev
bin/uv --directory benchmarks/harbor-buzz-orchestra run --frozen --extra dev pytest -q
bin/uv --directory benchmarks/harbor-buzz-orchestra run --frozen --extra dev ruff check .
# The task verifiers live in the sibling benchmarks/buzz-dataset, so
# they need the harness config passed explicitly to stay linted.
ruff check --config pyproject.toml ../buzz-dataset
bin/uv --directory benchmarks/harbor-buzz-orchestra run --frozen --extra dev \
ruff check --config pyproject.toml ../buzz-dataset
- name: Test provisioner
working-directory: benchmarks/harbor-buzz-orchestra/testbed
run: |
python -m pip install --disable-pip-version-check -e ".[dev]"
pytest -q
ruff check .
bin/uv --directory benchmarks/harbor-buzz-orchestra/testbed sync --frozen --extra dev
bin/uv --directory benchmarks/harbor-buzz-orchestra/testbed run --frozen --extra dev pytest -q
bin/uv --directory benchmarks/harbor-buzz-orchestra/testbed run --frozen --extra dev ruff check .

View File

@@ -883,7 +883,7 @@ jobs:
key: pub-${{ runner.os }}-${{ hashFiles('mobile/pubspec.lock') }}
restore-keys: pub-${{ runner.os }}-
- name: Install dependencies
run: cd mobile && flutter pub get
run: cd mobile && flutter pub get --enforce-lockfile
- name: Save pub cache
if: always() && steps.pub-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5
@@ -900,19 +900,57 @@ jobs:
- name: Build Android debug APK
run: just mobile-build-android
osv-lockfile-scan:
name: OSV Lockfile Scan
permissions:
actions: read
contents: read
uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@8deb546fdb875b9996d27d4950be7312dac076a1 # v2.5.0
with:
upload-sarif: false
scan-args: |-
--config=./osv-scanner.toml
--recursive
./
security:
name: Security
runs-on: ubuntu-latest
timeout-minutes: 20
needs: [changes]
if: github.event_name == 'push' || needs.changes.outputs.rust == 'true'
timeout-minutes: 25
needs: [osv-lockfile-scan]
if: always()
permissions:
contents: read
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1
- name: Dependency policy
run: cargo-deny check
- name: Require successful lockfile scan
env:
OSV_RESULT: ${{ needs.osv-lockfile-scan.result }}
run: |
if [ "$OSV_RESULT" != "success" ]; then
echo "::error::OSV lockfile scan finished with status: $OSV_RESULT"
exit 1
fi
- name: Review dependency changes
if: github.event_name == 'pull_request'
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
with:
fail-on-severity: low
- name: Root Rust dependency policy
run: cargo-deny --locked check
- name: Desktop Rust dependency policy
run: cargo-deny --locked --manifest-path desktop/src-tauri/Cargo.toml check
- name: Python lockfile consistency
run: |
bin/uv --directory benchmarks/harbor-buzz-orchestra lock --check
bin/uv --directory benchmarks/harbor-buzz-orchestra/testbed lock --check
- name: JavaScript vulnerability audit
run: pnpm audit --audit-level moderate
- name: CocoaPods vulnerability audit
run: bin/trivy fs --scanners vuln --exit-code 1 --severity UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL mobile/ios/Podfile.lock
dead-token-guard:
name: Dead Token Reference Guard

View File

@@ -175,12 +175,24 @@ jobs:
# Push by digest, not by tag — the merge job assembles the tags
# into one multi-arch manifest. This is what makes the native-arm
# matrix possible.
outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
outputs: ${{ github.event_name == 'pull_request' && format('type=docker,name=buzz-ci:release-{0}', matrix.arch) || format('type=image,name={0},push-by-digest=true,name-canonical=true,push=true', env.IMAGE_NAME) }}
cache-from: |
type=registry,ref=${{ env.IMAGE_NAME }}-buildcache:${{ matrix.arch }}
cache-to: |
${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && format('type=registry,ref={0}-buildcache:{1},mode=max,compression=zstd', env.IMAGE_NAME, matrix.arch) || '' }}
- name: Scan release image
env:
LOCAL_IMAGE: buzz-ci:release-${{ matrix.arch }}
REMOTE_IMAGE: ${{ env.IMAGE_NAME }}@${{ steps.build-release.outputs.digest }}
run: |
. ./bin/activate-hermit
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
scripts/scan-container-image.sh "$LOCAL_IMAGE"
else
scripts/scan-container-image.sh "$REMOTE_IMAGE"
fi
- name: Build and push debug image by digest
id: build-debug
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
@@ -190,10 +202,22 @@ jobs:
target: runtime-debug
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
outputs: ${{ github.event_name == 'pull_request' && format('type=docker,name=buzz-ci:debug-{0}', matrix.arch) || format('type=image,name={0},push-by-digest=true,name-canonical=true,push=true', env.IMAGE_NAME) }}
cache-from: |
type=registry,ref=${{ env.IMAGE_NAME }}-buildcache:${{ matrix.arch }}
- name: Scan debug image
env:
LOCAL_IMAGE: buzz-ci:debug-${{ matrix.arch }}
REMOTE_IMAGE: ${{ env.IMAGE_NAME }}@${{ steps.build-debug.outputs.digest }}
run: |
. ./bin/activate-hermit
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
scripts/scan-container-image.sh "$LOCAL_IMAGE"
else
scripts/scan-container-image.sh "$REMOTE_IMAGE"
fi
- name: Export release and debug digests
if: github.event_name != 'pull_request'
env:
@@ -400,9 +424,20 @@ jobs:
file: ./Dockerfile.push-gateway
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=ghcr.io/block/buzz-push-gateway,push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
outputs: ${{ github.event_name == 'pull_request' && format('type=docker,name=buzz-push-gateway-ci:{0}', matrix.arch) || 'type=image,name=ghcr.io/block/buzz-push-gateway,push-by-digest=true,name-canonical=true,push=true' }}
cache-from: type=registry,ref=ghcr.io/block/buzz-push-gateway-buildcache:${{ matrix.arch }}
cache-to: ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && format('type=registry,ref=ghcr.io/block/buzz-push-gateway-buildcache:{0},mode=max,compression=zstd', matrix.arch) || '' }}
- name: Scan push gateway image
env:
LOCAL_IMAGE: buzz-push-gateway-ci:${{ matrix.arch }}
REMOTE_IMAGE: ghcr.io/block/buzz-push-gateway@${{ steps.build.outputs.digest }}
run: |
. ./bin/activate-hermit
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
scripts/scan-container-image.sh "$LOCAL_IMAGE"
else
scripts/scan-container-image.sh "$REMOTE_IMAGE"
fi
- name: Export digest
if: github.event_name != 'pull_request'
env:

View File

@@ -120,12 +120,24 @@ jobs:
file: ./Dockerfile.sprig
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
outputs: ${{ github.event_name == 'pull_request' && format('type=docker,name=buzz-sprig-ci:{0}', matrix.arch) || format('type=image,name={0},push-by-digest=true,name-canonical=true,push=true', env.IMAGE_NAME) }}
cache-from: |
type=registry,ref=${{ env.IMAGE_NAME }}-buildcache:${{ matrix.arch }}
cache-to: |
${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && format('type=registry,ref={0}-buildcache:{1},mode=max,compression=zstd', env.IMAGE_NAME, matrix.arch) || '' }}
- name: Scan image
env:
LOCAL_IMAGE: buzz-sprig-ci:${{ matrix.arch }}
REMOTE_IMAGE: ${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
run: |
. ./bin/activate-hermit
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
scripts/scan-container-image.sh "$LOCAL_IMAGE"
else
scripts/scan-container-image.sh "$REMOTE_IMAGE"
fi
- name: Export digest
if: github.event_name != 'pull_request'
env: