Skip to content

Commit 5e0a92a

Browse files
committed
Attach an SBOM to the Docker image, retag stable, and document the image
Release images now carry an SPDX SBOM attestation next to the provenance attestation build-push-action already adds. Marking a release stable retags the image that release published instead of rebuilding it. The rebuild paired an older wheel with the default branch's Dockerfile, and gave users who had already pulled the release new layers to download. imagetools create carries the attestation manifests across. docs/ci-cd.md gains a Docker image section: what the image contains, how to persist the reachability engine cache between container runs, keeping pulls cheap in CI, and how to inspect the attestations.
1 parent 911331c commit 5e0a92a

7 files changed

Lines changed: 118 additions & 25 deletions

File tree

‎.github/workflows/docker-stable.yml‎

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,28 @@ jobs:
1717
with:
1818
persist-credentials: false
1919

20-
- name: Check if version exists in PyPI
21-
id: version_check
22-
env:
23-
INPUT_VERSION: ${{ inputs.version }}
24-
run: |
25-
if ! curl -s -f "https://pypi.org/pypi/socketsecurity/${INPUT_VERSION}/json" > /dev/null; then
26-
echo "Error: Version ${INPUT_VERSION} not found on PyPI"
27-
exit 1
28-
fi
29-
echo "Version ${INPUT_VERSION} found on PyPI - proceeding with release"
30-
3120
- name: Set up Docker publishing
3221
uses: $/.github/actions/setup-docker
3322
with:
23+
# Retagging copies manifests between tags; nothing is built.
24+
enable-qemu: "false"
3425
dockerhub-username: ${{ secrets.DOCKERHUB_USERNAME }}
3526
dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }}
3627

37-
- name: Build & Push Stable Docker
38-
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
39-
with:
40-
push: true
41-
platforms: linux/amd64,linux/arm64
42-
cache-from: type=gha
43-
cache-to: type=gha,mode=max
44-
tags: socketdev/cli:stable
45-
build-args: |
46-
CLI_VERSION=${{ inputs.version }}
47-
28+
# Point stable at the image the release already published instead of
29+
# rebuilding it. A rebuild would pair that release's wheel with today's
30+
# Dockerfile, and would give users who already pulled the release new
31+
# layers to download. The retag keeps the release's attestations.
32+
- name: Tag the release image as stable
33+
env:
34+
INPUT_VERSION: ${{ inputs.version }}
35+
run: |
36+
if ! printf '%s' "$INPUT_VERSION" | grep -Eq '^[0-9]+(\.[0-9A-Za-z-]+)+$'; then
37+
echo "Error: '${INPUT_VERSION}' is not a release version such as 1.2.3"
38+
exit 1
39+
fi
40+
if ! docker buildx imagetools inspect "socketdev/cli:${INPUT_VERSION}" > /dev/null; then
41+
echo "Error: socketdev/cli:${INPUT_VERSION} is not on Docker Hub"
42+
exit 1
43+
fi
44+
docker buildx imagetools create --tag socketdev/cli:stable "socketdev/cli:${INPUT_VERSION}"

‎.github/workflows/release.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ jobs:
119119
platforms: linux/amd64,linux/arm64
120120
cache-from: type=gha
121121
cache-to: type=gha,mode=max
122+
# Attach an SPDX SBOM generated from the built image, next to the
123+
# provenance attestation the action already adds.
124+
sbom: true
122125
tags: |
123126
socketdev/cli:latest
124127
socketdev/cli:${{ env.VERSION }}

‎CHANGELOG.md‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
# Changelog
22

