From 29186082408f544d2471d6463055795237cd42c4 Mon Sep 17 00:00:00 2001 From: NuklearRabbit <145918611+NuklearRabbit@users.noreply.github.com> Date: Sat, 29 Aug 2026 00:27:17 +0200 Subject: [PATCH] fix(ci): isolate contract and image scans from host paths --- .gitea/workflows/ci.yml | 20 +++----------------- backend/Dockerfile | 2 ++ scripts/scan-ci-image.sh | 29 +++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 17 deletions(-) create mode 100644 scripts/scan-ci-image.sh diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 5f47bbc..32f4a02 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -39,34 +39,20 @@ jobs: - name: Contract drift gate run: | docker compose -p mobilityops-ci -f compose.yaml -f compose.test.yaml run --rm \ - -v "$PWD:/repo:ro" api python /repo/scripts/check-contracts.py + api python scripts/check-contracts.py python scripts/check-source-budgets.py - name: Build production API image for vulnerability scan run: | docker build --target runtime --build-arg VCS_REF="$GITHUB_SHA" \ --tag mobilityops-api-ci --file backend/Dockerfile . - name: Production API image vulnerability scan (HIGH/CRITICAL) - uses: aquasecurity/trivy-action@a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 # v0.36.0 - with: - scan-type: image - image-ref: mobilityops-api-ci - format: table - severity: HIGH,CRITICAL - exit-code: "1" - ignore-unfixed: true + run: bash scripts/scan-ci-image.sh mobilityops-api-ci - name: Build production web image for vulnerability scan run: | docker build --build-arg VCS_REF="$GITHUB_SHA" \ --tag mobilityops-web-ci frontend - name: Production web image vulnerability scan (HIGH/CRITICAL) - uses: aquasecurity/trivy-action@a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 # v0.36.0 - with: - scan-type: image - image-ref: mobilityops-web-ci - format: table - severity: HIGH,CRITICAL - exit-code: "1" - ignore-unfixed: true + run: bash scripts/scan-ci-image.sh mobilityops-web-ci - name: Remove CI stack if: always() run: docker compose -p mobilityops-ci -f compose.yaml -f compose.test.yaml down -v --remove-orphans diff --git a/backend/Dockerfile b/backend/Dockerfile index d4ede03..1a48703 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -24,6 +24,8 @@ FROM runtime-base AS test COPY backend/requirements.lock ./requirements.lock RUN pip install --no-cache-dir -r requirements.lock COPY backend/tests ./tests +COPY contracts ./contracts +COPY scripts/check-contracts.py ./scripts/check-contracts.py USER app FROM runtime-base AS runtime diff --git a/scripts/scan-ci-image.sh b/scripts/scan-ci-image.sh new file mode 100644 index 0000000..abd2b6b --- /dev/null +++ b/scripts/scan-ci-image.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +TARGET_IMAGE="${1:?usage: scan-ci-image.sh }" +TRIVY_IMAGE="aquasec/trivy@sha256:be1190afcb28352bfddc4ddeb71470835d16462af68d310f9f4bca710961a41e" +SAFE_NAME="$(printf '%s' "$TARGET_IMAGE" | tr -cs 'A-Za-z0-9._-' '-')" +ARCHIVE_RELATIVE="artifacts/.${SAFE_NAME}.tar" +ARCHIVE="$ROOT/$ARCHIVE_RELATIVE" +trap 'rm -f "$ARCHIVE"' EXIT + +mkdir -p "$ROOT/artifacts" +docker image inspect "$TARGET_IMAGE" >/dev/null +docker save --output "$ARCHIVE" "$TARGET_IMAGE" + +WORKSPACE_ARGS=(-v "$ROOT:/workspace:ro") +CONTAINER_ARCHIVE="/workspace/$ARCHIVE_RELATIVE" +if docker inspect "${HOSTNAME:-}" >/dev/null 2>&1; then + WORKSPACE_ARGS=(--volumes-from "$HOSTNAME") + CONTAINER_ARCHIVE="$ROOT/$ARCHIVE_RELATIVE" +fi + +docker run --rm "${WORKSPACE_ARGS[@]}" "$TRIVY_IMAGE" image \ + --input "$CONTAINER_ARCHIVE" \ + --scanners vuln \ + --severity HIGH,CRITICAL \ + --ignore-unfixed \ + --exit-code 1 \ + --format table