diff --git a/.github/workflows/push-to-dockerhub.yml b/.github/workflows/push-to-dockerhub.yml index 1565b9c..26a9cfd 100644 --- a/.github/workflows/push-to-dockerhub.yml +++ b/.github/workflows/push-to-dockerhub.yml @@ -46,6 +46,7 @@ jobs: version: "20260302-001" os_version: "php81" build_args: "php_version=8.1" + platforms: linux/amd64,linux/arm64 secrets: inherit simplerisk-minimal-php83: name: 'Push simplerisk/simplerisk-minimal image based on PHP 8.3 with Apache' @@ -58,4 +59,5 @@ jobs: os_version: "php83" main_image: true build_args: "php_version=8.3" + platforms: linux/amd64,linux/arm64 secrets: inherit diff --git a/.github/workflows/push-to-dockerhub_rw.yml b/.github/workflows/push-to-dockerhub_rw.yml index 9242c5d..d9a0c2b 100644 --- a/.github/workflows/push-to-dockerhub_rw.yml +++ b/.github/workflows/push-to-dockerhub_rw.yml @@ -30,6 +30,10 @@ on: build_args: description: Arguments to use on image at runtime type: string + platforms: + description: Target platforms for the build (e.g. linux/amd64,linux/arm64) + default: linux/amd64 + type: string secrets: DOCKER_USERNAME: required: true @@ -43,6 +47,12 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Log in to Docker Hub uses: docker/login-action@v3 with: @@ -64,10 +74,13 @@ jobs: file: ${{ inputs.dockerfile_path }} push: ${{ github.event_name != 'pull_request' }} build-args: ${{ inputs.build_args || '' }} + platforms: ${{ inputs.platforms }} tags: | ${{ inputs.image_name }} ${{ inputs.image_name }}:${{ inputs.version }} labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha,scope=${{ inputs.os_version }} + cache-to: type=gha,mode=max,scope=${{ inputs.os_version }} - name: Build and push specific Docker image id: build-and-push-spec @@ -77,7 +90,10 @@ jobs: file: ${{ inputs.dockerfile_path }} push: ${{ github.event_name != 'pull_request' }} build-args: ${{ inputs.build_args || '' }} + platforms: ${{ inputs.platforms }} tags: | ${{ inputs.image_name }}:${{ inputs.version }}-${{ inputs.os_version }} labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha,scope=${{ inputs.os_version }} + cache-to: type=gha,mode=max,scope=${{ inputs.os_version }} diff --git a/.github/workflows/verify-image_rw.yml b/.github/workflows/verify-image_rw.yml index 6b1b5ab..22c65f1 100644 --- a/.github/workflows/verify-image_rw.yml +++ b/.github/workflows/verify-image_rw.yml @@ -34,10 +34,7 @@ jobs: image: ${{ inputs.image_tag }} failure-threshold: FATAL dockle-host: "unix:///var/run/docker.sock" + - name: Install Grype + run: curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin - name: Scan vulnerabilities with Grype - uses: anchore/scan-action@v3 - with: - image: ${{ inputs.image_tag }} - only-fixed: true - output-format: table - severity-cutoff: critical + run: grype -o table --fail-on critical --only-fixed ${{ inputs.image_tag }} diff --git a/.gitignore b/.gitignore index 04793e3..fe2ddac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /.direnv/ **/*.swp **/*.sql +/.idea diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c51e716 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,99 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +This repo contains the official SimpleRisk Docker images — a GRC (Governance, Risk, and Compliance) platform. Two images are maintained: + +- **`simplerisk/`** — Full-stack: Ubuntu-based, bundles Apache, PHP, MySQL 8.0, and mail utilities in a single container. Managed by Supervisor (Apache, rsyslog, cron). +- **`simplerisk-minimal/`** — Microservices-oriented: `php:8.x-apache` base, no bundled database. Runs as non-root `simplerisk` user. Requires an external MySQL instance. + +Both images use multi-stage builds (Alpine curl downloader stage → main stage), auto-generate self-signed SSL certificates, and install the SimpleRisk application bundle from upstream. + +## Common Commands + +### Build images locally + +```bash +# Full-stack (build args: ubuntu_version_code=jammy|noble) +docker build -t simplerisk/simplerisk simplerisk/ + +# Minimal (build args: php_version=8.1|8.3|8.4) +docker build -t simplerisk/simplerisk-minimal simplerisk-minimal/ +``` + +### Run locally + +```bash +# Full-stack standalone +docker run --name simplerisk -d -p 80:80 -p 443:443 simplerisk/simplerisk + +# Minimal with Docker Compose (includes MySQL + SMTP) +docker-compose -f simplerisk-minimal/stack.yml up -d +``` + +### Lint shell scripts + +```bash +# ShellCheck on all .sh files (severity: error) +# This runs in CI via .github/workflows/shellcheck.yml +# Install shellcheck locally or use the Nix dev environment +shellcheck simplerisk/entrypoint.sh simplerisk-minimal/entrypoint.sh +``` + +### Release a new version + +```bash +make update_version VERSION=YYYYMMDD-NNN +``` + +This runs four scripts in sequence: +1. `update_workflows.sh` — patches version in push workflow files +2. `simplerisk/generate_dockerfile.sh` — regenerates the full-stack Dockerfile from a template +3. `simplerisk-minimal/update_stack_and_workflows.sh` — regenerates `stack.yml` (with a fresh random password) and updates workflow files +4. `simplerisk-minimal/generate_dockerfile.sh` — regenerates the minimal Dockerfile + +### Nix dev environment + +```bash +nix develop # or: direnv allow (if using .envrc) +``` + +Provides: `docker-compose`, `dockle`, `grype`, `gorin`, `hadolint`. + +## Architecture & Key Patterns + +### Dockerfile generation + +Neither Dockerfile is hand-edited directly for version bumps. They are regenerated by `generate_dockerfile.sh` scripts. Edit the generator scripts when changing image structure; edit the Dockerfiles only for one-off experiments. + +### entrypoint.sh (both images) + +The entrypoint script handles: +- Writing `config.php` by substituting env vars via `sed` +- Automatic database provisioning (`DB_SETUP=automatic|automatic-only|manual|delete`) +- SSL certificate generation (minimal image generates a CA + signed cert; full-stack generates a self-signed cert) +- Cron setup (`SIMPLERISK_CRON_SETUP` in minimal; always-on in full-stack) +- Supervisor start (full-stack) or `apache2-foreground` (minimal) + +### Key environment variables (simplerisk-minimal) + +| Variable | Purpose | +|---|---| +| `DB_SETUP` | `automatic`, `automatic-only`, `manual`, `delete` | +| `DB_SETUP_PASS` | Password used when setting up the DB | +| `SIMPLERISK_DB_HOSTNAME` | External DB host | +| `SIMPLERISK_DB_USERNAME/PASSWORD/DATABASE` | DB credentials | +| `SIMPLERISK_CRON_SETUP` | Enable/disable PHP cron (default: enabled) | +| `SIMPLERISK_CSRF_SECRET` | Override auto-generated CSRF secret | + +### CI/CD + +- **PRs** trigger `container-validation.yml`: builds all 4 variants (jammy, noble, php81, php83), runs Dockle (Dockerfile linter) and Grype (CVE scanner, severity cutoff: critical, only-fixed). +- **Pushes** trigger separate workflows to publish to Docker Hub and GitHub Container Registry (GHCR). GHCR images are signed with Cosign/sigstore. +- The reusable workflow files (`*_rw.yml`) are called by the entry-point workflows. + +### Vulnerability ignore list + +`.grype.yaml` tracks CVEs intentionally ignored (e.g., unfixable at time of release). Update this file when suppressing a new finding, always with a comment explaining why.