Spaces:
Build error
Build error
Commit ·
ccb92e5
1
Parent(s): 87146ac
Add supply chain hardening: SBOM, cosign signing, pinned digests, Dependabot
Browse filesEnterprise supply chain improvements:
- publish.yml: Generate CycloneDX SBOM and attach to GitHub releases
- docker.yml: Sign all Docker images with Sigstore cosign (keyless OIDC)
- Dockerfile: Pin python:3.11-slim and distroless base images with SHA256
digests to prevent silent upstream changes
- Add .github/dependabot.yml for automated Docker digest, GitHub Actions,
and pip dependency update PRs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- .github/dependabot.yml +27 -0
- .github/workflows/docker.yml +17 -0
- .github/workflows/publish.yml +15 -2
- .gitignore +3 -0
- Dockerfile +7 -3
.github/dependabot.yml
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version: 2
|
| 2 |
+
updates:
|
| 3 |
+
# Docker base image digest updates
|
| 4 |
+
- package-ecosystem: docker
|
| 5 |
+
directory: /
|
| 6 |
+
schedule:
|
| 7 |
+
interval: weekly
|
| 8 |
+
commit-message:
|
| 9 |
+
prefix: "docker"
|
| 10 |
+
|
| 11 |
+
# GitHub Actions version updates
|
| 12 |
+
- package-ecosystem: github-actions
|
| 13 |
+
directory: /
|
| 14 |
+
schedule:
|
| 15 |
+
interval: weekly
|
| 16 |
+
commit-message:
|
| 17 |
+
prefix: "ci"
|
| 18 |
+
|
| 19 |
+
# Python dependency updates (pip)
|
| 20 |
+
- package-ecosystem: pip
|
| 21 |
+
directory: /
|
| 22 |
+
schedule:
|
| 23 |
+
interval: weekly
|
| 24 |
+
commit-message:
|
| 25 |
+
prefix: "deps"
|
| 26 |
+
# Only open PRs for security updates to avoid noise
|
| 27 |
+
open-pull-requests-limit: 5
|
.github/workflows/docker.yml
CHANGED
|
@@ -12,6 +12,7 @@ env:
|
|
| 12 |
permissions:
|
| 13 |
contents: read
|
| 14 |
packages: write
|
|
|
|
| 15 |
|
| 16 |
jobs:
|
| 17 |
docker-variant-tags:
|
|
@@ -81,3 +82,19 @@ jobs:
|
|
| 81 |
set: |
|
| 82 |
*.cache-from=type=gha
|
| 83 |
*.cache-to=type=gha,mode=max
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
permissions:
|
| 13 |
contents: read
|
| 14 |
packages: write
|
| 15 |
+
id-token: write # For cosign keyless signing via Sigstore OIDC
|
| 16 |
|
| 17 |
jobs:
|
| 18 |
docker-variant-tags:
|
|
|
|
| 82 |
set: |
|
| 83 |
*.cache-from=type=gha
|
| 84 |
*.cache-to=type=gha,mode=max
|
| 85 |
+
|
| 86 |
+
- name: Install cosign
|
| 87 |
+
uses: sigstore/cosign-installer@v3
|
| 88 |
+
|
| 89 |
+
- name: Sign images with cosign (keyless via Sigstore OIDC)
|
| 90 |
+
env:
|
| 91 |
+
BAKE_META: ${{ steps.bake.outputs.metadata }}
|
| 92 |
+
run: |
|
| 93 |
+
# Extract all pushed image digests from bake metadata and sign each
|
| 94 |
+
echo "$BAKE_META" | jq -r '
|
| 95 |
+
to_entries[].value."containerimage.digest" // empty
|
| 96 |
+
' | while read -r digest; do
|
| 97 |
+
image="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${digest}"
|
| 98 |
+
echo "Signing ${image}"
|
| 99 |
+
cosign sign --yes "${image}"
|
| 100 |
+
done
|
.github/workflows/publish.yml
CHANGED
|
@@ -9,7 +9,8 @@ jobs:
|
|
| 9 |
runs-on: ubuntu-latest
|
| 10 |
environment: pypi
|
| 11 |
permissions:
|
| 12 |
-
id-token: write
|
|
|
|
| 13 |
|
| 14 |
steps:
|
| 15 |
- uses: actions/checkout@v4
|
|
@@ -21,11 +22,23 @@ jobs:
|
|
| 21 |
|
| 22 |
- name: Install build tools
|
| 23 |
run: |
|
| 24 |
-
python -m pip install --upgrade pip build
|
| 25 |
|
| 26 |
- name: Build package
|
| 27 |
run: |
|
| 28 |
python -m build
|
| 29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
- name: Publish to PyPI
|
| 31 |
uses: pypa/gh-action-pypi-publish@release/v1
|
|
|
|
| 9 |
runs-on: ubuntu-latest
|
| 10 |
environment: pypi
|
| 11 |
permissions:
|
| 12 |
+
id-token: write # For trusted publishing
|
| 13 |
+
contents: write # For uploading release assets
|
| 14 |
|
| 15 |
steps:
|
| 16 |
- uses: actions/checkout@v4
|
|
|
|
| 22 |
|
| 23 |
- name: Install build tools
|
| 24 |
run: |
|
| 25 |
+
python -m pip install --upgrade pip build cyclonedx-bom
|
| 26 |
|
| 27 |
- name: Build package
|
| 28 |
run: |
|
| 29 |
python -m build
|
| 30 |
|
| 31 |
+
- name: Generate SBOM (CycloneDX)
|
| 32 |
+
run: |
|
| 33 |
+
pip install -e ".[proxy]"
|
| 34 |
+
cyclonedx-py environment \
|
| 35 |
+
--output-format json \
|
| 36 |
+
--outfile dist/headroom-sbom.cdx.json
|
| 37 |
+
|
| 38 |
+
- name: Upload SBOM to release
|
| 39 |
+
uses: softprops/action-gh-release@v2
|
| 40 |
+
with:
|
| 41 |
+
files: dist/headroom-sbom.cdx.json
|
| 42 |
+
|
| 43 |
- name: Publish to PyPI
|
| 44 |
uses: pypa/gh-action-pypi-publish@release/v1
|
.gitignore
CHANGED
|
@@ -8,6 +8,9 @@ scripts/*
|
|
| 8 |
# Swift SDK (separate repo)
|
| 9 |
swift/
|
| 10 |
|
|
|
|
|
|
|
|
|
|
| 11 |
# Audit/scan outputs (contain security findings — never commit)
|
| 12 |
bandit_result.txt
|
| 13 |
pip_audit_result.txt
|
|
|
|
| 8 |
# Swift SDK (separate repo)
|
| 9 |
swift/
|
| 10 |
|
| 11 |
+
# Local planning docs (never commit)
|
| 12 |
+
ENTERPRISE_HARDENING.md
|
| 13 |
+
|
| 14 |
# Audit/scan outputs (contain security findings — never commit)
|
| 15 |
bandit_result.txt
|
| 16 |
pip_audit_result.txt
|
Dockerfile
CHANGED
|
@@ -1,10 +1,14 @@
|
|
| 1 |
ARG PYTHON_VERSION=3.11
|
| 2 |
ARG UV_VERSION=0.6.17
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
ARG DISTROLESS_IMAGE=gcr.io/distroless/python3-debian13
|
| 4 |
ARG PYTHON_SITE_PACKAGES=/usr/local/lib/python${PYTHON_VERSION}/site-packages
|
| 5 |
|
| 6 |
# ---- Build stage: compile native extensions, build wheel ----
|
| 7 |
-
FROM python:${PYTHON_VERSION}-slim AS builder
|
| 8 |
|
| 9 |
ARG UV_VERSION
|
| 10 |
|
|
@@ -32,7 +36,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
|
|
| 32 |
uv pip install --system --no-deps --reinstall-package headroom-ai .
|
| 33 |
|
| 34 |
# ---- Runtime stage (python-slim): supports root/nonroot via build arg ----
|
| 35 |
-
FROM python:${PYTHON_VERSION}-slim AS runtime-slim-base
|
| 36 |
|
| 37 |
ARG RUNTIME_USER=nonroot
|
| 38 |
ARG PYTHON_SITE_PACKAGES
|
|
@@ -69,7 +73,7 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
|
|
| 69 |
ENTRYPOINT ["headroom", "proxy"]
|
| 70 |
CMD ["--host", "0.0.0.0", "--port", "8787"]
|
| 71 |
|
| 72 |
-
FROM ${DISTROLESS_IMAGE} AS runtime-slim
|
| 73 |
|
| 74 |
ARG RUNTIME_USER=nonroot
|
| 75 |
ARG PYTHON_SITE_PACKAGES
|
|
|
|
| 1 |
ARG PYTHON_VERSION=3.11
|
| 2 |
ARG UV_VERSION=0.6.17
|
| 3 |
+
# Pinned 2026-04-15. Update via Dependabot or: docker pull python:3.11-slim
|
| 4 |
+
ARG PYTHON_DIGEST=sha256:233de06753d30d120b1a3ce359d8d3be8bda78524cd8f520c99883bfe33964cf
|
| 5 |
+
# Pinned 2026-04-15. Update via Dependabot or: docker pull gcr.io/distroless/python3-debian13
|
| 6 |
+
ARG DISTROLESS_DIGEST=sha256:ed3a4beb46f8f8baac068743ba1b1f95ea3f793422129cf6dd23967f779b6018
|
| 7 |
ARG DISTROLESS_IMAGE=gcr.io/distroless/python3-debian13
|
| 8 |
ARG PYTHON_SITE_PACKAGES=/usr/local/lib/python${PYTHON_VERSION}/site-packages
|
| 9 |
|
| 10 |
# ---- Build stage: compile native extensions, build wheel ----
|
| 11 |
+
FROM python:${PYTHON_VERSION}-slim@${PYTHON_DIGEST} AS builder
|
| 12 |
|
| 13 |
ARG UV_VERSION
|
| 14 |
|
|
|
|
| 36 |
uv pip install --system --no-deps --reinstall-package headroom-ai .
|
| 37 |
|
| 38 |
# ---- Runtime stage (python-slim): supports root/nonroot via build arg ----
|
| 39 |
+
FROM python:${PYTHON_VERSION}-slim@${PYTHON_DIGEST} AS runtime-slim-base
|
| 40 |
|
| 41 |
ARG RUNTIME_USER=nonroot
|
| 42 |
ARG PYTHON_SITE_PACKAGES
|
|
|
|
| 73 |
ENTRYPOINT ["headroom", "proxy"]
|
| 74 |
CMD ["--host", "0.0.0.0", "--port", "8787"]
|
| 75 |
|
| 76 |
+
FROM ${DISTROLESS_IMAGE}@${DISTROLESS_DIGEST} AS runtime-slim
|
| 77 |
|
| 78 |
ARG RUNTIME_USER=nonroot
|
| 79 |
ARG PYTHON_SITE_PACKAGES
|