Skip to content
Merged
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
105 changes: 88 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ jobs:
- name: Test release tag validation
run: bash tests/release-tag.sh

- name: Test entrypoint path preparation
run: bash tests/entrypoint-paths.sh

- name: Test SPDX augmentation
run: python -m unittest discover --start-directory tests --pattern "test_*.py"

- name: Audit GitHub Actions security
uses: zizmorcore/zizmor-action@70fb788f84895a7701f5643d103d587e460b5c99 # v0.6.3
with:
Expand All @@ -51,11 +57,29 @@ jobs:
min-severity: medium

image:
runs-on: ubuntu-latest
timeout-minutes: 30
name: image (${{ matrix.architecture }})
strategy:
fail-fast: false
matrix:
include:
- architecture: amd64
runner: ubuntu-24.04
platform: linux/amd64
machine: x86_64
- architecture: arm64
runner: ubuntu-24.04-arm
platform: linux/arm64
machine: aarch64
runs-on: ${{ matrix.runner }}
timeout-minutes: 45
permissions:
contents: read
security-events: write
env:
TEST_IMAGE: ghcr.io/datopsis/clickhouse-server-ubi9:test-${{ matrix.architecture }}
SBOM_FILE: clickhouse-server-ubi9-${{ matrix.architecture }}.spdx.json
GRYPE_SARIF: grype-${{ matrix.architecture }}.sarif
GRYPE_ALL: grype-all-${{ matrix.architecture }}.json
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand All @@ -65,6 +89,11 @@ jobs:
- name: Set up Buildx
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0

- name: Confirm native runner architecture
env:
EXPECTED_MACHINE: ${{ matrix.machine }}
run: test "$(uname -m)" = "${EXPECTED_MACHINE}"

- name: Scan build configuration
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
Expand All @@ -79,21 +108,30 @@ jobs:
with:
context: .
file: Containerfile
platforms: ${{ matrix.platform }}
load: true
push: false
tags: ghcr.io/datopsis/clickhouse-server-ubi9:test
cache-from: type=gha
cache-to: type=gha,mode=max
tags: ${{ env.TEST_IMAGE }}
cache-from: type=gha,scope=image-${{ matrix.architecture }}
cache-to: type=gha,mode=max,scope=image-${{ matrix.architecture }}

- name: Confirm loaded image architecture
env:
EXPECTED_ARCHITECTURE: ${{ matrix.architecture }}
run: >-
test "$(docker image inspect --format '{{.Architecture}}' "${TEST_IMAGE}")"
= "${EXPECTED_ARCHITECTURE}"

- name: Run smoke tests
env:
IMAGE: ghcr.io/datopsis/clickhouse-server-ubi9:test
CONTAINER_RUNTIME: docker
IMAGE: ${{ env.TEST_IMAGE }}
run: bash tests/smoke.sh

- name: Scan image
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
image-ref: ghcr.io/datopsis/clickhouse-server-ubi9:test
image-ref: ${{ env.TEST_IMAGE }}
format: table
exit-code: "1"
ignore-unfixed: true
Expand All @@ -102,39 +140,72 @@ jobs:
- name: Generate SPDX SBOM with Syft
uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2
with:
image: ghcr.io/datopsis/clickhouse-server-ubi9:test
image: ${{ env.TEST_IMAGE }}
format: spdx-json
output-file: clickhouse-server-ubi9.spdx.json
output-file: ${{ env.SBOM_FILE }}
syft-version: v1.51.1
upload-artifact: false
upload-release-assets: false

- name: Add declared ClickHouse TGZ components to SPDX SBOM
run: >-
python scripts/augment-spdx.py
--input "${SBOM_FILE}"
--output "${SBOM_FILE}"

- name: Scan Syft SBOM with Grype
id: grype
uses: anchore/scan-action@27805bf3b4e84b4a5c980df22ed233c00390a439 # v7.4.2
with:
sbom: clickhouse-server-ubi9.spdx.json
sbom: ${{ env.SBOM_FILE }}
output-format: sarif
output-file: grype.sarif
output-file: ${{ env.GRYPE_SARIF }}
severity-cutoff: high
only-fixed: true
fail-build: true
cache-db: true
grype-version: v0.118.0

- name: Record all Grype findings
if: ${{ always() && hashFiles(env.SBOM_FILE) != '' }}
uses: anchore/scan-action@27805bf3b4e84b4a5c980df22ed233c00390a439 # v7.4.2
with:
sbom: ${{ env.SBOM_FILE }}
output-format: json
output-file: ${{ env.GRYPE_ALL }}
severity-cutoff: negligible
only-fixed: false
fail-build: false
cache-db: true
grype-version: v0.118.0

