Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 19 additions & 22 deletions .github/workflows/docker-stable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,28 @@ jobs:
with:
persist-credentials: false

- name: Check if version exists in PyPI
id: version_check
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
if ! curl -s -f "https://pypi.org/pypi/socketsecurity/${INPUT_VERSION}/json" > /dev/null; then
echo "Error: Version ${INPUT_VERSION} not found on PyPI"
exit 1
fi
echo "Version ${INPUT_VERSION} found on PyPI - proceeding with release"

- name: Set up Docker publishing
uses: $/.github/actions/setup-docker
with:
# Retagging copies manifests between tags; nothing is built.
enable-qemu: "false"
dockerhub-username: ${{ secrets.DOCKERHUB_USERNAME }}
dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build & Push Stable Docker
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
push: true
platforms: linux/amd64,linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max
tags: socketdev/cli:stable
build-args: |
CLI_VERSION=${{ inputs.version }}

# Point stable at the image the release already published instead of
# rebuilding it. A rebuild would pair that release's wheel with today's
# Dockerfile, and would give users who already pulled the release new
# layers to download. The retag keeps the release's attestations.
- name: Tag the release image as stable
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
if ! printf '%s' "$INPUT_VERSION" | grep -Eq '^[0-9]+(\.[0-9A-Za-z-]+)+$'; then
echo "Error: '${INPUT_VERSION}' is not a release version such as 1.2.3"
exit 1
fi
if ! docker buildx imagetools inspect "socketdev/cli:${INPUT_VERSION}" > /dev/null; then
echo "Error: socketdev/cli:${INPUT_VERSION} is not on Docker Hub"
exit 1
fi
docker buildx imagetools create --tag socketdev/cli:stable "socketdev/cli:${INPUT_VERSION}"
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ jobs:
platforms: linux/amd64,linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max
# Attach an SPDX SBOM generated from the built image, next to the
# provenance attestation the action already adds.
sbom: true
tags: |
socketdev/cli:latest
socketdev/cli:${{ env.VERSION }}
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Changelog

## 2.11.12

### Added: SBOM attestation on the Docker image

- Release images on Docker Hub now carry an SPDX SBOM attestation alongside the
existing provenance attestation. See
[Verify the image](docs/ci-cd.md#verify-the-image).

### Changed: `stable` points at the published release image

- Marking a release stable now retags the image that release published instead of
rebuilding it, so `socketdev/cli:stable` is the same image as
`socketdev/cli:<version>`, attestations included.

### Added: Docker image guide

- New [Docker image](docs/ci-cd.md#docker-image) section covering how to cache the
reachability engine between container runs and keep image pulls cheap in CI.

## 2.11.11

### Changed: use lowercase Python CLI User-Agent
Expand Down
74 changes: 74 additions & 0 deletions docs/ci-cd.md
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,80 @@ Dashboard metadata unless `--integration` was explicitly supplied. PR comments
remain limited to the existing GitHub and GitLab SCM adapters; Azure receives
console output and Dashboard association but does not post a PR comment.

## Docker image

`socketdev/cli` on Docker Hub packages the CLI with the toolchains reachability
analysis runs on: Node.js, Go, Java, .NET, Rust, Ruby, pyenv, and PyPy on
`linux/amd64`. The toolchains are most of the image's size. Tags are published
per release (`socketdev/cli:<version>`), plus `latest` and `stable`.

```sh
docker run --rm \
-e SOCKET_SECURITY_API_TOKEN \
-v "$PWD:/src" \
socketdev/cli:<version> --target-path /src --reach
```

### Cache the reachability engine

With `--reach`, the CLI downloads its pinned reachability engine on first use and
caches it under `$XDG_CACHE_HOME/socket/coana` (`/root/.cache/socket/coana` in the
image). A new container starts with an empty cache, so without a persistent
cache every run downloads the engine again. Mount a volume to keep it:

```sh
docker run --rm \
-e SOCKET_SECURITY_API_TOKEN \
-v "$PWD:/src" \
-v socket-cache:/root/.cache/socket \
socketdev/cli:<version> --target-path /src --reach
```

On CI runners that start every job on a fresh machine, mount a directory your CI
provider caches instead, and key that cache on the CLI version, which determines
the engine version. In GitHub Actions:

```yaml
- uses: actions/cache@v4
with:
path: ${{ runner.temp }}/socket-cache
key: socket-cli-<version>
- run: |
docker run --rm \
-e SOCKET_SECURITY_API_TOKEN \
-v "$PWD:/src" \
-v "${{ runner.temp }}/socket-cache:/root/.cache/socket" \
socketdev/cli:<version> --target-path /src --reach
env:
SOCKET_SECURITY_API_TOKEN: ${{ secrets.SOCKET_SECURITY_API_TOKEN }}
```

Keep the cache outside the directory being scanned. A cache restored for a
different version is harmless: the CLI downloads the version it needs.

### Keep image pulls cheap

- Pin a version tag, or a digest, rather than `latest`, so runners that already
have the image reuse it.
- Mirror the image to a registry close to your runners (GHCR, ECR, Artifact
Registry, Artifactory). This also avoids Docker Hub's pull rate limits.
- Ephemeral hosted runners pull the whole image on every job. Long-lived or
self-hosted runners pull it once per host.

### Verify the image

Each release image carries a provenance attestation and an SPDX SBOM:

```sh
docker buildx imagetools inspect socketdev/cli:<version> --format '{{ json .Provenance }}'
docker buildx imagetools inspect socketdev/cli:<version> --format '{{ json .SBOM }}'
```

The SBOM is generated from the built image, so it covers the Alpine packages and
the Python and npm packages installed in it. Toolchains installed from release
archives rather than a package manager, such as Rust (via rustup) and PyPy, are
listed thinly or not at all.

## Workflow templates

Prebuilt examples in this repo:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "hatchling.build"

[project]
name = "socketsecurity"
version = "2.11.11"
version = "2.11.12"
requires-python = ">= 3.11"
license = {"file" = "LICENSE"}
dependencies = [
Expand Down
2 changes: 1 addition & 1 deletion socketsecurity/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__author__ = 'socket.dev'
__version__ = '2.11.11'
__version__ = '2.11.12'
USER_AGENT_NAME = 'socket-python-cli'
USER_AGENT = f'{USER_AGENT_NAME}/{__version__}'
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading