From 0c8854c83f92594ed312997fc78586e36ab5f2b1 Mon Sep 17 00:00:00 2001 From: nisargabd Date: Thu, 3 Sep 2026 15:01:56 +0530 Subject: [PATCH 1/7] chore: add test, security and build-and-push CI workflows [#999] Adds a run-tests/security/build-and-push flow: gated lint, gotestsum with diff-scoped coverage, dependency+image Trivy scans gated on HIGH/CRITICAL, multi-registry multi-arch build-and-push on release tags. Both Dockerfiles switch to dhi.io base images (with public overrides for a local build without a DHI subscription), so the security and build-and-push jobs authenticate to dhi.io first. --- .github/actions/dhi-login/action.yml | 28 +++ .github/workflows/build-and-push.yml | 276 +++++++++++++++++++++++++++ .github/workflows/run-tests.yml | 107 +++++++++++ .github/workflows/security.yml | 215 +++++++++++++++++++++ .gitignore | 8 + Dockerfile.adapter | 36 +++- Dockerfile.adapter-with-plugins | 34 +++- Makefile | 175 +++++++++++++++++ 8 files changed, 864 insertions(+), 15 deletions(-) create mode 100644 .github/actions/dhi-login/action.yml create mode 100644 .github/workflows/build-and-push.yml create mode 100644 .github/workflows/run-tests.yml create mode 100644 .github/workflows/security.yml create mode 100644 Makefile diff --git a/.github/actions/dhi-login/action.yml b/.github/actions/dhi-login/action.yml new file mode 100644 index 00000000..4dac2fdb --- /dev/null +++ b/.github/actions/dhi-login/action.yml @@ -0,0 +1,28 @@ +name: Log in to dhi.io +description: > + Authenticates to dhi.io (Docker Hardened Images), gated on a Docker + subscription — anonymous pulls 401. Both Dockerfiles default to dhi.io/* + base images (see each Dockerfile's FROM comment), so every job that builds + or scans an image needs this first. Written directly to + ~/.docker/config.json rather than through docker/login-action, whose + username/password inputs don't accept a pre-combined blob — this matches + the format `docker login` itself writes. + +inputs: + username: + description: DHI credential username (org secret DOCKERHUB_USERNAME — DHI's subscription is tied to a Docker Hub account) + required: true + token: + description: DHI credential token (org secret DOCKERHUB_TOKEN) + required: true + +runs: + using: composite + steps: + - shell: bash + run: | + AUTH=$(printf '%s:%s' "${{ inputs.username }}" "${{ inputs.token }}" | base64 -w0) + mkdir -p ~/.docker + cat > ~/.docker/config.json <> "$GITHUB_OUTPUT" + + - name: Cache Trivy binary and vulnerability DB + uses: actions/cache@v4 + with: + path: | + bin/trivy + ~/.cache/trivy + key: trivy-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('Makefile') }}-${{ steps.trivy-date.outputs.date }} + restore-keys: | + trivy-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('Makefile') }}- + + - uses: docker/setup-buildx-action@v3 + + # One flag per registry, read from repo variables (Settings > Secrets + # and variables > Actions > Variables), so a registry is switched on + # without a workflow edit. GHCR is the only one we use today, so it + # defaults on; everything else defaults off until its secrets exist. + # Adding a registry later is: a flag here, a login step below, and one + # more branch in "Tag and push" and the manifest job's create_manifest + # calls — the build/scan steps never change. + - name: Set registry flags + run: | + echo "GHCR_ENABLED=${{ vars.GHCR_ENABLED != 'false' }}" >> "$GITHUB_ENV" + echo "DOCKERHUB_ENABLED=${{ vars.DOCKERHUB_ENABLED == 'true' }}" >> "$GITHUB_ENV" + echo "AZURE_CONTAINER_REGISTRY_ENABLED=${{ vars.AZURE_CONTAINER_REGISTRY_ENABLED == 'true' }}" >> "$GITHUB_ENV" + echo "GOOGLE_ARTIFACT_REGISTRY_ENABLED=${{ vars.GOOGLE_ARTIFACT_REGISTRY_ENABLED == 'true' }}" >> "$GITHUB_ENV" + + - name: Log in to dhi.io + uses: ./.github/actions/dhi-login + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + token: ${{ secrets.DOCKERHUB_TOKEN }} + + # GITHUB_TOKEN can be denied write_package when creating a brand-new + # package under a personal (non-org) namespace, even with this + # workflow's `packages: write` and the repo's default token permissions + # both set to write — a documented GHCR quirk. GHCR_PAT (classic PAT, + # write:packages) is the standard workaround; falls back to + # GITHUB_TOKEN when no such secret is set, which is enough once the + # package exists or for an org-owned repo. + - name: Log in to GHCR + if: env.GHCR_ENABLED == 'true' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GHCR_PAT || secrets.GITHUB_TOKEN }} + + - name: Log in to Docker Hub + if: env.DOCKERHUB_ENABLED == 'true' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + + - name: Log in to Azure Container Registry + if: env.AZURE_CONTAINER_REGISTRY_ENABLED == 'true' + uses: docker/login-action@v3 + with: + registry: ${{ secrets.AZURE_REGISTRY_NAME }} + username: ${{ secrets.AZURE_REGISTRY_USERNAME }} + password: ${{ secrets.AZURE_REGISTRY_PASSWORD }} + + - name: Authenticate to Google Cloud + if: env.GOOGLE_ARTIFACT_REGISTRY_ENABLED == 'true' + uses: google-github-actions/auth@v3 + with: + token_format: "access_token" + workload_identity_provider: ${{ secrets.GOOGLE_WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_EMAIL }} + + - name: Configure Docker for Google Artifact Registry + if: env.GOOGLE_ARTIFACT_REGISTRY_ENABLED == 'true' + run: gcloud auth configure-docker ${{ secrets.GCP_REGION }}-docker.pkg.dev --quiet + + # GHCR image refs must be lowercase; github.repository_owner preserves + # the owner's real case, so it can't be used as-is. This resolves to + # whichever account or org owns the repo the tag was pushed to — a + # fork pushes under the fork owner, no per-person edit needed. + - name: Set image owner + run: echo "OWNER=$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV" + + # Single source of truth for the build-time identity vars (see + # pkg/version) — written to $GITHUB_ENV so the build-push-action step + # below can reference them as build-args the same way a local + # `source install/scripts/version-vars.sh` would. + - name: Resolve version vars + run: | + source install/scripts/version-vars.sh + { + echo "ONIX_VERSION=$ONIX_VERSION" + echo "GIT_COMMIT=$GIT_COMMIT" + echo "GIT_TREE_STATE=$GIT_TREE_STATE" + echo "BUILD_DATE=$BUILD_DATE" + } >> "$GITHUB_ENV" + + # One local, unpushed tag per arch — the manifest job below stitches + # amd64 and arm64 into the single tag users actually pull. + # + # load: true instead of push: true — the image lands in this runner's + # local Docker daemon first so Trivy can scan the exact bytes about to + # ship, before it is tagged for or pushed to any registry. + - name: Build (local, unpushed) + uses: docker/build-push-action@v6 + with: + context: . + file: Dockerfile.adapter + platforms: ${{ matrix.platform }} + build-args: | + ONIX_VERSION=${{ env.ONIX_VERSION }} + GIT_COMMIT=${{ env.GIT_COMMIT }} + GIT_TREE_STATE=${{ env.GIT_TREE_STATE }} + BUILD_DATE=${{ env.BUILD_DATE }} + load: true + tags: ${{ env.IMAGE_NAME }}:${{ github.ref_name }}-${{ matrix.arch }} + + # trivy-release-gate exits 1 on a finding — the release gate, not just + # a report — before any push below runs. One scan covers every registry. + - name: Trivy image scan (gate) + run: make trivy-release-gate IMAGE=${{ env.IMAGE_NAME }}:${{ github.ref_name }}-${{ matrix.arch }} + + # Re-tag the already-scanned local image for each enabled registry and + # push it there. No rebuild, no re-scan. + - name: Tag and push + run: | + LOCAL="${{ env.IMAGE_NAME }}:${{ github.ref_name }}-${{ matrix.arch }}" + TAG="${{ github.ref_name }}-${{ matrix.arch }}" + + if [ "$GHCR_ENABLED" = "true" ]; then + DEST="ghcr.io/${OWNER}/${{ env.IMAGE_NAME }}:${TAG}" + docker tag "$LOCAL" "$DEST" + docker push "$DEST" + fi + if [ "$DOCKERHUB_ENABLED" = "true" ]; then + DEST="${{ secrets.DOCKERHUB_NAMESPACE }}/${{ env.IMAGE_NAME }}:${TAG}" + docker tag "$LOCAL" "$DEST" + docker push "$DEST" + fi + if [ "$AZURE_CONTAINER_REGISTRY_ENABLED" = "true" ]; then + DEST="${{ secrets.AZURE_REGISTRY_NAME }}/${{ env.IMAGE_NAME }}:${TAG}" + docker tag "$LOCAL" "$DEST" + docker push "$DEST" + fi + if [ "$GOOGLE_ARTIFACT_REGISTRY_ENABLED" = "true" ]; then + DEST="${{ secrets.GCP_REGION }}-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/${{ secrets.GOOGLE_ARTIFACT_REPO }}/${{ env.IMAGE_NAME }}:${TAG}" + docker tag "$LOCAL" "$DEST" + docker push "$DEST" + fi + + manifest: + runs-on: ubuntu-latest + needs: build + steps: + - uses: docker/setup-buildx-action@v3 + + - name: Set registry flags + run: | + echo "GHCR_ENABLED=${{ vars.GHCR_ENABLED != 'false' }}" >> "$GITHUB_ENV" + echo "DOCKERHUB_ENABLED=${{ vars.DOCKERHUB_ENABLED == 'true' }}" >> "$GITHUB_ENV" + echo "AZURE_CONTAINER_REGISTRY_ENABLED=${{ vars.AZURE_CONTAINER_REGISTRY_ENABLED == 'true' }}" >> "$GITHUB_ENV" + echo "GOOGLE_ARTIFACT_REGISTRY_ENABLED=${{ vars.GOOGLE_ARTIFACT_REGISTRY_ENABLED == 'true' }}" >> "$GITHUB_ENV" + + - name: Log in to GHCR + if: env.GHCR_ENABLED == 'true' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GHCR_PAT || secrets.GITHUB_TOKEN }} + + - name: Log in to Docker Hub + if: env.DOCKERHUB_ENABLED == 'true' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + + - name: Log in to Azure Container Registry + if: env.AZURE_CONTAINER_REGISTRY_ENABLED == 'true' + uses: docker/login-action@v3 + with: + registry: ${{ secrets.AZURE_REGISTRY_NAME }} + username: ${{ secrets.AZURE_REGISTRY_USERNAME }} + password: ${{ secrets.AZURE_REGISTRY_PASSWORD }} + + - name: Authenticate to Google Cloud + if: env.GOOGLE_ARTIFACT_REGISTRY_ENABLED == 'true' + uses: google-github-actions/auth@v3 + with: + token_format: "access_token" + workload_identity_provider: ${{ secrets.GOOGLE_WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_EMAIL }} + + - name: Configure Docker for Google Artifact Registry + if: env.GOOGLE_ARTIFACT_REGISTRY_ENABLED == 'true' + run: gcloud auth configure-docker ${{ secrets.GCP_REGION }}-docker.pkg.dev --quiet + + - name: Set image owner + run: echo "OWNER=$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV" + + # imagetools create makes one manifest list from the two arch-specific + # images the build job just pushed to that registry — this is what + # lets `docker pull` resolve the right arch automatically on either + # amd64 or arm64. One create_manifest call per enabled registry. + - name: Create multi-arch manifests + run: | + create_manifest() { + local BASE="$1" + docker buildx imagetools create \ + -t "${BASE}:${{ github.ref_name }}" \ + -t "${BASE}:latest" \ + "${BASE}:${{ github.ref_name }}-amd64" \ + "${BASE}:${{ github.ref_name }}-arm64" + } + + if [ "$GHCR_ENABLED" = "true" ]; then + create_manifest "ghcr.io/${OWNER}/${{ env.IMAGE_NAME }}" + fi + if [ "$DOCKERHUB_ENABLED" = "true" ]; then + create_manifest "${{ secrets.DOCKERHUB_NAMESPACE }}/${{ env.IMAGE_NAME }}" + fi + if [ "$AZURE_CONTAINER_REGISTRY_ENABLED" = "true" ]; then + create_manifest "${{ secrets.AZURE_REGISTRY_NAME }}/${{ env.IMAGE_NAME }}" + fi + if [ "$GOOGLE_ARTIFACT_REGISTRY_ENABLED" = "true" ]; then + create_manifest "${{ secrets.GCP_REGION }}-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/${{ secrets.GOOGLE_ARTIFACT_REPO }}/${{ env.IMAGE_NAME }}" + fi diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 00000000..47f4136f --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,107 @@ +name: Run Tests + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + pull-requests: write + +concurrency: + group: test-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + # continue-on-error rather than dropping the job: CLAUDE.md keeps CI + # lint as the safety net behind the pre-commit hook, which is bypassable + # (--no-verify). Advisory here, not a gate — a red lint check must never + # be the reason a PR can't merge, only a reason someone looks. + - run: make lint + continue-on-error: true + + test: + runs-on: ubuntu-latest + steps: + # fetch-depth: 0 — cover-diff below needs the base branch's history + # locally to compute the PR's changed files; a PR checkout otherwise + # holds only the head commit. + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - run: make build + - run: make test-ci + + # continue-on-error so a coverage miss still posts its report; the last + # step in the job turns that outcome back into a failure. Always + # diff-scoped, never whole-repo — main only ever moves by PR merge + # (CLAUDE.md: never commit directly to main), so a PR's own diff is + # already the gate that matters. On a pull_request event that's the PR + # branch vs its target; on a push to main (the merge landing) it's + # github.event.before, the commit main pointed to right before this one. + - name: Check coverage + id: coverage + continue-on-error: true + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + make cover-diff BASE_REF="origin/${{ github.event.pull_request.base.ref }}" + else + make cover-diff BASE_REF="${{ github.event.before }}" + fi + + # Marker goes into the file itself, not just the step summary — it's + # what body-path feeds the PR comment below, and find-comment matches + # on this exact string to update rather than duplicate that comment. + - name: Publish coverage summary + run: | + printf '\n%s\n' "$(cat coverage-report.md)" > coverage-report.md + cat coverage-report.md >> "$GITHUB_STEP_SUMMARY" + + # Always posted, pass or fail or not-applicable — a comment that only + # shows up on failure is ambiguous from the PR itself: did coverage + # run at all, pass, or just never trigger? Always-visible with an + # explicit ✅/❌ (cover-diff's own output) answers that without a + # reviewer having to open the job. Updated in place across runs, not + # reposted, via find-comment below. + # + # continue-on-error on both: a fork PR's default GITHUB_TOKEN is + # read-only, so create-or-update-comment 403s there even with + # pull-requests: write declared. A comment that can't post must never + # fail the job — coverage already gated above, this step is cosmetic. + - name: Find existing coverage comment + if: github.event_name == 'pull_request' + continue-on-error: true + uses: peter-evans/find-comment@v3 + id: find-coverage-comment + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: "github-actions[bot]" + body-includes: "" + + - name: Comment coverage on PR + if: github.event_name == 'pull_request' + continue-on-error: true + uses: peter-evans/create-or-update-comment@v4 + with: + comment-id: ${{ steps.find-coverage-comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body-path: coverage-report.md + edit-mode: replace + + - name: Gate on minimum coverage + if: steps.coverage.outcome == 'failure' + run: | + echo "::error::coverage is below the minimum — see the summary above" + exit 1 diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 00000000..f4a66049 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,215 @@ +name: Security + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + # Findings are uploaded as SARIF for GitHub's own code scanning UI (Security + # tab, diff annotations) AND posted as a PR comment — the SARIF path alone + # took three clicks (check -> run -> results) to see a finding that used to + # be one scroll away in the PR conversation. pull-requests: write is for + # the comment; security-events: write is for the SARIF upload. + pull-requests: write + security-events: write + +concurrency: + group: security-${{ github.ref }} + cancel-in-progress: true + +jobs: + security: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # The trivy-action this replaced cached both the binary and its + # vulnerability DB across runs; `make trivy-deps`/`trivy-image` alone + # would re-download both (binary ~30MB, DB ~100MB+) on every run. + # Keyed on the Makefile's own hash so a TRIVY_VERSION bump there busts + # the cache automatically, plus a daily date so the DB itself doesn't + # go stale for longer than a day. + - name: Trivy cache date + id: trivy-date + run: echo "date=$(date -u +%F)" >> "$GITHUB_OUTPUT" + + - name: Cache Trivy binary and vulnerability DB + uses: actions/cache@v4 + with: + path: | + bin/trivy + ~/.cache/trivy + key: trivy-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('Makefile') }}-${{ steps.trivy-date.outputs.date }} + restore-keys: | + trivy-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('Makefile') }}- + + # T4, half one: the dependency graph as written. This catches what the + # image scan structurally cannot — a vulnerable module that only the test + # suite imports, so it is never linked into the binary and never appears + # in a layer. + # + # Logic lives in the Makefile's trivy-deps target — same command a local + # `make trivy-deps` runs. + - name: Trivy dependency scan (report) + run: make trivy-deps + + # A category per scan: without it the second upload replaces the first, + # because GitHub keys an analysis on (ref, category). + - name: Upload dependency findings + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: trivy-deps.sarif + category: trivy-dependencies + + # Posted right after the report, on every run — pass or fail, and + # before the image is even built — so a PR shows the dependency finding + # immediately rather than after the whole job finishes. Reads the same + # SARIF just uploaded above; no second scan. + # + # Trivy's SARIF has no structured per-field severity/version columns; + # each finding's detail lives as prose in message.text ("Package: + # ...\nSeverity: ...\n..."), so the table columns below are pulled out + # of that text rather than from dedicated JSON fields. + # continue-on-error: a report-formatting step must never be able to + # fail the job — the gate at the bottom is what decides that. + - name: Assemble Trivy dependency PR comment + if: github.event_name == 'pull_request' + continue-on-error: true + run: | + { + echo "" + echo "### 🛡️ Trivy — Go dependency scan (HIGH,CRITICAL)" + echo "[View full run](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})" + echo + jq -r ' + def val(re; default): (capture(re) // {v: default}).v; + [ .runs[].results[]? ] as $found + | if ($found | length) == 0 then + "No HIGH or CRITICAL findings." + else + "| Package | Severity | Installed | Fixed in | Advisory |", + "|---|---|---|---|---|", + ( $found[] | .ruleId as $id | (.message.text // "") as $m | + "| `" + ($m | val("Package: (?[^\\n]+)"; "?")) + "` " + + "| " + ($m | val("Severity: (?[^\\n]+)"; "?")) + " " + + "| " + ($m | val("Installed Version: (?[^\\n]+)"; "?")) + " " + + "| " + ($m | val("Fixed Version: (?[^\\n]+)"; "—")) + " " + + "| [" + $id + "](" + ($m | val("Link: \\[[^]]+\\]\\((?[^)]+)\\)"; "")) + ") |" + ) + end + ' trivy-deps.sarif + } > trivy-deps-comment.md + + - name: Find existing Trivy dependency comment + if: github.event_name == 'pull_request' + continue-on-error: true + uses: peter-evans/find-comment@v3 + id: find-trivy-deps-comment + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: "github-actions[bot]" + body-includes: "" + + # continue-on-error: a fork PR's default GITHUB_TOKEN is read-only, so + # this 403s there even with pull-requests: write declared. The gate at + # the bottom of this job is what actually decides pass/fail; a comment + # that can't post must never fail the job over that. + - name: Comment Trivy dependency report on PR + if: github.event_name == 'pull_request' + continue-on-error: true + uses: peter-evans/create-or-update-comment@v4 + with: + comment-id: ${{ steps.find-trivy-deps-comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body-path: trivy-deps-comment.md + edit-mode: replace + + - name: Log in to dhi.io + uses: ./.github/actions/dhi-login + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + token: ${{ secrets.DOCKERHUB_TOKEN }} + + # Both Dockerfiles default to dhi.io/* base images, and Trivy reads the + # base layers plus the Go build info embedded in the binary — including + # `stdlib`, so a Go toolchain CVE is reported here and nowhere else the + # dependency scan above cannot see. + - name: Build image + run: | + source install/scripts/version-vars.sh + docker build -f Dockerfile.adapter \ + --build-arg ONIX_VERSION="$ONIX_VERSION" \ + --build-arg GIT_COMMIT="$GIT_COMMIT" \ + --build-arg GIT_TREE_STATE="$GIT_TREE_STATE" \ + --build-arg BUILD_DATE="$BUILD_DATE" \ + -t network-adapter:${{ github.sha }} . + # Plain `docker build`, not build-push-action, matches security.yml's + # single-arch report scan — build-and-push.yml is where per-arch, + # buildx-driven builds actually matter. + + - name: Trivy image scan (report) + run: make trivy-image IMAGE=network-adapter:${{ github.sha }} + + - name: Upload image findings + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: trivy-image.sarif + category: trivy-image + + - name: Assemble Trivy image PR comment + if: github.event_name == 'pull_request' + continue-on-error: true + run: | + { + echo "" + echo "### 🛡️ Trivy — image scan (HIGH,CRITICAL)" + echo "[View full run](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})" + echo + jq -r ' + def val(re; default): (capture(re) // {v: default}).v; + [ .runs[].results[]? ] as $found + | if ($found | length) == 0 then + "No HIGH or CRITICAL findings." + else + "| Package | Severity | Installed | Fixed in | Advisory |", + "|---|---|---|---|---|", + ( $found[] | .ruleId as $id | (.message.text // "") as $m | + "| `" + ($m | val("Package: (?[^\\n]+)"; "?")) + "` " + + "| " + ($m | val("Severity: (?[^\\n]+)"; "?")) + " " + + "| " + ($m | val("Installed Version: (?[^\\n]+)"; "?")) + " " + + "| " + ($m | val("Fixed Version: (?[^\\n]+)"; "—")) + " " + + "| [" + $id + "](" + ($m | val("Link: \\[[^]]+\\]\\((?[^)]+)\\)"; "")) + ") |" + ) + end + ' trivy-image.sarif + } > trivy-image-comment.md + + - name: Find existing Trivy image comment + if: github.event_name == 'pull_request' + continue-on-error: true + uses: peter-evans/find-comment@v3 + id: find-trivy-image-comment + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: "github-actions[bot]" + body-includes: "" + + - name: Comment Trivy image report on PR + if: github.event_name == 'pull_request' + continue-on-error: true + uses: peter-evans/create-or-update-comment@v4 + with: + comment-id: ${{ steps.find-trivy-image-comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body-path: trivy-image-comment.md + edit-mode: replace + + # Gate on the reports already produced rather than scanning a third and + # fourth time — logic lives in the Makefile's trivy-gate target so a + # local `make trivy-gate` checks the exact same two files this job + # just wrote. Last in the job, so a red build still leaves both reports + # behind. + - name: Gate on HIGH or CRITICAL findings + run: make trivy-gate || { echo "::error::HIGH or CRITICAL Trivy findings — see job log above"; exit 1; } diff --git a/.gitignore b/.gitignore index 618e9b42..48d66b76 100644 --- a/.gitignore +++ b/.gitignore @@ -143,6 +143,14 @@ create_benchmark_issues.sh # Ignore coverage output files coverage.out coverage.html +coverage-report.md + +# Makefile tool/build artifacts (golangci-lint, gotestsum, trivy binaries) +/bin/ +trivy-deps.sarif +trivy-image.sarif +trivy-deps-comment.md +trivy-image-comment.md # Ignore the schema directory used for testing /schemas/ diff --git a/Dockerfile.adapter b/Dockerfile.adapter index 41dd7ca8..0b1fd641 100644 --- a/Dockerfile.adapter +++ b/Dockerfile.adapter @@ -1,4 +1,23 @@ -FROM golang:1.26.1-bookworm AS builder +# syntax=docker/dockerfile:1 + +# DHI (Docker Hardened Images) requires `docker login dhi.io` first — a Docker +# subscription credential this build cannot supply. Both stages default to it +# because it's what CI and every shipped image use, but a local build without +# that subscription can override both build-args with public equivalents: +# +# docker build -f Dockerfile.adapter \ +# --build-arg BUILD_IMAGE=golang:1.26.1-bookworm \ +# --build-arg RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base:latest \ +# -t network-adapter:dev . +# +# Tags verified against github.com/docker-hardened-images/catalog +# image/golang/debian-12/1.26-dev.yaml and image/debian-base/debian-12/12.yaml. +# No cgo here, but the -dev variant's gcc/g++/make come bundled regardless — +# nothing extra to install for either the default or the public override. +ARG BUILD_IMAGE=dhi.io/golang:1.26-debian12-dev +ARG RUNTIME_IMAGE=dhi.io/debian-base:bookworm + +FROM ${BUILD_IMAGE} AS builder WORKDIR /workspace/app COPY cmd/adapter ./cmd/adapter @@ -15,16 +34,15 @@ ARG BUILD_DATE=unknown RUN go build -ldflags "-X github.com/beckn-one/beckn-onix/pkg/version.Version=${ONIX_VERSION} -X github.com/beckn-one/beckn-onix/pkg/version.GitCommit=${GIT_COMMIT} -X github.com/beckn-one/beckn-onix/pkg/version.GitTreeState=${GIT_TREE_STATE} -X github.com/beckn-one/beckn-onix/pkg/version.BuildDate=${BUILD_DATE}" -o server cmd/adapter/main.go -# Create a minimal runtime image -FROM cgr.dev/chainguard/wolfi-base:latest -# ✅ Alpine is removed; using minimal Debian +# Debian-based hardened runtime, run-as nonroot by default — kept explicit +# below since RUNTIME_IMAGE can be overridden to wolfi-base, which uses the +# same uid 65532 convention. A shell is required here: CMD below needs +# `sh -c` to expand $CONFIG_FILE. +FROM ${RUNTIME_IMAGE} WORKDIR /app -# Copy only the built binary and plugin COPY --from=builder /workspace/app/server . -# Expose port 8080 EXPOSE 8080 - -# Run the Go server with the config flag from environment variable. -CMD ["sh", "-c", "./server --config=${CONFIG_FILE}"] \ No newline at end of file +USER 65532:65532 +CMD ["sh", "-c", "./server --config=${CONFIG_FILE}"] diff --git a/Dockerfile.adapter-with-plugins b/Dockerfile.adapter-with-plugins index a7ba5e98..de97fcd6 100644 --- a/Dockerfile.adapter-with-plugins +++ b/Dockerfile.adapter-with-plugins @@ -1,11 +1,30 @@ -FROM golang:1.26.1-bookworm AS builder +# syntax=docker/dockerfile:1 + +# DHI (Docker Hardened Images) requires `docker login dhi.io` first — a Docker +# subscription credential this build cannot supply. Both stages default to it +# because it's what CI and every shipped image use, but a local build without +# that subscription can override both build-args with public equivalents: +# +# docker build -f Dockerfile.adapter-with-plugins \ +# --build-arg BUILD_IMAGE=golang:1.26.1-bookworm \ +# --build-arg RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base:latest \ +# -t network-adapter-plugins:dev . +# +# Tags verified against github.com/docker-hardened-images/catalog +# image/golang/debian-12/1.26-dev.yaml and image/debian-base/debian-12/12.yaml. +# -buildmode=plugin needs a C toolchain regardless of base — the -dev +# variant's gcc/g++/make come bundled, same as the public bookworm override. +ARG BUILD_IMAGE=dhi.io/golang:1.26-debian12-dev +ARG RUNTIME_IMAGE=dhi.io/debian-base:bookworm + +FROM ${BUILD_IMAGE} AS builder WORKDIR /workspace/app # Specifically copy only the necessary files and directories COPY cmd/adapter/ ./cmd/adapter/ -COPY core/ ./core/ -COPY pkg/ ./pkg/ +COPY core/ ./core +COPY pkg/ ./pkg COPY install/build-plugins.sh ./install/build-plugins.sh COPY install/scripts/version-vars.sh ./install/scripts/version-vars.sh COPY go.mod . @@ -30,8 +49,11 @@ RUN chmod +x install/build-plugins.sh && \ ONIX_VERSION="${ONIX_VERSION}" GIT_COMMIT="${GIT_COMMIT}" GIT_TREE_STATE="${GIT_TREE_STATE}" BUILD_DATE="${BUILD_DATE}" \ ./install/build-plugins.sh -# Create minimal runtime image -FROM cgr.dev/chainguard/wolfi-base:latest +# Debian-based hardened runtime, run-as nonroot by default — kept explicit +# below since RUNTIME_IMAGE can be overridden to wolfi-base, which uses the +# same uid 65532 convention. A shell is required here: CMD below needs +# `sh -c` to expand $CONFIG_FILE. +FROM ${RUNTIME_IMAGE} WORKDIR /app # Copy binary and plugins built with same Go version @@ -39,5 +61,5 @@ COPY --from=builder /workspace/app/server . COPY --from=builder /workspace/app/plugins ./plugins EXPOSE 8081 - +USER 65532:65532 CMD ["sh", "-c", "./server --config=${CONFIG_FILE}"] diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..0bd4ab21 --- /dev/null +++ b/Makefile @@ -0,0 +1,175 @@ +# OAN Network Adapter — build, test and toolchain targets. +# +# Mirrors discovery-service's Makefile shape (same target names, same +# run-tests/security/build-and-push workflows call these, not raw commands), +# adapted to this module: no DB, no sqlc/migrate, no separate tools/ module — +# golangci-lint, gotestsum and trivy install straight into bin/ via `go +# install`/curl, same as discovery-service does for gotestsum and trivy. + +GO ?= go +BIN_DIR := bin +IMAGE ?= network-adapter:dev + +# CI thresholds/pins live here, not duplicated into workflow env blocks — one +# source of truth for both a local `make` run and the GitHub Actions runner. +MIN_COVERAGE ?= 80 +BASE_REF ?= origin/main +SEVERITY ?= HIGH,CRITICAL +GOLANGCI_LINT_VERSION := v2.5.0 +GOTESTSUM_VERSION := v1.13.0 +TRIVY_VERSION := v0.74.0 + +GOLANGCI_LINT := $(BIN_DIR)/golangci-lint +GOTESTSUM := $(BIN_DIR)/gotestsum +TRIVY := $(BIN_DIR)/trivy + +.DEFAULT_GOAL := help + +## help: list the available targets +help: + @grep -hE '^## ' $(MAKEFILE_LIST) | sed 's/^## / /' | sort + +## build: compile the adapter binary +# Scoped to cmd/adapter, not ./... — pkg/plugin/implementation/*/cmd holds +# `package main` sources meant only for `go build -buildmode=plugin` +# (install/build-plugins.sh), with no func main() for an ordinary build. +build: + $(GO) build -trimpath -o $(BIN_DIR)/ ./cmd/adapter/... + +## test: run the unit and integration suites +test: + $(GO) test -race ./... + +## cover: run the suites and write a coverage profile +cover: + $(GO) test -race -covermode=atomic -coverprofile=coverage.out ./... + +## test-ci: run the suites through gotestsum — one line per package, coverage +## profile written alongside. What run-tests.yml calls; `make test` +## stays the plain everyday entrypoint. +test-ci: $(GOTESTSUM) + $(GOTESTSUM) --format pkgname --format-hide-empty-pkg -- \ + -race -coverprofile=coverage.out -covermode=atomic ./... + +## cover-diff: coverage restricted to files changed vs BASE_REF — a PR review +## needs the diff's number, not the whole repo's. On failure, +## names the changed files dragging the number down (worst first). +cover-diff: coverage.out + @CHANGED=$$(git diff --name-only --diff-filter=ACMR "$(BASE_REF)...HEAD" -- '*.go' | grep -v '_test\.go$$' || true); \ + if [ -z "$$CHANGED" ]; then \ + echo "📊 **Test Coverage: ✅ Passed** — not applicable, no changed Go files vs $(BASE_REF)" | tee coverage-report.md; \ + exit 0; \ + fi; \ + MODULE=$$($(GO) list -m); \ + RESULT=$$(echo "$$CHANGED" | awk -v mod="$$MODULE/" -v min="$(MIN_COVERAGE)" ' \ + NR==FNR { want[mod $$0] = 1; next } \ + { f = $$1; sub(/:.*/, "", f); if (!(f in want)) next; \ + tot[f] += $$(NF-1); if ($$NF > 0) cov[f] += $$(NF-1) } \ + END { \ + T = 0; C = 0; \ + for (f in tot) { \ + T += tot[f]; C += cov[f]; \ + p = int(cov[f] * 100 / tot[f]); \ + disp = f; sub("^" mod, "", disp); \ + if (p < min) print "FILE\t" p "\t" disp; \ + } \ + if (T == 0) { print "EMPTY"; exit } \ + print "TOTAL\t" int(C * 100 / T) \ + }' - coverage.out); \ + if echo "$$RESULT" | grep -q '^EMPTY$$'; then \ + echo "📊 **Test Coverage: ✅ Passed** — not applicable, changed files carry no coverable statements" | tee coverage-report.md; \ + exit 0; \ + fi; \ + PCT=$$(echo "$$RESULT" | awk -F'\t' '$$1=="TOTAL"{print $$2}'); \ + if [ "$$PCT" -lt "$(MIN_COVERAGE)" ]; then \ + BELOW=$$(echo "$$RESULT" | awk -F'\t' '$$1=="FILE"{printf "%s\t%s\n",$$2,$$3}' | sort -n); \ + TOTAL_BELOW=$$(echo "$$BELOW" | wc -l); \ + { \ + echo "📊 **Test Coverage: ❌ Failed** — $${PCT}% of changed lines covered, min $(MIN_COVERAGE)%"; \ + echo; \ + echo "| File | Coverage |"; \ + echo "|---|---|"; \ + echo "$$BELOW" | head -15 | awk -F'\t' '{printf "| `%s` | %s%% |\n", $$2, $$1}'; \ + [ "$$TOTAL_BELOW" -gt 15 ] && echo "| … | $$((TOTAL_BELOW - 15)) more file(s) below $(MIN_COVERAGE)% |"; \ + } > coverage-report.md; \ + else \ + echo "📊 **Test Coverage: ✅ Passed** — $${PCT}% of changed lines covered, min $(MIN_COVERAGE)%" > coverage-report.md; \ + fi; \ + cat coverage-report.md; \ + [ "$$PCT" -ge "$(MIN_COVERAGE)" ] + +## trivy-deps: dependency graph scan (T4), SARIF report. Catches what the +## image scan structurally cannot — a vulnerable module only the +## test suite imports, so it's never linked into the binary. +trivy-deps: $(TRIVY) + $(TRIVY) fs . --severity $(SEVERITY) --exit-code 0 \ + --format sarif --output trivy-deps.sarif + +TRIVY_IMAGE_SCAN = $(TRIVY) image $(IMAGE) --severity $(SEVERITY) + +## trivy-image: shipped image scan (T4), SARIF report. IMAGE names the ref. +trivy-image: $(TRIVY) + $(TRIVY_IMAGE_SCAN) --exit-code 0 --format sarif --output trivy-image.sarif + +## trivy-release-gate: same image scan as trivy-image, but exit 1 on a +## finding instead of writing a report — the pre-push +## release gate build-and-push.yml runs once per +## arch-tagged local image, before anything is pushed. +trivy-release-gate: $(TRIVY) + $(TRIVY_IMAGE_SCAN) --exit-code 1 --format table + +## trivy-gate: fail if either SARIF report already produced by a scan step +## carries a finding. Reads the reports rather than rescanning. +trivy-gate: + @fail=0; \ + for report in trivy-deps.sarif trivy-image.sarif; do \ + count=$$(jq '[.runs[].results[]?] | length' "$$report"); \ + echo "$${report}: $${count} $(SEVERITY)"; \ + if [ "$$count" -gt 0 ]; then \ + jq -r '.runs[].results[]? | "\(.ruleId) \(.message.text)"' "$$report"; \ + fail=1; \ + fi; \ + done; \ + exit $$fail + +## lint: vet, format check and static analysis +lint: $(GOLANGCI_LINT) + $(GOLANGCI_LINT) run ./... + $(GOLANGCI_LINT) fmt --diff ./... + +## fmt: apply the formatters lint checks for +fmt: $(GOLANGCI_LINT) + $(GOLANGCI_LINT) fmt ./... + +## docker: build the adapter image +docker: + docker build -f Dockerfile.adapter -t $(IMAGE) . + +## tools: build the pinned toolchain into bin/ +tools: $(GOLANGCI_LINT) $(GOTESTSUM) $(TRIVY) + +## clean: remove build output and coverage/scan artifacts +clean: + rm -rf $(BIN_DIR) coverage.out coverage-report.md trivy-deps.sarif trivy-image.sarif + +$(GOLANGCI_LINT): + @mkdir -p $(BIN_DIR) + GOBIN=$(abspath $(BIN_DIR)) $(GO) install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) + +# gotestsum is CI-only (see run-tests.yml), so it doesn't belong in the +# adapter's or the linter's dependency graph either one. +$(GOTESTSUM): + @mkdir -p $(BIN_DIR) + GOBIN=$(abspath $(BIN_DIR)) $(GO) install gotest.tools/gotestsum@$(GOTESTSUM_VERSION) + +# The prebuilt release binary, not `go install`: trivy's rpm-db parser needs +# cgo, and its module graph is comparable in size to golangci-lint's for a +# tool nothing here imports — the official install script is what +# aquasecurity itself recommends over building from source for exactly this. +$(TRIVY): + @mkdir -p $(BIN_DIR) + curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | \ + sh -s -- -b $(abspath $(BIN_DIR)) $(TRIVY_VERSION) + +.PHONY: help build test cover test-ci cover-diff lint fmt trivy-deps \ + trivy-image trivy-release-gate trivy-gate docker tools clean From f206f4fe893bf00ad07fd1eb28c66b3450165ef6 Mon Sep 17 00:00:00 2001 From: nisargabd Date: Thu, 3 Sep 2026 15:32:42 +0530 Subject: [PATCH 2/7] fix: switch adapter runtime to a glibc-only DHI image, drop the shell dependency [#999] security.yml's Trivy gate failed on unpatched CVEs in dhi.io/debian-base's bundled perl-base, ncurses, util-linux and zlib1g -- none of which the adapter uses. Neither can move to the fully static dhi.io/static image though: the adapter loads plugin .so files at runtime via Go's `plugin` package, which needs cgo and a real glibc dynamic linker to work at all. dhi.io/static's glibc variant is the middle ground -- keeps libc6 so plugin.Open still works, drops everything else the scan was flagging. That variant has no shell, so CMD's `sh -c "./server --config=$CONFIG_FILE"` can no longer expand the env var. Switched to an exec-form ENTRYPOINT and taught main.go to read CONFIG_FILE itself as the --config default. --- Dockerfile.adapter | 23 +++++++++++++++-------- Dockerfile.adapter-with-plugins | 20 ++++++++++++-------- cmd/adapter/main.go | 11 +++++++++-- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/Dockerfile.adapter b/Dockerfile.adapter index 0b1fd641..b3df00e8 100644 --- a/Dockerfile.adapter +++ b/Dockerfile.adapter @@ -11,11 +11,15 @@ # -t network-adapter:dev . # # Tags verified against github.com/docker-hardened-images/catalog -# image/golang/debian-12/1.26-dev.yaml and image/debian-base/debian-12/12.yaml. -# No cgo here, but the -dev variant's gcc/g++/make come bundled regardless — -# nothing extra to install for either the default or the public override. +# image/golang/debian-12/1.26-dev.yaml and image/static/debian-12/static-glibc.yaml. +# No cgo *required* for the plain build, but the adapter loads plugin .so +# files at runtime via Go's `plugin` package, which needs cgo and a real +# glibc dynamic linker regardless — so this stays a normal dynamic build, not +# -extldflags '-static'. The -dev variant's gcc/g++/make come bundled +# regardless — nothing extra to install for either the default or the public +# override. ARG BUILD_IMAGE=dhi.io/golang:1.26-debian12-dev -ARG RUNTIME_IMAGE=dhi.io/debian-base:bookworm +ARG RUNTIME_IMAGE=dhi.io/static:20250419-glibc-debian12 FROM ${BUILD_IMAGE} AS builder @@ -34,10 +38,11 @@ ARG BUILD_DATE=unknown RUN go build -ldflags "-X github.com/beckn-one/beckn-onix/pkg/version.Version=${ONIX_VERSION} -X github.com/beckn-one/beckn-onix/pkg/version.GitCommit=${GIT_COMMIT} -X github.com/beckn-one/beckn-onix/pkg/version.GitTreeState=${GIT_TREE_STATE} -X github.com/beckn-one/beckn-onix/pkg/version.BuildDate=${BUILD_DATE}" -o server cmd/adapter/main.go -# Debian-based hardened runtime, run-as nonroot by default — kept explicit +# glibc-only runtime — no shell, no perl/ncurses/util-linux (the packages +# that were carrying unpatched CVEs on the fuller debian-base image), but +# keeps libc6 so plugin.Open's dynamic linking still works. Explicit USER # below since RUNTIME_IMAGE can be overridden to wolfi-base, which uses the -# same uid 65532 convention. A shell is required here: CMD below needs -# `sh -c` to expand $CONFIG_FILE. +# same uid 65532 convention. FROM ${RUNTIME_IMAGE} WORKDIR /app @@ -45,4 +50,6 @@ COPY --from=builder /workspace/app/server . EXPOSE 8080 USER 65532:65532 -CMD ["sh", "-c", "./server --config=${CONFIG_FILE}"] +# Exec form, not `sh -c` — this base has no shell. main.go reads CONFIG_FILE +# itself as the --config default, so no shell expansion is needed here. +ENTRYPOINT ["/app/server"] diff --git a/Dockerfile.adapter-with-plugins b/Dockerfile.adapter-with-plugins index de97fcd6..043a91e6 100644 --- a/Dockerfile.adapter-with-plugins +++ b/Dockerfile.adapter-with-plugins @@ -11,11 +11,12 @@ # -t network-adapter-plugins:dev . # # Tags verified against github.com/docker-hardened-images/catalog -# image/golang/debian-12/1.26-dev.yaml and image/debian-base/debian-12/12.yaml. -# -buildmode=plugin needs a C toolchain regardless of base — the -dev -# variant's gcc/g++/make come bundled, same as the public bookworm override. +# image/golang/debian-12/1.26-dev.yaml and image/static/debian-12/static-glibc.yaml. +# -buildmode=plugin, and plugin.Open at runtime, both need a C toolchain and +# a real glibc dynamic linker — the -dev variant's gcc/g++/make come +# bundled, same as the public bookworm override. ARG BUILD_IMAGE=dhi.io/golang:1.26-debian12-dev -ARG RUNTIME_IMAGE=dhi.io/debian-base:bookworm +ARG RUNTIME_IMAGE=dhi.io/static:20250419-glibc-debian12 FROM ${BUILD_IMAGE} AS builder @@ -49,10 +50,11 @@ RUN chmod +x install/build-plugins.sh && \ ONIX_VERSION="${ONIX_VERSION}" GIT_COMMIT="${GIT_COMMIT}" GIT_TREE_STATE="${GIT_TREE_STATE}" BUILD_DATE="${BUILD_DATE}" \ ./install/build-plugins.sh -# Debian-based hardened runtime, run-as nonroot by default — kept explicit +# glibc-only runtime — no shell, no perl/ncurses/util-linux (the packages +# that were carrying unpatched CVEs on the fuller debian-base image), but +# keeps libc6 so plugin.Open's dynamic linking still works. Explicit USER # below since RUNTIME_IMAGE can be overridden to wolfi-base, which uses the -# same uid 65532 convention. A shell is required here: CMD below needs -# `sh -c` to expand $CONFIG_FILE. +# same uid 65532 convention. FROM ${RUNTIME_IMAGE} WORKDIR /app @@ -62,4 +64,6 @@ COPY --from=builder /workspace/app/plugins ./plugins EXPOSE 8081 USER 65532:65532 -CMD ["sh", "-c", "./server --config=${CONFIG_FILE}"] +# Exec form, not `sh -c` — this base has no shell. main.go reads CONFIG_FILE +# itself as the --config default, so no shell expansion is needed here. +ENTRYPOINT ["/app/server"] diff --git a/cmd/adapter/main.go b/cmd/adapter/main.go index f74d6fb0..09a88226 100644 --- a/cmd/adapter/main.go +++ b/cmd/adapter/main.go @@ -63,8 +63,15 @@ var configPath string var runFunc = run func main() { - // Define and parse command-line flags. - flag.StringVar(&configPath, "config", "../../config/onix/adapter.yaml", "Path to the configuration file") + // Define and parse command-line flags. CONFIG_FILE seeds the default so + // a shell-less container entrypoint (no `sh -c` to expand it into + // --config) can still select a config file via env var; --config still + // overrides it explicitly when passed. + defaultConfig := "../../config/onix/adapter.yaml" + if v := os.Getenv("CONFIG_FILE"); v != "" { + defaultConfig = v + } + flag.StringVar(&configPath, "config", defaultConfig, "Path to the configuration file") flag.Parse() // Use custom log for initial setup messages. From b6ca6a2508240102f3c6a03df865f73305e19f88 Mon Sep 17 00:00:00 2001 From: nisargabd Date: Thu, 3 Sep 2026 15:39:33 +0530 Subject: [PATCH 3/7] fix: bump golang.org/x/crypto and google.golang.org/grpc to close known CVEs [#999] security.yml's trivy-deps scan flagged CVE-2026-56854 (x/crypto, CRITICAL) and CVE-2026-84304 (grpc, HIGH), both with fixed versions already published upstream. --- go.mod | 22 +++++++++++----------- go.sum | 54 ++++++++++++++++++++++++++++-------------------------- 2 files changed, 39 insertions(+), 37 deletions(-) diff --git a/go.mod b/go.mod index fe8b8670..63fed0f4 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.26.1 require ( github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 - golang.org/x/crypto v0.54.0 + golang.org/x/crypto v0.55.0 ) require github.com/stretchr/testify v1.11.1 @@ -19,7 +19,7 @@ require ( require github.com/zenazn/pkcs7pad v0.0.0-20170308005700-253a5b1f0e03 -require golang.org/x/text v0.40.0 // indirect +require golang.org/x/text v0.41.0 // indirect require ( github.com/agnivade/levenshtein v1.2.1 // indirect @@ -80,11 +80,11 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.56.0 // indirect + golang.org/x/net v0.57.0 // indirect golang.org/x/sys v0.47.0 // indirect golang.org/x/time v0.15.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260427160629-7cedc36a6bc4 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/protobuf v1.36.11 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) @@ -107,20 +107,20 @@ require ( github.com/redis/go-redis/v9 v9.19.0 github.com/rs/zerolog v1.35.1 go.opentelemetry.io/contrib/instrumentation/runtime v0.68.0 - go.opentelemetry.io/otel v1.43.0 + go.opentelemetry.io/otel v1.44.0 go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 go.opentelemetry.io/otel/exporters/prometheus v0.65.0 go.opentelemetry.io/otel/log v0.19.0 - go.opentelemetry.io/otel/metric v1.43.0 - go.opentelemetry.io/otel/sdk v1.43.0 + go.opentelemetry.io/otel/metric v1.44.0 + go.opentelemetry.io/otel/sdk v1.44.0 go.opentelemetry.io/otel/sdk/log v0.19.0 - go.opentelemetry.io/otel/sdk/metric v1.43.0 - go.opentelemetry.io/otel/trace v1.43.0 + go.opentelemetry.io/otel/sdk/metric v1.44.0 + go.opentelemetry.io/otel/trace v1.44.0 go.uber.org/automaxprocs v1.6.0 golang.org/x/sync v0.22.0 - google.golang.org/grpc v1.82.1 + google.golang.org/grpc v1.83.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 055511f8..3f7b7a09 100644 --- a/go.sum +++ b/go.sum @@ -219,8 +219,8 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/runtime v0.68.0 h1:jhVIQEprwUTV+KfzzliLidclhoTOoHTgdz96kAyR8mU= go.opentelemetry.io/contrib/instrumentation/runtime v0.68.0/go.mod h1:4HsdbLUbernaTnA8CNaNE+1g026SciXb3juRYe3l8EY= -go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= -go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 h1:Dn8rkudDzY6KV9dr/D/bTUuWgqDf9xe0rr4G2elrn0Y= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0/go.mod h1:gMk9F0xDgyN9M/3Ed5Y1wKcx/9mlU91NXY2SNq7RQuU= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 h1:8UQVDcZxOJLtX6gxtDt3vY2WTgvZqMQRzjsqiIHQdkc= @@ -233,18 +233,20 @@ go.opentelemetry.io/otel/exporters/prometheus v0.65.0 h1:jOveH/b4lU9HT7y+Gfamf18 go.opentelemetry.io/otel/exporters/prometheus v0.65.0/go.mod h1:i1P8pcumauPtUI4YNopea1dhzEMuEqWP1xoUZDylLHo= go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4= go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk= -go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= -go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= -go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= -go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/metric/x v0.66.0 h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA= +go.opentelemetry.io/otel/metric/x v0.66.0/go.mod h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko= go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg= go.opentelemetry.io/otel/sdk/log/logtest v0.19.0 h1:BEbF7ZBB6qQloV/Ub1+3NQoOUnVtcGkU3XX4Ws3GQfk= go.opentelemetry.io/otel/sdk/log/logtest v0.19.0/go.mod h1:Lua81/3yM0wOmoHTokLj9y9ADeA02v1naRrVrkAZuKk= -go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= -go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= -go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= -go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -257,30 +259,30 @@ go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= -golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= -golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= -golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= -golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= -golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= +golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= +golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= +golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= +golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= -golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= -golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= -golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= +golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= +golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/genproto/googleapis/api v0.0.0-20260427160629-7cedc36a6bc4 h1:yOzSCGPx+cp5VO7IxvZ9SBFF7j1tZVcNtlHR2iYKtVo= -google.golang.org/genproto/googleapis/api v0.0.0-20260427160629-7cedc36a6bc4/go.mod h1:Q9HWtNeE7tM9npdIsEvqXj1QJIvVoeAV3rtXtS715Cw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 h1:tEkOQcXgF6dH1G+MVKZrfpYvozGrzb91k6ha7jireSM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= -google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.83.1 h1:HIO0+BEtBP6soyqvqC8sNUjZ7bTs+0hFQuFF+RAy++Y= +google.golang.org/grpc v1.83.1/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 63862e675f5f38d3e2145f8a304c7db605b833ac Mon Sep 17 00:00:00 2001 From: nisargabd Date: Thu, 3 Sep 2026 15:56:01 +0530 Subject: [PATCH 4/7] fix: disable Terraform deploy's push trigger [#999] Ran on every push including this branch and always failed here -- missing Gerrit credentials for the private Terraform-CICD repo it clones. workflow_dispatch stays, so it's still runnable by hand; kept, not deleted, pending a decision on whether it's folded into build-and-push.yml or removed outright. --- .github/workflows/onix-gcp-terraform-deploy.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/onix-gcp-terraform-deploy.yml b/.github/workflows/onix-gcp-terraform-deploy.yml index 478979be..4d35fe94 100644 --- a/.github/workflows/onix-gcp-terraform-deploy.yml +++ b/.github/workflows/onix-gcp-terraform-deploy.yml @@ -1,7 +1,9 @@ name: Terraform Deploy to GCP on: - push: + # push trigger disabled — this always fails (missing Gerrit credentials in + # this repo) and ran on every push, including unrelated branches. Kept as + # manual-only until it's confirmed dead or folded into build-and-push.yml. workflow_dispatch: # Manual triggerr jobs: From 45a339e4af608e05ee9f386cb6b5d07a9ece9364 Mon Sep 17 00:00:00 2001 From: nisargabd Date: Thu, 3 Sep 2026 16:37:32 +0530 Subject: [PATCH 5/7] chore: keep golang.org/x/crypto and google.golang.org/grpc at prior versions [#999] This is CI setup, not a dependency-bump PR -- the two CVEs trivy-deps flags (CVE-2026-56854, CVE-2026-84304) are real and the scan catching them is working as intended; the actual bump is deferred to its own change. --- go.mod | 22 +++++++++++----------- go.sum | 54 ++++++++++++++++++++++++++---------------------------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/go.mod b/go.mod index 63fed0f4..fe8b8670 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.26.1 require ( github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 - golang.org/x/crypto v0.55.0 + golang.org/x/crypto v0.54.0 ) require github.com/stretchr/testify v1.11.1 @@ -19,7 +19,7 @@ require ( require github.com/zenazn/pkcs7pad v0.0.0-20170308005700-253a5b1f0e03 -require golang.org/x/text v0.41.0 // indirect +require golang.org/x/text v0.40.0 // indirect require ( github.com/agnivade/levenshtein v1.2.1 // indirect @@ -80,11 +80,11 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.57.0 // indirect + golang.org/x/net v0.56.0 // indirect golang.org/x/sys v0.47.0 // indirect golang.org/x/time v0.15.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260427160629-7cedc36a6bc4 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 // indirect google.golang.org/protobuf v1.36.11 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) @@ -107,20 +107,20 @@ require ( github.com/redis/go-redis/v9 v9.19.0 github.com/rs/zerolog v1.35.1 go.opentelemetry.io/contrib/instrumentation/runtime v0.68.0 - go.opentelemetry.io/otel v1.44.0 + go.opentelemetry.io/otel v1.43.0 go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 go.opentelemetry.io/otel/exporters/prometheus v0.65.0 go.opentelemetry.io/otel/log v0.19.0 - go.opentelemetry.io/otel/metric v1.44.0 - go.opentelemetry.io/otel/sdk v1.44.0 + go.opentelemetry.io/otel/metric v1.43.0 + go.opentelemetry.io/otel/sdk v1.43.0 go.opentelemetry.io/otel/sdk/log v0.19.0 - go.opentelemetry.io/otel/sdk/metric v1.44.0 - go.opentelemetry.io/otel/trace v1.44.0 + go.opentelemetry.io/otel/sdk/metric v1.43.0 + go.opentelemetry.io/otel/trace v1.43.0 go.uber.org/automaxprocs v1.6.0 golang.org/x/sync v0.22.0 - google.golang.org/grpc v1.83.1 + google.golang.org/grpc v1.82.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 3f7b7a09..055511f8 100644 --- a/go.sum +++ b/go.sum @@ -219,8 +219,8 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/runtime v0.68.0 h1:jhVIQEprwUTV+KfzzliLidclhoTOoHTgdz96kAyR8mU= go.opentelemetry.io/contrib/instrumentation/runtime v0.68.0/go.mod h1:4HsdbLUbernaTnA8CNaNE+1g026SciXb3juRYe3l8EY= -go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= -go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 h1:Dn8rkudDzY6KV9dr/D/bTUuWgqDf9xe0rr4G2elrn0Y= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0/go.mod h1:gMk9F0xDgyN9M/3Ed5Y1wKcx/9mlU91NXY2SNq7RQuU= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 h1:8UQVDcZxOJLtX6gxtDt3vY2WTgvZqMQRzjsqiIHQdkc= @@ -233,20 +233,18 @@ go.opentelemetry.io/otel/exporters/prometheus v0.65.0 h1:jOveH/b4lU9HT7y+Gfamf18 go.opentelemetry.io/otel/exporters/prometheus v0.65.0/go.mod h1:i1P8pcumauPtUI4YNopea1dhzEMuEqWP1xoUZDylLHo= go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4= go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk= -go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= -go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= -go.opentelemetry.io/otel/metric/x v0.66.0 h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA= -go.opentelemetry.io/otel/metric/x v0.66.0/go.mod h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk= -go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= -go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko= go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg= go.opentelemetry.io/otel/sdk/log/logtest v0.19.0 h1:BEbF7ZBB6qQloV/Ub1+3NQoOUnVtcGkU3XX4Ws3GQfk= go.opentelemetry.io/otel/sdk/log/logtest v0.19.0/go.mod h1:Lua81/3yM0wOmoHTokLj9y9ADeA02v1naRrVrkAZuKk= -go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= -go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= -go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= -go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -259,30 +257,30 @@ go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= -golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= -golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= -golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= -golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= -golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= +golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= -golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= +golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= -golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= -golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= -google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.83.1 h1:HIO0+BEtBP6soyqvqC8sNUjZ7bTs+0hFQuFF+RAy++Y= -google.golang.org/grpc v1.83.1/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ= +google.golang.org/genproto/googleapis/api v0.0.0-20260427160629-7cedc36a6bc4 h1:yOzSCGPx+cp5VO7IxvZ9SBFF7j1tZVcNtlHR2iYKtVo= +google.golang.org/genproto/googleapis/api v0.0.0-20260427160629-7cedc36a6bc4/go.mod h1:Q9HWtNeE7tM9npdIsEvqXj1QJIvVoeAV3rtXtS715Cw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 h1:tEkOQcXgF6dH1G+MVKZrfpYvozGrzb91k6ha7jireSM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= +google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From ef9089e54457449ad26c14f769935632c47f3d8b Mon Sep 17 00:00:00 2001 From: nisargabd Date: Thu, 3 Sep 2026 17:19:06 +0530 Subject: [PATCH 6/7] fix: scope the DHI runtime switch to the plugins image only [#999] Dockerfile.adapter goes back to the original public base images -- Dockerfile.adapter-with-plugins is the one actually deployed, so that's the one that needs the CVE fix. Keeps dhi.io/static's glibc-only variant (clears the unpatched perl-base/ncurses/util-linux/zlib1g CVEs, keeps libc6 so plugin.Open still works) but drops the main.go change entirely: Deployment/deployment.yaml now passes --config=$(CONFIG_FILE) via args, letting the kubelet do the substitution instead of a shell inside the container. --- Deployment/deployment.yaml | 5 +++++ Dockerfile.adapter | 23 ++++++++--------------- Dockerfile.adapter-with-plugins | 7 +++++-- cmd/adapter/main.go | 11 ++--------- 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/Deployment/deployment.yaml b/Deployment/deployment.yaml index 561fdb5a..443ac03c 100644 --- a/Deployment/deployment.yaml +++ b/Deployment/deployment.yaml @@ -19,6 +19,11 @@ spec: containers: - name: onix-adapter image: "asia-south1-docker.pkg.dev/trusty-relic-370809/onix-adapter-cicd/beckn-onix:latest" #------ + # $(CONFIG_FILE) is expanded by the kubelet against the env below + # before the container starts -- the image's shell-less DHI base + # has no `sh -c` to do that substitution itself. + args: + - "--config=$(CONFIG_FILE)" ports: - containerPort: 8080 env: diff --git a/Dockerfile.adapter b/Dockerfile.adapter index b3df00e8..0b1fd641 100644 --- a/Dockerfile.adapter +++ b/Dockerfile.adapter @@ -11,15 +11,11 @@ # -t network-adapter:dev . # # Tags verified against github.com/docker-hardened-images/catalog -# image/golang/debian-12/1.26-dev.yaml and image/static/debian-12/static-glibc.yaml. -# No cgo *required* for the plain build, but the adapter loads plugin .so -# files at runtime via Go's `plugin` package, which needs cgo and a real -# glibc dynamic linker regardless — so this stays a normal dynamic build, not -# -extldflags '-static'. The -dev variant's gcc/g++/make come bundled -# regardless — nothing extra to install for either the default or the public -# override. +# image/golang/debian-12/1.26-dev.yaml and image/debian-base/debian-12/12.yaml. +# No cgo here, but the -dev variant's gcc/g++/make come bundled regardless — +# nothing extra to install for either the default or the public override. ARG BUILD_IMAGE=dhi.io/golang:1.26-debian12-dev -ARG RUNTIME_IMAGE=dhi.io/static:20250419-glibc-debian12 +ARG RUNTIME_IMAGE=dhi.io/debian-base:bookworm FROM ${BUILD_IMAGE} AS builder @@ -38,11 +34,10 @@ ARG BUILD_DATE=unknown RUN go build -ldflags "-X github.com/beckn-one/beckn-onix/pkg/version.Version=${ONIX_VERSION} -X github.com/beckn-one/beckn-onix/pkg/version.GitCommit=${GIT_COMMIT} -X github.com/beckn-one/beckn-onix/pkg/version.GitTreeState=${GIT_TREE_STATE} -X github.com/beckn-one/beckn-onix/pkg/version.BuildDate=${BUILD_DATE}" -o server cmd/adapter/main.go -# glibc-only runtime — no shell, no perl/ncurses/util-linux (the packages -# that were carrying unpatched CVEs on the fuller debian-base image), but -# keeps libc6 so plugin.Open's dynamic linking still works. Explicit USER +# Debian-based hardened runtime, run-as nonroot by default — kept explicit # below since RUNTIME_IMAGE can be overridden to wolfi-base, which uses the -# same uid 65532 convention. +# same uid 65532 convention. A shell is required here: CMD below needs +# `sh -c` to expand $CONFIG_FILE. FROM ${RUNTIME_IMAGE} WORKDIR /app @@ -50,6 +45,4 @@ COPY --from=builder /workspace/app/server . EXPOSE 8080 USER 65532:65532 -# Exec form, not `sh -c` — this base has no shell. main.go reads CONFIG_FILE -# itself as the --config default, so no shell expansion is needed here. -ENTRYPOINT ["/app/server"] +CMD ["sh", "-c", "./server --config=${CONFIG_FILE}"] diff --git a/Dockerfile.adapter-with-plugins b/Dockerfile.adapter-with-plugins index 043a91e6..6f72a4c0 100644 --- a/Dockerfile.adapter-with-plugins +++ b/Dockerfile.adapter-with-plugins @@ -64,6 +64,9 @@ COPY --from=builder /workspace/app/plugins ./plugins EXPOSE 8081 USER 65532:65532 -# Exec form, not `sh -c` — this base has no shell. main.go reads CONFIG_FILE -# itself as the --config default, so no shell expansion is needed here. +# Exec form, not `sh -c` — this base has no shell, and no Go code reads +# CONFIG_FILE either. The deployment layer resolves it instead: Kubernetes +# expands $(CONFIG_FILE) in args itself before exec'ing the container (see +# Deployment/deployment.yaml) -- no shell involved on either side. A plain +# `docker run` without that substitution needs an explicit --config flag. ENTRYPOINT ["/app/server"] diff --git a/cmd/adapter/main.go b/cmd/adapter/main.go index 09a88226..f74d6fb0 100644 --- a/cmd/adapter/main.go +++ b/cmd/adapter/main.go @@ -63,15 +63,8 @@ var configPath string var runFunc = run func main() { - // Define and parse command-line flags. CONFIG_FILE seeds the default so - // a shell-less container entrypoint (no `sh -c` to expand it into - // --config) can still select a config file via env var; --config still - // overrides it explicitly when passed. - defaultConfig := "../../config/onix/adapter.yaml" - if v := os.Getenv("CONFIG_FILE"); v != "" { - defaultConfig = v - } - flag.StringVar(&configPath, "config", defaultConfig, "Path to the configuration file") + // Define and parse command-line flags. + flag.StringVar(&configPath, "config", "../../config/onix/adapter.yaml", "Path to the configuration file") flag.Parse() // Use custom log for initial setup messages. From 53d17a75e7ecf6ad617a62668d124518dc13ff72 Mon Sep 17 00:00:00 2001 From: nisargabd Date: Thu, 3 Sep 2026 17:25:16 +0530 Subject: [PATCH 7/7] fix: build and scan Dockerfile.adapter-with-plugins, not Dockerfile.adapter [#999] security.yml and build-and-push.yml still pointed at Dockerfile.adapter, which we just reverted back to the original, unpatched base images -- so the security gate was scanning the wrong Dockerfile and the CVE fix never took effect. Dockerfile.adapter-with-plugins is the one actually deployed and the one carrying the DHI glibc-only runtime fix. --- .github/workflows/build-and-push.yml | 2 +- .github/workflows/security.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index 4ff2479f..2d49bbcf 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -153,7 +153,7 @@ jobs: uses: docker/build-push-action@v6 with: context: . - file: Dockerfile.adapter + file: Dockerfile.adapter-with-plugins platforms: ${{ matrix.platform }} build-args: | ONIX_VERSION=${{ env.ONIX_VERSION }} diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index f4a66049..cfc42c5c 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -139,7 +139,7 @@ jobs: - name: Build image run: | source install/scripts/version-vars.sh - docker build -f Dockerfile.adapter \ + docker build -f Dockerfile.adapter-with-plugins \ --build-arg ONIX_VERSION="$ONIX_VERSION" \ --build-arg GIT_COMMIT="$GIT_COMMIT" \ --build-arg GIT_TREE_STATE="$GIT_TREE_STATE" \