- name: Retain security artifacts
if: ${{ always() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: image-security-${{ github.sha }}
name: image-security-${{ github.sha }}-${{ matrix.architecture }}
path: |
clickhouse-server-ubi9.spdx.json
grype.sarif
${{ env.SBOM_FILE }}
${{ env.GRYPE_SARIF }}
${{ env.GRYPE_ALL }}
if-no-files-found: warn
retention-days: 14

- name: Publish Grype findings to code scanning
if: ${{ always() && github.event_name != 'pull_request' && hashFiles('grype.sarif') != '' }}
if: ${{ always() && github.event_name != 'pull_request' && hashFiles(env.GRYPE_SARIF) != '' }}
uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
with:
sarif_file: grype.sarif
category: grype-image
sarif_file: ${{ env.GRYPE_SARIF }}
category: grype-image-${{ matrix.architecture }}

image-result:
name: image
if: ${{ always() }}
needs: image
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Require every native image job
env:
MATRIX_RESULT: ${{ needs.image.result }}
run: test "${MATRIX_RESULT}" = success
39 changes: 39 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ jobs:
provenance: mode=max
sbom: true

- name: Verify published manifest architectures
env:
DIGEST: ${{ steps.build.outputs.digest }}
run: |
set -Eeuo pipefail
docker buildx imagetools inspect --raw "${IMAGE}@${DIGEST}" |
jq -e '
([.manifests[].platform | select(.os == "linux" and .architecture == "amd64")] | length >= 1)
and ([.manifests[].platform | select(.os == "linux" and .architecture == "arm64")] | length >= 1)
'

- name: Scan published image
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
Expand All @@ -89,6 +100,12 @@ jobs:
upload-artifact: false
upload-release-assets: false

- name: Add declared ClickHouse TGZ components to SPDX SBOM
run: >-
python scripts/augment-spdx.py
--input image.spdx.json
--output image.spdx.json

- name: Scan Syft SBOM with Grype
uses: anchore/scan-action@27805bf3b4e84b4a5c980df22ed233c00390a439 # v7.4.2
with:
Expand All @@ -98,6 +115,20 @@ jobs:
severity-cutoff: high
only-fixed: true
fail-build: true
cache-db: true
grype-version: v0.118.0

- name: Record all Grype findings
if: ${{ always() && hashFiles('image.spdx.json') != '' }}
uses: anchore/scan-action@27805bf3b4e84b4a5c980df22ed233c00390a439 # v7.4.2
with:
sbom: image.spdx.json
output-format: json
output-file: grype-all.json
severity-cutoff: negligible
only-fixed: false
fail-build: false
cache-db: true
grype-version: v0.118.0

- name: Retain release security artifacts
Expand All @@ -108,6 +139,7 @@ jobs:
path: |
image.spdx.json
grype.sarif
grype-all.json
if-no-files-found: warn
retention-days: 30

Expand All @@ -121,6 +153,13 @@ jobs:
- name: Install Cosign
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2

- name: Attest complete SPDX SBOM with GitHub OIDC
env:
DIGEST: ${{ steps.build.outputs.digest }}
run: >-
cosign attest --yes --predicate image.spdx.json --type spdxjson
"${IMAGE}@${DIGEST}"

- name: Sign image with GitHub OIDC
env:
DIGEST: ${{ steps.build.outputs.digest }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
.smoke-secrets.*/
/clickhouse-server-ubi9.spdx.json
/grype.sarif
/grype-all.json
/image.intoto.jsonl
/image.sigstore.json
/image.spdx.json
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- A documented container and repository versioning and release standard.
- CI security-layer, enforcement, result-review, and Endor Labs guidance.
- Structured bug reporting and pull-request review checklists.
- Production, TLS, disconnected-deployment, vulnerability-triage, upstream-license, and official-image comparison documentation.
- Entrypoint initialization and health checks over TLS-only native-port configurations.
- Complete Grype JSON inventories, including unfixed findings, retained beside the fixed High/Critical blocking result in CI and release runs.
- Explicit ClickHouse TGZ component records in SPDX inventories and a keyless, digest-bound complete SPDX release attestation.
- Rootless storage guidance for named volumes, bind mounts, Kubernetes/OpenShift identities, custom data paths, additional disks, SELinux, and NFS.
- Native AMD64 and ARM64 CI builds, smoke tests, vulnerability evidence, and release-manifest architecture validation.
- Explicit repository scope and official-image storage compatibility guidance, including the XML-based replacement for the unreleased `CLICKHOUSE_DATA_DIR` interface.
- Podman-first user procedures, a tested Podman support baseline, and rootless user-namespace permission guidance.

### Changed

- The entrypoint now derives primary and additional writable directories from the effective ClickHouse configuration, rejects the misleading `CLICKHOUSE_DATA_DIR` variable, and reports non-root permission failures before server startup.
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ This repository builds a security-oriented ClickHouse Server container on Red Ha
Build and test commands are documented in `README.md`. The primary local verification is:

```bash
docker build --file Containerfile --tag ghcr.io/datopsis/clickhouse-server-ubi9:test .
IMAGE=ghcr.io/datopsis/clickhouse-server-ubi9:test bash tests/smoke.sh
podman build --format docker --file Containerfile --tag ghcr.io/datopsis/clickhouse-server-ubi9:test .
CONTAINER_RUNTIME=podman IMAGE=ghcr.io/datopsis/clickhouse-server-ubi9:test bash tests/smoke.sh
```

## Git conventions
Expand Down
5 changes: 2 additions & 3 deletions Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ RUN microdnf install -y dnf gzip tar \
/runtime/docker-entrypoint-initdb.d \
/runtime/etc/clickhouse-server/config.d \
/runtime/etc/clickhouse-server/users.d \
/runtime/var/lib/clickhouse/generated \
/runtime/var/lib/clickhouse \
/runtime/var/log/clickhouse-server \
&& chown -R 101:0 \
/runtime/docker-entrypoint-initdb.d \
Expand Down Expand Up @@ -86,8 +86,7 @@ COPY --chown=101:0 --chmod=0644 container/config.d/container.xml /etc/clickhouse

ENV LANG="C.UTF-8" \
TZ="UTC" \
CLICKHOUSE_CONFIG="/etc/clickhouse-server/config.xml" \
CLICKHOUSE_DATA_DIR="/var/lib/clickhouse"
CLICKHOUSE_CONFIG="/etc/clickhouse-server/config.xml"

USER 101:0
WORKDIR /var/lib/clickhouse
Expand Down
Loading
Loading