diff --git a/.commitlintrc.yml b/.commitlintrc.yml index 9534020..fe2f03d 100644 --- a/.commitlintrc.yml +++ b/.commitlintrc.yml @@ -10,7 +10,7 @@ extends: # feat(docker): add versioned Node stage # fix: correct TruffleHog tag format # docs: update pinning strategy guidance -# chore(deps): bump Trivy to 0.69.3 +# chore(deps): bump TruffleHog to 3.93.8 # ci: add commit-lint workflow rules: diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9b19124..e24f434 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -43,10 +43,13 @@ updates: cooldown: default-days: 7 - # Main Dockerfile — tracks aquasec/trivy, trufflesecurity/trufflehog, - # ghcr.io/astral-sh/uv, and the python base image. + # Main Dockerfile — tracks trufflesecurity/trufflehog, ghcr.io/astral-sh/uv, + # and the python base image. # NOTE: OPENGREP_VERSION is not trackable via Dependabot (no Docker image); # update it manually in the Dockerfile ARG. + # NOTE: trivy is deliberately NOT tracked here — it comes from Socket's own + # build (ghcr.io/socketdev/trivy, digest-pinned) and is updated by that + # release process, never bumped independently. - package-ecosystem: "docker" directory: "/" schedule: @@ -56,7 +59,6 @@ updates: - dependency-name: "python" - dependency-name: "ghcr.io/astral-sh/uv" - dependency-name: "trufflesecurity/trufflehog" - - dependency-name: "aquasec/trivy" groups: docker-main-minor-patch: patterns: @@ -74,7 +76,7 @@ updates: - "docker" commit-message: prefix: "chore" - include: "scope" # → chore(deps): bump trivy from 0.69.2 to 0.69.3 + include: "scope" # → chore(deps): bump trufflehog from 3.93.7 to 3.93.8 cooldown: default-days: 7 @@ -89,7 +91,6 @@ updates: - dependency-name: "golang" - dependency-name: "securego/gosec" - dependency-name: "trufflesecurity/trufflehog" - - dependency-name: "aquasec/trivy" groups: docker-app-tests-minor-patch: patterns: diff --git a/.github/workflows/_docker-pipeline.yml b/.github/workflows/_docker-pipeline.yml index 44acfb2..f338525 100644 --- a/.github/workflows/_docker-pipeline.yml +++ b/.github/workflows/_docker-pipeline.yml @@ -79,6 +79,11 @@ on: jobs: pipeline: runs-on: ${{ inputs.runs_on }} + # Push mode binds the `publish` environment so the environment-scoped + # Docker Hub secrets resolve (callers use `secrets: inherit`). Test mode + # (push: false) binds no environment — PR branches would violate the + # environment's deployment policy. + environment: ${{ inputs.push && 'publish' || '' }} timeout-minutes: 60 steps: @@ -95,9 +100,11 @@ jobs: - name: 🔨 Set up Docker Buildx uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 - # GHCR login runs before the build — needed to pull ghcr.io/astral-sh/uv. + # GHCR login runs before the build in EVERY mode (not just push): the + # trivy build stage pulls the private ghcr.io/socketdev/trivy image, so + # unauthenticated PR builds would fail at FROM. Callers must grant + # `packages: read`. - name: Login to GHCR - if: inputs.push uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4.5.1 with: registry: ghcr.io diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml index 4c8a906..d779579 100644 --- a/.github/workflows/commit-lint.yml +++ b/.github/workflows/commit-lint.yml @@ -46,6 +46,6 @@ jobs: echo " feat(docker): Add versioned Node stage" echo " fix: Correct TruffleHog tag format" echo " docs: Update pinning strategy guidance" - echo " chore(deps): Bump Trivy to 0.69.3" + echo " chore(deps): Bump TruffleHog to 3.93.8" exit 1 fi diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index a5748a9..3a8cc31 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -281,10 +281,12 @@ jobs: uses: ./.github/workflows/_docker-pipeline.yml permissions: contents: read + packages: read # pull the private Socket-built trivy base image with: name: socket-basics-app-tests dockerfile: app_tests/Dockerfile - context: . + # app_tests/ is its own build context (its pyproject/uv.lock, fixture apps). + context: app_tests check_set: app-tests push: false diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 387d4b0..be43d84 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -15,9 +15,12 @@ name: publish-docker # registry, distinguished by tag suffix: 2.0.0 (main), 2.0.0-heavy (heavy). # See docs/github-action.md → "Pinning strategies" for the full rationale. # -# Required repository secrets: -# DOCKERHUB_USERNAME — Docker Hub account name +# Required secrets — scoped to the `publish` environment (deployment policy: +# branch `main` + tags `v*`), not repo-level: +# DOCKERHUB_USERNAME — Docker Hub account name (also the registry namespace) # DOCKERHUB_TOKEN — Docker Hub access token (read/write) +# Publishing jobs bind `environment: publish` to resolve them; the reusable +# pipeline binds it only in push mode (see _docker-pipeline.yml). on: push: @@ -149,7 +152,10 @@ jobs: check_set: heavy arch: arm64 runs_on: ubuntu-24.04-arm - uses: ./.github/workflows/_docker-pipeline.yml + # zizmor: ignore[secrets-inherit] — required: environment-scoped secrets + # cannot be passed via an explicit workflow-call mapping (they only resolve + # on the environment-bound job inside the called same-repo workflow). + uses: ./.github/workflows/_docker-pipeline.yml # zizmor: ignore[secrets-inherit] with: name: ${{ matrix.image }} dockerfile: ${{ matrix.dockerfile }} @@ -164,20 +170,25 @@ jobs: push: true version: ${{ needs.resolve-version.outputs.version }} ref: ${{ needs.resolve-version.outputs.ref }} - secrets: - DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} - DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} + # Environment secrets can't be passed from a workflow-call job (no + # `environment:` allowed here); inherit lets the reusable workflow's + # environment-bound job resolve them itself. + secrets: inherit # ── Job 3: Merge per-arch digests into a multi-arch manifest list ────────── - # Floating major version tags (v2 → latest v2.x.y) are intentionally omitted. - # Mutable tags are structurally equivalent to :latest and inappropriate for a - # security tool. Users should pin to an exact version and use Dependabot. + # Tags: exact immutable version (X.Y.Z / X.Y.Z-heavy) plus the floating + # `latest` / `latest-heavy` convenience aliases. Version tags are immutable + # registry-side (Docker Hub immutable-tag rule: ^\d+\.\d+\.\d+(-heavy)?$); + # `latest` deliberately floats. Consumers needing reproducibility should pin + # the exact version or digest (docs/github-action.md → "Pinning strategies"). + # Floating MAJOR tags (v2 → latest v2.x.y) remain intentionally omitted. merge-manifests: name: merge-manifests (${{ matrix.variant }}) needs: [resolve-version, build-test-push] permissions: contents: read packages: write + environment: publish # Docker Hub secrets are environment-scoped runs-on: ubuntu-latest strategy: fail-fast: false @@ -221,16 +232,22 @@ jobs: images: | ghcr.io/socketdev/socket-basics ${{ secrets.DOCKERHUB_USERNAME }}/socket-basics - # Disable the automatic :latest tag — metadata-action adds it by default - # for semver tag pushes. Mutable tags are inappropriate for a security tool. - # The variant suffix yields 2.2.0 for the main image, 2.2.0-heavy for heavy. + # `latest` (and `latest-heavy` via the variant suffix) float to the + # newest release; exact version tags stay immutable registry-side. + # The variant suffix yields X.Y.Z for the main image, X.Y.Z-heavy for heavy. flavor: | - latest=false - suffix=${{ matrix.tag_suffix }} + latest=true + # onlatest applies the variant suffix to the latest alias too — + # without it both variants would publish a bare, racing `latest` + # and `latest-heavy` would never exist. + suffix=${{ matrix.tag_suffix }},onlatest=true tags: | - # Tag push (v2.0.0) → exact immutable version tag only. + # Tag push (vX.Y.Z) → exact immutable version tag + latest alias. type=semver,pattern={{version}} - # workflow_dispatch re-publish → use the version input directly + # workflow_dispatch re-publish → use the version input directly. + # NOTE: re-pushing an already-published version tag is rejected by + # the registry's immutable-tag rule — dispatch mode is for recovery + # when tags never landed (it also repoints `latest`). type=raw,value=${{ needs.resolve-version.outputs.version }},enable=${{ github.event_name == 'workflow_dispatch' }} - name: 🧬 Create multi-arch manifest list diff --git a/.github/workflows/smoke-test.yml b/.github/workflows/smoke-test.yml index 025ae14..46e58df 100644 --- a/.github/workflows/smoke-test.yml +++ b/.github/workflows/smoke-test.yml @@ -27,6 +27,7 @@ on: permissions: contents: read + packages: read # pull the private Socket-built trivy base image concurrency: group: smoke-test-${{ github.ref }} diff --git a/Dockerfile b/Dockerfile index 6ea5bb9..9447fa4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,26 @@ # ─── Global version pins (single source of truth) ──────────────────────────── # Dependabot tracks all ARGs below via the FROM lines that reference them. -# To override at build time: docker build --build-arg TRIVY_VERSION=0.70.0 . +# To override at build time: docker build --build-arg TRUFFLEHOG_VERSION=3.93.8 . # # Dependabot-trackable (each has a corresponding FROM : stage): ARG PYTHON_VERSION=3.12 -ARG TRUFFLEHOG_VERSION=3.93.8 -ARG TRIVY_VERSION=0.69.3 -ARG UV_VERSION=0.10.11 +ARG TRUFFLEHOG_VERSION=3.96.0 +ARG UV_VERSION=0.12.1 # # NOT Dependabot-trackable (no official Docker image with a stable binary path): -ARG OPENGREP_VERSION=v1.16.5 +ARG OPENGREP_VERSION=v1.26.0 +# +# NOT Dependabot-trackable — Socket-built Trivy, rebuilt from unmodified upstream +# source and published by Socket's own release pipeline. Pinned by digest; both +# ARGs are updated together by that release process, never bumped independently. +# Building requires pull access to the registry; contributors without it can +# override, e.g.: docker build --build-arg TRIVY_IMAGE=aquasec/trivy:0.73.0 . +# TRIVY_VERSION feeds the image label — keep it in sync with the TRIVY_IMAGE tag. +ARG TRIVY_VERSION=0.73.0 +ARG TRIVY_IMAGE=ghcr.io/socketdev/trivy:0.73.0@sha256:e3d9d5f10250cb73b0ea9446ae1191c0f2da2f5e6173eac08a840b1812f02e0b -# ─── Stage: trivy (Dependabot-trackable) ────────────────────────────────────── -# FROM aquasec/trivy:${TRIVY_VERSION} AS trivy +# ─── Stage: trivy (Socket-built redistribution) ─────────────────────────────── +FROM ${TRIVY_IMAGE} AS trivy # ─── Stage: trufflehog (Dependabot-trackable) ───────────────────────────────── FROM trufflesecurity/trufflehog:${TRUFFLEHOG_VERSION} AS trufflehog @@ -42,7 +50,7 @@ WORKDIR /socket-basics COPY --from=uv /uv /uvx /bin/ # Binary tools from immutable build stages -# COPY --from=trivy /usr/local/bin/trivy /usr/local/bin/trivy +COPY --from=trivy /usr/local/bin/trivy /usr/local/bin/trivy COPY --from=trufflehog /usr/bin/trufflehog /usr/local/bin/trufflehog COPY --from=opengrep-installer /root/.opengrep /root/.opengrep diff --git a/Dockerfile.heavy b/Dockerfile.heavy index 9a180f9..a60f0ed 100644 --- a/Dockerfile.heavy +++ b/Dockerfile.heavy @@ -1,12 +1,13 @@ # Heavy POC image: socket-basics plus a pinned stable Python Socket CLI. ARG PYTHON_VERSION=3.12 -ARG TRUFFLEHOG_VERSION=3.93.8 -ARG TRIVY_VERSION=0.69.3 -ARG UV_VERSION=0.10.11 -ARG OPENGREP_VERSION=v1.16.5 -ARG SOCKET_CLI_VERSION=2.5.0 +ARG TRUFFLEHOG_VERSION=3.96.0 +ARG UV_VERSION=0.12.1 +ARG OPENGREP_VERSION=v1.26.0 +ARG SOCKET_CLI_VERSION=2.5.8 +# Socket-built Trivy, pinned by digest — see the note in ./Dockerfile. +ARG TRIVY_IMAGE=ghcr.io/socketdev/trivy:0.73.0@sha256:e3d9d5f10250cb73b0ea9446ae1191c0f2da2f5e6173eac08a840b1812f02e0b -# FROM aquasec/trivy:${TRIVY_VERSION} AS trivy +FROM ${TRIVY_IMAGE} AS trivy FROM trufflesecurity/trufflehog:${TRUFFLEHOG_VERSION} AS trufflehog FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv @@ -24,6 +25,7 @@ FROM python:${PYTHON_VERSION}-slim AS runtime WORKDIR /socket-basics COPY --from=uv /uv /uvx /bin/ +COPY --from=trivy /usr/local/bin/trivy /usr/local/bin/trivy COPY --from=trufflehog /usr/bin/trufflehog /usr/local/bin/trufflehog COPY --from=opengrep-installer /root/.opengrep /root/.opengrep diff --git a/README.md b/README.md index d13d9e1..426dc74 100644 --- a/README.md +++ b/README.md @@ -65,20 +65,17 @@ jobs: Socket Basics can also run locally or in other CI/CD environments: -> [!IMPORTANT] -> The supported pre-built GitHub Action and Docker image paths currently ship -> _without_ Trivy while we evaluate the safest way to bundle it with Basics -> again. -> If you need Trivy in the meantime, use the native/manual path and pin to -> `v0.69.3` or Docker tag `0.69.3`. -> [Aqua's official incident summary](https://www.aquasec.com/blog/trivy-supply-chain-attack-what-you-need-to-know/) -> lists the known-safe Trivy binary range as `v0.69.2` to `v0.69.3`; we -> standardize on the latest known-safe version. -> Do not use `v0.69.4`, and audit any cached Docker Hub images for `0.69.5` and -> `0.69.6`. +> [!NOTE] +> Trivy-backed scanning is bundled in the pre-built GitHub Action and Docker +> images again. Socket Basics ships a **Socket-built distribution of Trivy** — +> rebuilt from unmodified upstream source by Socket's own release pipeline and +> pinned by digest in the [Dockerfile](Dockerfile) — rather than pulling +> upstream-published binaries or images. +> If you install Trivy natively instead, never use versions `0.69.4`, `0.69.5`, +> or `0.69.6` ([Aqua's incident summary](https://www.aquasec.com/blog/trivy-supply-chain-attack-what-you-need-to-know/)), +> and audit any cached Docker Hub images for those tags. > See [Local Installation](docs/local-installation.md#trivy-container-scanning) -> for the detailed version guidance, installation options, and the -> corresponding Aqua action versions. +> for installation options. - **[Pre-Commit Hook](docs/pre-commit-hook.md)** — Catch issues before they're committed - **[Local Docker Installation](docs/local-install-docker.md)** — Run in Docker with no tool installation required @@ -89,7 +86,7 @@ Socket Basics can also run locally or in other CI/CD environments: **Built-in Security Scanners:** - 🔍 **SAST** — Static analysis for 15+ languages (Python, JavaScript, Go, Java, Ruby, C#, and more) - 🔐 **Secret Scanning** — Detect leaked credentials and API keys with TruffleHog -- 🐳 **Container Scanning** — Trivy-backed image and Dockerfile scanning for native installs +- 🐳 **Container Scanning** — Trivy-backed image and Dockerfile scanning - 📦 **Dependency Analysis** — Socket Tier 1 reachability analysis for supply chain security **Enterprise Features** (requires [Socket Enterprise](https://socket.dev/enterprise)): diff --git a/action.yml b/action.yml index dcb6dc7..7e93f7b 100644 --- a/action.yml +++ b/action.yml @@ -80,7 +80,6 @@ runs: INPUT_SWIFT_DISABLED_RULES: ${{ inputs.swift_disabled_rules }} INPUT_SWIFT_ENABLED_RULES: ${{ inputs.swift_enabled_rules }} INPUT_SWIFT_SAST_ENABLED: ${{ inputs.swift_sast_enabled }} - # Trivy-backed scanning is temporarily disabled in the pre-built GitHub Action image. INPUT_TRIVY_DISABLED_RULES: ${{ inputs.trivy_disabled_rules }} INPUT_TRIVY_IMAGE_SCANNING_DISABLED: ${{ inputs.trivy_image_scanning_disabled }} INPUT_TRIVY_NOTIFICATION_METHOD: ${{ inputs.trivy_notification_method }} @@ -412,19 +411,19 @@ inputs: required: false default: "false" trivy_disabled_rules: - description: "Comma-separated list of Trivy rules to disable. Trivy-backed scanning is temporarily unavailable in the pre-built GitHub Action image." + description: "Comma-separated list of Trivy rules to disable." required: false default: "" trivy_image_scanning_disabled: - description: "Disable Trivy image scanning. Trivy-backed scanning is temporarily unavailable in the pre-built GitHub Action image." + description: "Disable Trivy image scanning." required: false default: "false" trivy_notification_method: - description: "Notification method for Trivy (e.g., console, slack). Trivy-backed scanning is temporarily unavailable in the pre-built GitHub Action image." + description: "Notification method for Trivy (e.g., console, slack)." required: false default: "" trivy_vuln_enabled: - description: "Enable Trivy vulnerability scanning for all supported language ecosystems. Trivy-backed scanning is temporarily unavailable in the pre-built GitHub Action image." + description: "Enable Trivy vulnerability scanning for all supported language ecosystems." required: false default: "false" trufflehog_exclude_dir: diff --git a/app_tests/Dockerfile b/app_tests/Dockerfile index 92148b8..4146998 100644 --- a/app_tests/Dockerfile +++ b/app_tests/Dockerfile @@ -1,21 +1,24 @@ # ─── Global version pins (single source of truth) ──────────────────────────── # Dependabot tracks all ARGs below via the FROM lines that reference them. -# To override at build time: docker build --build-arg TRIVY_VERSION=0.70.0 . +# To override at build time: docker build --build-arg TRUFFLEHOG_VERSION=3.93.8 . # # Dependabot-trackable (each has a corresponding FROM : stage): -ARG GOLANG_VERSION=1.24.1 +ARG GOLANG_VERSION=1.26.5 ARG NODE_VERSION=22 ARG PYTHON_VERSION=3.12 -ARG TRUFFLEHOG_VERSION=3.93.8 -ARG TRIVY_VERSION=0.69.3 -ARG UV_VERSION=0.10.11 +ARG TRUFFLEHOG_VERSION=3.96.0 +ARG UV_VERSION=0.12.1 # # NOT Dependabot-trackable (no official Docker image with a stable binary path): -ARG GOSEC_VERSION=v2.24.7 -ARG OPENGREP_VERSION=v1.16.5 +ARG GOSEC_VERSION=v2.28.0 +ARG OPENGREP_VERSION=v1.26.0 +# +# NOT Dependabot-trackable — Socket-built Trivy, pinned by digest; updated by +# Socket's trivy-dist release process. See the note in the root ./Dockerfile. +ARG TRIVY_IMAGE=ghcr.io/socketdev/trivy:0.73.0@sha256:e3d9d5f10250cb73b0ea9446ae1191c0f2da2f5e6173eac08a840b1812f02e0b -# ─── Stage: trivy (Dependabot-trackable) ────────────────────────────────────── -FROM aquasec/trivy:${TRIVY_VERSION} AS trivy +# ─── Stage: trivy (Socket-built redistribution) ─────────────────────────────── +FROM ${TRIVY_IMAGE} AS trivy # ─── Stage: trufflehog (Dependabot-trackable) ───────────────────────────────── FROM trufflesecurity/trufflehog:${TRUFFLEHOG_VERSION} AS trufflehog @@ -58,7 +61,7 @@ RUN curl -fsSL https://raw.githubusercontent.com/opengrep/opengrep/main/install. # ─── Stage: runtime ─────────────────────────────────────────────────────────── FROM python:${PYTHON_VERSION}-slim AS runtime -WORKDIR /socket-security-tools +WORKDIR /app-tests ENV PATH=$PATH:/usr/local/go/bin COPY --from=uv /uv /uvx /bin/ @@ -70,11 +73,14 @@ COPY --from=opengrep-installer /root/.opengrep /root/.opengrep COPY --from=golang /usr/local/go /usr/local/go COPY --from=gosec-installer /usr/local/bin/gosec /usr/local/bin/gosec -# Node binary + npm from the versioned node stage (Dependabot-trackable) +# Node binary + npm from the versioned node stage (Dependabot-trackable). +# npm/npx in the node image are symlinks into node_modules/npm/bin — COPY +# dereferences symlinks into flat files, which breaks npm's relative requires, +# so recreate them as proper symlinks instead of copying. COPY --from=node /usr/local/bin/node /usr/local/bin/node -COPY --from=node /usr/local/bin/npm /usr/local/bin/npm -COPY --from=node /usr/local/bin/npx /usr/local/bin/npx COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules +RUN ln -sf /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \ + && ln -sf /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx # System deps + ESLint + Socket CLI (npm now available from node stage above) RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ @@ -91,19 +97,14 @@ RUN --mount=type=cache,target=/root/.cache/uv \ uv tool install bandit && uv tool install socketsecurity ENV PATH="/root/.local/bin:$PATH" -# App source -COPY src/socket_external_tools_runner.py /socket-security-tools/ -COPY src/version.py /socket-security-tools/ -COPY src/core /socket-security-tools/core -COPY entrypoint.sh /socket-security-tools/ - -RUN chmod +x /socket-security-tools/entrypoint.sh - -COPY pyproject.toml uv.lock /scripts/ -WORKDIR /scripts -RUN --mount=type=cache,target=/root/.cache/uv \ - uv sync --frozen && uv pip install light-s3-client +# NOTE: the legacy socket-security-tools runner (src/, entrypoint.sh) predates +# the socket_basics layout migration and no longer exists in this repo — the +# stale COPY/ENTRYPOINT lines had made this image unbuildable. Until the +# app-tests harness is modernized, this is a tools image (scanners + language +# runtimes) exercised by CI smoke checks against the fixture apps here. +# Build with app_tests/ as the context: +# docker build -f app_tests/Dockerfile app_tests -ENV PATH="/scripts/.venv/bin:/root/.opengrep/cli/latest:$PATH" +ENV PATH="/root/.opengrep/cli/latest:$PATH" -ENTRYPOINT ["/socket-security-tools/entrypoint.sh"] +CMD ["/bin/sh"] diff --git a/app_tests/uv.lock b/app_tests/uv.lock index 0cdfd1e..25470c9 100644 --- a/app_tests/uv.lock +++ b/app_tests/uv.lock @@ -1,7 +1,13 @@ version = 1 -revision = 1 +revision = 3 requires-python = ">=3.9" [[package]] -name = "" -version = "" +name = "app-tests-python" +version = "0.0.0" +source = { virtual = "." } + +[package.metadata] + +[package.metadata.requires-dev] +dev = [] diff --git a/docs/github-action.md b/docs/github-action.md index b9ba113..93cc83f 100644 --- a/docs/github-action.md +++ b/docs/github-action.md @@ -97,9 +97,10 @@ the action itself is compromised or ships a bad release, every repo running it is immediately affected. We've seen this happen across the ecosystem: - **Floating tags** (`@v2`, `:latest`) auto-update on every new release. - A single bad push silently reaches all users with no review gate. This is - structurally identical to `docker pull :latest` — the anti-pattern we - explicitly warn against in our Docker docs. + A single bad push silently reaches all users with no review gate. (We do + publish `:latest`/`:latest-heavy` Docker aliases as an onboarding + convenience, but treat them as exactly that — production pipelines should + pin an exact version or digest.) - **Version tags** (`@v2.0.3`) are better, but tags are mutable by default. A tag can be deleted and recreated pointing at a different commit. There are documented cases of this happening — maliciously and accidentally. @@ -107,9 +108,10 @@ is immediately affected. We've seen this happen across the ecosystem: reassigned. Combined with Dependabot, you get automated upgrades with a human review gate at zero ongoing maintenance cost. -We don't publish a floating major tag (`v2`). We do publish immutable version -tags (`v2.0.3`) protected by tag protection rules in GitHub — but SHA pinning -is still the recommendation for defence in depth. +We don't publish a floating major tag (`v2`) for the action. Docker image +version tags are immutable registry-side (enforced by an immutable-tag rule), +with `latest`/`latest-heavy` as the only floating aliases — but SHA/digest +pinning is still the recommendation for defence in depth. ### Pinning strategies @@ -536,16 +538,13 @@ jobs: ### Container Security Pipeline -> [!IMPORTANT] -> The supported pre-built GitHub Action path currently ships _without_ Trivy -> while we evaluate the safest way to bundle it with Basics again. -> If you need Trivy in the meantime, install and run it independently in the -> workflow, pin to `v0.69.3` or Docker tag `0.69.3`, and review the upstream -> install path and artifacts carefully. -> Do not use `v0.69.4`, and audit any Docker Hub use of `0.69.5` and `0.69.6`. -> See [Local Installation](local-installation.md#trivy-container-scanning) for -> the detailed version guidance, corresponding Aqua action versions, and install -> options. +> [!NOTE] +> The pre-built GitHub Action bundles Trivy (a Socket-built distribution, +> rebuilt from unmodified upstream source and pinned by digest), so the +> container-scanning inputs below work out of the box. The standalone-install +> example that follows is only for running Trivy independently of Socket +> Basics; if you do that, never use versions `0.69.4`–`0.69.6` — see +> [Local Installation](local-installation.md#trivy-container-scanning). ```yaml name: Container Security @@ -573,7 +572,10 @@ jobs: - name: Install pinned Trivy run: | - TRIVY_VERSION=0.69.3 + # Pin explicitly; never use 0.69.4–0.69.6 (see the Trivy section in + # docs/local-installation.md). Keep in step with the version bundled + # in the Socket Basics image (TRIVY_VERSION in the Dockerfile). + TRIVY_VERSION=0.73.0 curl -fsSL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh \ | sh -s -- -b /usr/local/bin "v${TRIVY_VERSION}" @@ -637,10 +639,8 @@ jobs: GITHUB_PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} with: github_token: ${{ secrets.GITHUB_TOKEN }} - # Dockerfile discovery remains useful context for future container - # scanning support, but the current pre-built action path currently - # ships _without_ Trivy while we evaluate the safest way to bundle it - # with Basics again. + # Discovered Dockerfiles feed Trivy-backed misconfiguration scanning, + # which is bundled in the pre-built action image. verbose: 'true' ``` @@ -783,13 +783,9 @@ See [`action.yml`](../action.yml) for the complete list of inputs. - `trivy_vuln_enabled` — Enable vulnerability scanning > [!NOTE] -> These inputs remain part of the action interface, but the current pre-built -> GitHub Action path currently ships _without_ Trivy while we evaluate the -> safest way to bundle it with Basics again. -> Use the [native installation path](local-installation.md) if container -> scanning is a near-term requirement. See -> [Trivy (Container Scanning)](local-installation.md#trivy-container-scanning) -> for the current version guidance and install options. +> Container scanning is backed by Trivy, bundled in the pre-built GitHub +> Action image (a Socket-built distribution, pinned by digest) — these inputs +> work without any extra setup. **Notifications (Enterprise Required):** - `slack_webhook_url` — Slack webhook @@ -845,13 +841,6 @@ permissions: **Problem:** Container image scanning fails. **Solutions:** -> [!NOTE] -> The current pre-built GitHub Action path ships _without_ Trivy while we -> evaluate the safest way to bundle it with Basics again. If container scanning -> is a near-term requirement, switch to a native Trivy install in the workflow. -> See -> [Trivy (Container Scanning)](local-installation.md#trivy-container-scanning) -> for the current version guidance and install options. 1. For private images, add authentication: ```yaml diff --git a/docs/github-pr-comment-guide.md b/docs/github-pr-comment-guide.md index 640e28f..b704607 100644 --- a/docs/github-pr-comment-guide.md +++ b/docs/github-pr-comment-guide.md @@ -14,10 +14,9 @@ These enhancements work across **all scanner types**: All scanners share the same UX enhancements for a consistent, professional experience. > [!NOTE] -> Container-scanning UX is still supported by Socket Basics, but the current -> pre-built GitHub Action image currently ships _without_ Trivy while we -> evaluate the safest way to bundle it with Basics again. For the current Trivy -> status, version guidance, and temporary self-service path, see +> Container-scanning results come from Trivy, which is bundled in the pre-built +> GitHub Action image (a Socket-built distribution of Trivy, pinned by digest). +> For native-install guidance see > [Local Installation](local-installation.md#trivy-container-scanning). ## 🎯 Quick Start diff --git a/docs/local-install-docker.md b/docs/local-install-docker.md index d4e31bc..e149dd1 100644 --- a/docs/local-install-docker.md +++ b/docs/local-install-docker.md @@ -55,15 +55,12 @@ docker inspect ghcr.io/socketdev/socket-basics:2.0.3 \ # } ``` -> [!IMPORTANT] -> The supported pre-built Docker image currently ships _without_ Trivy while we -> evaluate the safest way to bundle it with Basics again. -> If you need Trivy in the meantime, run it separately from Socket Basics and -> pin to `v0.69.3` or Docker tag `0.69.3`. -> Do not use `v0.69.4`, and audit any Docker Hub pulls or caches for `0.69.5` -> and `0.69.6`. +> [!NOTE] +> The pre-built Docker image bundles Trivy — a Socket-built distribution, +> rebuilt from unmodified upstream source and pinned by digest — so container +> and Dockerfile scanning work out of the box. > See [Local Installation](local-installation.md#trivy-container-scanning) for -> the detailed version guidance and install options. +> native-install guidance (including versions to avoid). ### Registries @@ -180,9 +177,11 @@ docker build \ -t socket-basics:2.0.3 . ``` -`TRIVY_VERSION` still exists in the Dockerfile for maintainers, but the current -published image intentionally omits the Trivy binary. For the app tests image, build -from the `app_tests` directory and use the same build args. +Trivy comes from a Socket-built image pinned by digest via the `TRIVY_IMAGE` +build arg (`TRIVY_VERSION` feeds the image label and must match its tag). +Building locally requires pull access to that registry; contributors without it +can override with `--build-arg TRIVY_IMAGE=aquasec/trivy:`. For the app +tests image, build from the `app_tests` directory and use the same build args. ### Verify Installation @@ -367,15 +366,11 @@ docker run --rm \ ### Container Scanning Status -> [!IMPORTANT] -> The supported pre-built Docker image currently ships _without_ Trivy while we -> evaluate the safest way to bundle it with Basics again. -> If you need Trivy before it returns to the image, run a separate -> `aquasec/trivy:0.69.3` step or a host-native `trivy` install pinned to -> `v0.69.3`, rather than rebuilding the Socket Basics image and re-enabling -> Trivy ad hoc. -> See [Local Installation](local-installation.md#trivy-container-scanning) for -> the detailed version guidance. +> [!NOTE] +> Trivy-backed container and Dockerfile scanning is included in the pre-built +> image (Socket-built Trivy distribution, digest-pinned). No separate Trivy +> setup is required. For native installs, see +> [Local Installation](local-installation.md#trivy-container-scanning). ### Save Results to File diff --git a/docs/local-installation.md b/docs/local-installation.md index 5bd59d0..5a5c0b7 100644 --- a/docs/local-installation.md +++ b/docs/local-installation.md @@ -38,13 +38,11 @@ trufflehog --version ``` > [!NOTE] -> The supported pre-built GitHub Action and Docker image paths currently ship -> _without_ Trivy while we evaluate the safest way to bundle it with Basics -> again. -> If you need container or Dockerfile scanning today, use -> [Trivy (Container Scanning)](#trivy-container-scanning) and review the -> upstream install path and artifacts carefully before adopting it in production -> CI. +> The pre-built GitHub Action and Docker images bundle Trivy (a Socket-built +> distribution, rebuilt from unmodified upstream source and pinned by digest) — +> no separate install is needed on those paths. The instructions below are for +> **native** installs only; see +> [Trivy (Container Scanning)](#trivy-container-scanning) for version guidance. For detailed installation instructions, continue reading below. @@ -190,25 +188,20 @@ export SOCKET_SECURITY_API_KEY="your-api-key" **Required for:** Container image and Dockerfile vulnerability scanning -> [!IMPORTANT] -> The supported pre-built GitHub Action and Docker image paths currently ship -> _without_ Trivy while we evaluate the safest way to bundle it with Basics -> again. -> -> If you need Trivy before it formally returns to Socket Basics: -> - Pin the binary to `v0.69.3` or the Docker image to -> `aquasec/trivy:0.69.3`. -> - Do not use `v0.69.4` of the binary. -> - Audit any cached Docker Hub images for `0.69.5` and `0.69.6`. -> -> [Aqua's official incident summary](https://www.aquasec.com/blog/trivy-supply-chain-attack-what-you-need-to-know/) -> lists the known-safe Trivy binary range as `v0.69.2` to `v0.69.3`; the -> corresponding Docker image tags are `0.69.2` to `0.69.3` without the `v` -> prefix. We standardize on `v0.69.3` / Docker tag `0.69.3`. +> [!NOTE] +> The pre-built Socket Basics images already include Trivy — a Socket-built +> distribution rebuilt from unmodified upstream source and pinned by digest in +> the [Dockerfile](../Dockerfile). Install natively only if you run Socket +> Basics outside those images. > -> If you use Aqua's own GitHub Actions independently of Socket Basics, pin -> `aquasecurity/trivy-action@v0.35.0` and `aquasecurity/setup-trivy@v0.2.6` by -> full commit SHA rather than by tag. +> For native installs: +> - Pin an explicit recent version; prefer verifying upstream release signatures. +> - **Never use `v0.69.4`, `0.69.5`, or `0.69.6`** — see +> [Aqua's incident summary](https://www.aquasec.com/blog/trivy-supply-chain-attack-what-you-need-to-know/) — +> and audit any cached Docker Hub images for those tags. +> - If you use Aqua's own GitHub Actions independently of Socket Basics, pin +> `aquasecurity/trivy-action` (≥ v0.35.0) and `aquasecurity/setup-trivy` +> (≥ v0.2.6) by full commit SHA rather than by tag. **Installation:** @@ -217,9 +210,11 @@ export SOCKET_SECURITY_API_KEY="your-api-key" brew install trivy # Ubuntu/Debian: -sudo apt-get install wget apt-transport-https gnupg lsb-release +# NOTE: upstream publishes to the `generic` distribution as of Trivy v0.72.0 — +# codename-based entries (jammy, noble, ...) are frozen and no longer updated. +sudo apt-get install wget apt-transport-https gnupg wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add - -echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list +echo "deb https://aquasecurity.github.io/trivy-repo/deb generic main" | sudo tee -a /etc/apt/sources.list.d/trivy.list sudo apt-get update sudo apt-get install trivy @@ -233,18 +228,16 @@ enabled=1 EOF sudo yum -y install trivy -# Using Docker (alternative; pin explicitly): -docker pull aquasec/trivy:0.69.3 +# Using Docker (alternative; always pin an explicit version, ideally by digest): +docker pull aquasec/trivy:0.73.0 # Verify installation trivy --version ``` -For this interim path, `trivy --version` should report `Version: 0.69.3`, and a -container-based install should use image tag `aquasec/trivy:0.69.3`. If your -package manager or container reference resolves to some other version, treat -that as a separate review decision rather than assuming it matches the current -Socket Basics guidance. +Match the version bundled in the Socket Basics image where possible (see the +`TRIVY_VERSION` pin in the [Dockerfile](../Dockerfile)) so native and +containerized scans produce comparable results. **Documentation:** https://github.com/aquasecurity/trivy diff --git a/docs/parameters.md b/docs/parameters.md index 4e8ed3f..22adfeb 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -349,16 +349,10 @@ socket-basics --secrets --show-unverified ## Container Scanning > [!NOTE] -> These parameters remain part of the Socket Basics interface for container -> scanning. In the current pre-built GitHub Action and Docker image paths, -> Socket Basics currently ships _without_ Trivy while we evaluate the safest way -> to bundle it with Basics again. The parameters still apply for the -> [native installation path](local-installation.md) as a temporary workaround, -> and for future container scanner support in the pre-built paths. -> Review the upstream install path and artifacts carefully before adopting that -> workaround in production CI. See -> [Trivy (Container Scanning)](local-installation.md#trivy-container-scanning) -> for the current version guidance and installation options. +> Container scanning is backed by Trivy, which is bundled in the pre-built +> GitHub Action and Docker images (a Socket-built distribution, digest-pinned). +> These parameters work out of the box on those paths, and equally with a +> [native installation](local-installation.md#trivy-container-scanning). ### `--images IMAGES` Comma-separated list of container images to scan (auto-enables image scanning). diff --git a/docs/pre-commit-hook.md b/docs/pre-commit-hook.md index 827f7e3..585c8f9 100644 --- a/docs/pre-commit-hook.md +++ b/docs/pre-commit-hook.md @@ -204,8 +204,8 @@ See [Local Installation Guide](local-installation.md) for detailed instructions - OpenGrep - TruffleHog -The Trivy section in that guide also covers the current Basics status and the -recommended self-service version pins: +The Trivy section in that guide covers version guidance for native installs +(including versions to avoid): [Trivy (Container Scanning)](local-installation.md#trivy-container-scanning). ### Setup Steps diff --git a/scripts/integration-test-docker.sh b/scripts/integration-test-docker.sh index 77545ff..0720e0d 100755 --- a/scripts/integration-test-docker.sh +++ b/scripts/integration-test-docker.sh @@ -5,6 +5,8 @@ # 1. socket-basics CLI starts and responds to --help # 2. opengrep can scan Python code using the bundled rules (no API key needed) # 3. socket-basics runs a scan on a small fixture without crashing +# 4. the trivy connector scans a fixture Dockerfile end-to-end (bundled +# Socket-built trivy binary → `trivy config` → result parsing) # # Usage: # ./scripts/integration-test-docker.sh [--image-tag TAG] @@ -82,4 +84,37 @@ fi pass "socket-basics ran on fixture without crashing" +# ── Test 4: trivy connector end-to-end (Dockerfile misconfig scan) ──────────── +# Exercises the trivy connector's full path (config → `trivy config` → result +# parsing → console output) against the fixture Dockerfile. As with Test 3 we +# assert no crash rather than specific findings — BUT we must also catch a +# missing binary explicitly: the connector logs "Trivy not found" and continues +# rather than failing, so without that grep this test would pass vacuously. +echo "--> socket-basics --dockerfiles scan on fixture Dockerfile" +trivy_output=$( + docker run --rm \ + -v "${FIXTURE_DIR}:/workspace:ro" \ + --entrypoint /bin/sh \ + "$IMAGE_TAG" \ + -c "socket-basics --workspace /workspace --dockerfiles /workspace/Dockerfile --console-tabular-enabled 2>&1" \ +) || true # accept non-zero exit (findings are expected) + +if [[ -z "$trivy_output" ]]; then + fail "socket-basics produced no output on Dockerfile scan" +fi + +if echo "$trivy_output" | grep -qi "Trivy not found"; then + echo " Scan output:" + echo "$trivy_output" | head -30 + fail "trivy binary missing inside the image (connector fell back to a no-op)" +fi + +if echo "$trivy_output" | grep -qiE "^(panic:|fatal error:)|segmentation fault|Traceback \(most recent call last\)$"; then + echo " Scan output:" + echo "$trivy_output" | head -30 + fail "socket-basics crashed during Dockerfile scan" +fi + +pass "trivy connector scanned the fixture Dockerfile without crashing" + echo "==> Integration test passed" diff --git a/scripts/smoke-test-docker.sh b/scripts/smoke-test-docker.sh index 14c2243..180f63f 100644 --- a/scripts/smoke-test-docker.sh +++ b/scripts/smoke-test-docker.sh @@ -15,11 +15,13 @@ BUILD_PROGRESS="${SMOKE_TEST_BUILD_PROGRESS:-}" MAIN_TOOLS=( "socket-basics -h" "command -v socket" + "trivy --version" "trufflehog --version" "opengrep --version" ) APP_TESTS_TOOLS=( + "trivy --version" "trufflehog --version" "opengrep --version" "command -v socket" @@ -29,16 +31,11 @@ HEAVY_TOOLS=( "socket-basics -h" "socketcli --help" "command -v socket" + "trivy --version" "trufflehog --version" "opengrep --version" ) -# TEMPORARY: trivy is being removed to assess impact. These checks FAIL if the -# tool is still present in the image — ensures removal is complete. -MUST_NOT_EXIST_TOOLS=( - "trivy" -) - usage() { echo "Usage: $0 [--image-tag TAG] [--app-tests] [--skip-build] [--check-set main|app-tests|heavy] [--dockerfile FILE] [--build-progress MODE]" echo " --skip-build: skip docker build; verify tools in a pre-built image" @@ -106,6 +103,7 @@ fi build_args_for_tag() { local tag="$1" BUILD_ARGS=(--progress "$BUILD_PROGRESS" -t "$tag") + [[ -n "${TRIVY_IMAGE:-}" ]] && BUILD_ARGS+=(--build-arg "TRIVY_IMAGE=$TRIVY_IMAGE") [[ -n "${TRIVY_VERSION:-}" ]] && BUILD_ARGS+=(--build-arg "TRIVY_VERSION=$TRIVY_VERSION") [[ -n "${TRUFFLEHOG_VERSION:-}" ]] && BUILD_ARGS+=(--build-arg "TRUFFLEHOG_VERSION=$TRUFFLEHOG_VERSION") [[ -n "${OPENGREP_VERSION:-}" ]] && BUILD_ARGS+=(--build-arg "OPENGREP_VERSION=$OPENGREP_VERSION") @@ -127,20 +125,42 @@ run_checks() { done } -# TEMPORARY: verify tools have been fully removed from the image. -# Fails if any tool in the list is still present. -run_must_not_exist_checks() { +# Socket-built trivy assertions, beyond presence: +# 1. the binary's reported version must agree with the version tag pinned in +# the Dockerfile's TRIVY_IMAGE ARG (catches pin/binary drift), and +# 2. `trivy config` — the exact subcommand the trivy connector invokes — must +# succeed against a trivial fixture, with the connector's flags. +run_trivy_checks() { local tag="$1" - shift - local tools=("$@") - for tool in "${tools[@]}"; do - if docker run --rm --entrypoint /bin/sh "$tag" -c "command -v $tool" > /dev/null 2>&1; then - echo " FAIL: $tool is still present in the image (expected removal)" - return 1 - else - echo " OK: $tool not found (removal confirmed)" - fi - done + local dockerfile="$2" + local expected + expected="$(sed -n 's/^ARG TRIVY_IMAGE=[^:]*:\([^@]*\)@.*/\1/p' "$dockerfile")" + if [[ -z "$expected" ]]; then + echo " FAIL: could not parse the TRIVY_IMAGE version tag from $dockerfile" + return 1 + fi + if docker run --rm --entrypoint /bin/sh "$tag" -c "trivy --version | grep -q 'Version: $expected'"; then + echo " OK: trivy version matches the Dockerfile pin ($expected)" + else + echo " FAIL: trivy version does not match the Dockerfile pin ($expected)" + docker run --rm --entrypoint /bin/sh "$tag" -c "trivy --version" 2>&1 || true + return 1 + fi + if docker run --rm --entrypoint /bin/sh "$tag" \ + -c "printf 'FROM alpine:3.20\n' > /tmp/smoke.Dockerfile && trivy config --format json --output /tmp/smoke-result.json /tmp/smoke.Dockerfile"; then + echo " OK: trivy config scan succeeds (connector code path)" + else + echo " FAIL: trivy config scan failed" + return 1 + fi +} + +trivy_ref_dockerfile() { + case "$CHECK_SET" in + app-tests) echo "app_tests/Dockerfile" ;; + heavy) echo "Dockerfile.heavy" ;; + *) echo "Dockerfile" ;; + esac } cd "$REPO_ROOT" @@ -157,7 +177,7 @@ if $SKIP_BUILD; then else run_checks "$IMAGE_TAG" "${MAIN_TOOLS[@]}" fi - run_must_not_exist_checks "$IMAGE_TAG" "${MUST_NOT_EXIST_TOOLS[@]}" + run_trivy_checks "$IMAGE_TAG" "$(trivy_ref_dockerfile)" else # ── Normal mode: build then verify ──────────────────────────────────────── echo "==> Build main image" @@ -176,20 +196,20 @@ else else run_checks "$IMAGE_TAG" "${MAIN_TOOLS[@]}" fi - run_must_not_exist_checks "$IMAGE_TAG" "${MUST_NOT_EXIST_TOOLS[@]}" + run_trivy_checks "$IMAGE_TAG" "$DOCKERFILE" if $RUN_APP_TESTS; then echo "==> Build app_tests image" echo "Image: $APP_TESTS_IMAGE_TAG" build_args_for_tag "$APP_TESTS_IMAGE_TAG" app_build_start="$(date +%s)" - docker build -f app_tests/Dockerfile "${BUILD_ARGS[@]}" . + docker build -f app_tests/Dockerfile "${BUILD_ARGS[@]}" app_tests app_build_end="$(date +%s)" echo "app_tests image build completed in $((app_build_end - app_build_start))s" echo "==> Verify tools in app_tests image" run_checks "$APP_TESTS_IMAGE_TAG" "${APP_TESTS_TOOLS[@]}" - run_must_not_exist_checks "$APP_TESTS_IMAGE_TAG" "${MUST_NOT_EXIST_TOOLS[@]}" + run_trivy_checks "$APP_TESTS_IMAGE_TAG" "app_tests/Dockerfile" fi fi diff --git a/tests/fixtures/integration/Dockerfile b/tests/fixtures/integration/Dockerfile new file mode 100644 index 0000000..1c24b2d --- /dev/null +++ b/tests/fixtures/integration/Dockerfile @@ -0,0 +1,6 @@ +# Integration-test fixture for Trivy Dockerfile (misconfiguration) scanning. +# Deliberately minimal and imperfect (no USER, broad COPY) so trivy has +# something to look at; the test asserts the scan runs, not specific findings. +FROM alpine:3.20 +COPY . /app +CMD ["sh"]