3+
## 2.11.12
4+
5+
### Added: SBOM attestation on the Docker image
6+
7+
- Release images on Docker Hub now carry an SPDX SBOM attestation alongside the
8+
existing provenance attestation. See
9+
[Verify the image](docs/ci-cd.md#verify-the-image).
10+
11+
### Changed: `stable` points at the published release image
12+
13+
- Marking a release stable now retags the image that release published instead of
14+
rebuilding it, so `socketdev/cli:stable` is the same image as
15+
`socketdev/cli:<version>`, attestations included.
16+
17+
### Added: Docker image guide
18+
19+
- New [Docker image](docs/ci-cd.md#docker-image) section covering how to cache the
20+
reachability engine between container runs and keep image pulls cheap in CI.
21+
322
## 2.11.11
423

524
### Changed: use lowercase Python CLI User-Agent

‎docs/ci-cd.md‎

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,80 @@ Dashboard metadata unless `--integration` was explicitly supplied. PR comments
522522
remain limited to the existing GitHub and GitLab SCM adapters; Azure receives
523523
console output and Dashboard association but does not post a PR comment.
524524

525+
## Docker image
526+
527+
`socketdev/cli` on Docker Hub packages the CLI with the toolchains reachability
528+
analysis runs on: Node.js, Go, Java, .NET, Rust, Ruby, pyenv, and PyPy on
529+
`linux/amd64`. The toolchains are most of the image's size. Tags are published
530+
per release (`socketdev/cli:<version>`), plus `latest` and `stable`.
531+
532+
```sh
533+
docker run --rm \
534+
-e SOCKET_SECURITY_API_TOKEN \
535+
-v "$PWD:/src" \
536+
socketdev/cli:<version> --target-path /src --reach
537+
```
538+
539+
### Cache the reachability engine
540+
541+
With `--reach`, the CLI downloads its pinned reachability engine on first use and
542+
caches it under `$XDG_CACHE_HOME/socket/coana` (`/root/.cache/socket/coana` in the
543+
image). A new container starts with an empty cache, so without a persistent
544+
cache every run downloads the engine again. Mount a volume to keep it:
545+
546+
```sh
547+
docker run --rm \
548+
-e SOCKET_SECURITY_API_TOKEN \
549+
-v "$PWD:/src" \
550+
-v socket-cache:/root/.cache/socket \
551+
socketdev/cli:<version> --target-path /src --reach
552+
```
553+
554+
On CI runners that start every job on a fresh machine, mount a directory your CI
555+
provider caches instead, and key that cache on the CLI version, which determines
556+
the engine version. In GitHub Actions:
557+
558+
```yaml
559+
- uses: actions/cache@v4
560+
with:
561+
path: ${{ runner.temp }}/socket-cache
562+
key: socket-cli-<version>
563+
- run: |
564+
docker run --rm \
565+
-e SOCKET_SECURITY_API_TOKEN \
566+
-v "$PWD:/src" \
567+
-v "${{ runner.temp }}/socket-cache:/root/.cache/socket" \
568+
socketdev/cli:<version> --target-path /src --reach
569+
env:
570+
SOCKET_SECURITY_API_TOKEN: ${{ secrets.SOCKET_SECURITY_API_TOKEN }}
571+
```
572+
573+
Keep the cache outside the directory being scanned. A cache restored for a
574+
different version is harmless: the CLI downloads the version it needs.
575+
576+
### Keep image pulls cheap
577+
578+
- Pin a version tag, or a digest, rather than `latest`, so runners that already
579+
have the image reuse it.
580+
- Mirror the image to a registry close to your runners (GHCR, ECR, Artifact
581+
Registry, Artifactory). This also avoids Docker Hub's pull rate limits.
582+
- Ephemeral hosted runners pull the whole image on every job. Long-lived or
583+
self-hosted runners pull it once per host.
584+
585+
### Verify the image
586+
587+
Each release image carries a provenance attestation and an SPDX SBOM:
588+
589+
```sh
590+
docker buildx imagetools inspect socketdev/cli:<version> --format '{{ json .Provenance }}'
591+
docker buildx imagetools inspect socketdev/cli:<version> --format '{{ json .SBOM }}'
592+
```
593+
594+
The SBOM is generated from the built image, so it covers the Alpine packages and
595+
the Python and npm packages installed in it. Toolchains installed from release
596+
archives rather than a package manager, such as Rust (via rustup) and PyPy, are
597+
listed thinly or not at all.
598+
525599
## Workflow templates
526600

527601
Prebuilt examples in this repo:

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
66

77
[project]
88
name = "socketsecurity"
9-
version = "2.11.11"
9+
version = "2.11.12"
1010
requires-python = ">= 3.11"
1111
license = {"file" = "LICENSE"}
1212
dependencies = [

‎socketsecurity/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
__author__ = 'socket.dev'
2-
__version__ = '2.11.11'
2+
__version__ = '2.11.12'
33
USER_AGENT_NAME = 'socket-python-cli'
44
USER_AGENT = f'{USER_AGENT_NAME}/{__version__}'

‎uv.lock‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)