https://github.com/anthony-spruyt/container-images
Container images built from upstream sources or custom Dockerfiles, with automated security scanning, release management, and SLSA provenance
https://github.com/anthony-spruyt/container-images
chrony container container-image containers docker docker-container docker-image docker-images llm-guard llm-guardrail llm-guardrails megalinter
Last synced: 11 days ago
JSON representation
Container images built from upstream sources or custom Dockerfiles, with automated security scanning, release management, and SLSA provenance
- Host: GitHub
- URL: https://github.com/anthony-spruyt/container-images
- Owner: anthony-spruyt
- License: mit
- Created: 2026-01-01T04:17:52.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2026-06-06T02:05:29.000Z (20 days ago)
- Last Synced: 2026-06-06T04:22:44.042Z (19 days ago)
- Topics: chrony, container, container-image, containers, docker, docker-container, docker-image, docker-images, llm-guard, llm-guardrail, llm-guardrails, megalinter
- Language: Shell
- Homepage:
- Size: 1.19 MB
- Stars: 1
- Watchers: 0
- Forks: 1
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Codeowners: .github/CODEOWNERS
- Security: SECURITY.md
Awesome Lists containing this project
README
# Container Images
[](https://github.com/anthony-spruyt/container-images/blob/main/LICENSE) [](https://github.com/anthony-spruyt/container-images/actions/workflows/ci.yaml)
[](https://github.com/anthony-spruyt/container-images/actions/workflows/trivy-scan.yaml) [](https://github.com/anthony-spruyt/container-images/stargazers)
[](https://github.com/anthony-spruyt/container-images/forks) [](https://github.com/anthony-spruyt/container-images/graphs/contributors)
[](https://github.com/anthony-spruyt/container-images/issues)
Container images built from upstream sources or custom Dockerfiles, published to GitHub Container Registry with automated security scanning and SLSA provenance.
## Development
See [DEVELOPMENT.md](DEVELOPMENT.md) for development environment setup.
## Usage
Pull an image:
```bash
docker pull ghcr.io/anthony-spruyt/chrony:latest
```
## Adding a New Image
### Option 1: Build from Upstream Source
Use this when building from an external repository (e.g., a GitHub project):
1. Create a directory with the image name
2. Add `metadata.yaml`:
```yaml
upstream: owner/repo
version: "1.0.0"
```
3. Optionally add a custom `Dockerfile` to override the upstream's
4. Push to main - the image will be built and published automatically
### Option 2: Build from Local Dockerfile
Use this for custom images with no upstream source:
1. Create a directory with the image name
2. Add your `Dockerfile` and any required files
3. Add `metadata.yaml`:
```yaml
version: "1.0.0"
```
4. Push to main - the image will be built and published automatically
### Option 3: Auto-Patched Version
For images where CI should auto-increment the patch version on each build, specify only the base version and set `auto_patch: true`:
```yaml
version: "1.1"
auto_patch: true
```
CI appends `.N` automatically (e.g., `1.1.0`, `1.1.1`, `1.1.2`). Do **not** include the patch segment in `version` — writing `"1.1.0"` with `auto_patch: true` would produce `1.1.0.0`.
### Automatic Configuration
- **Upstream validation** - Uses each image's own `metadata.yaml` as source of truth
- **Renovate tracking** - Add `# renovate:` annotations to `metadata.yaml` for automatic version updates
## Adding a Custom MegaLinter Flavor
Custom MegaLinter flavors extend official flavors with additional linters. The `megalinter-factory/` directory contains tooling to generate flavor files from a simple configuration.
### Using Claude Code (Recommended)
The `/create-megalinter-flavor` command automates flavor creation with automatic base flavor selection:
```bash
# With specific linters
/create-megalinter-flavor my-ci ACTION_ACTIONLINT,MARKDOWN_MARKDOWNLINT,BASH_SHELLCHECK
# Interactive mode (prompts for linter selection)
/create-megalinter-flavor my-ci
```
The command will:
1. Validate the flavor name and check for conflicts
2. Look up linter configurations from the catalog
3. Auto-select the optimal base flavor (minimizing custom installs)
4. Generate `megalinter-/flavor.yaml` with Renovate annotations
### Manual Setup
1. Create a directory for your flavor:
```bash
mkdir megalinter-/
```
2. Create `flavor.yaml` with your configuration:
```yaml
name: my-flavor
description: "MegaLinter for my use case"
# renovate: datasource=docker depName=oxsecurity/megalinter-ci_light
upstream_image: "oxsecurity/megalinter-ci_light:v9.3.0@sha256:..."
custom_linters:
- ACTION_ACTIONLINT
- MARKDOWN_MARKDOWNLINT
- PYTHON_BANDIT
```
3. Commit `flavor.yaml` - CI generates Dockerfile, test.sh, and metadata.yaml, then builds automatically
### Available Linters
Linter information is extracted directly from MegaLinter's descriptors at build time. The generator automatically fetches the latest versions from .
### Version Updates
Linter versions are automatically extracted from MegaLinter at build time - no manual tracking needed. The weekly scheduled rebuild workflow picks up any new linter versions.
For the base image, Renovate tracks the upstream MegaLinter version:
```yaml
# renovate: datasource=docker depName=oxsecurity/megalinter-ci_light
upstream_image: "oxsecurity/megalinter-ci_light:v9.3.0@sha256:..."
```
When Renovate creates a PR updating `flavor.yaml`, CI regenerates the Dockerfile and builds.
### Local Development
To test locally, generate files first:
```bash
pip install pyyaml jinja2
python megalinter-factory/generate.py megalinter-/
```
Generated files (`Dockerfile`, `test.sh`) are regenerated by CI at build time.
## Build Triggers
### Automatic
Pushing changes to `metadata.yaml`, `Dockerfile`, `flavor.yaml`, or `assets/` on main triggers a build using the version in metadata. Changes to `megalinter-factory/` trigger rebuilds of all flavors.
### Manual / n8n Integration
Trigger via GitHub API (workflow_dispatch):
```bash
# Dry run (default) - builds and scans but doesn't push or release
curl -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/anthony-spruyt/container-images/actions/workflows/ci.yaml/dispatches \
-d '{"ref":"main","inputs":{"image":"chrony","version":"4.6.1"}}'
# Production build - pushes to GHCR and creates release
curl -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/anthony-spruyt/container-images/actions/workflows/ci.yaml/dispatches \
-d '{"ref":"main","inputs":{"image":"chrony","version":"4.6.1","dry_run":"false"}}'
```
Parameters:
- **image** (required): Image directory name (e.g., `chrony`, `ssh-key-rotation`)
- **version** (optional): Semver tag to build (e.g., `4.6.1`) - checks out this tag from upstream
- **dry_run** (optional, default: `true`): When `true`, builds and scans the image but skips push to GHCR and release creation. Set to `false` for production builds.
## Automatic Version Updates
### Renovate (Recommended)
Add a Renovate annotation to `metadata.yaml` for automatic version tracking:
```yaml
upstream: owner/repo
# renovate: datasource=github-tags depName=owner/repo
version: "1.0.0"
```
Supported datasources:
- `github-tags` - GitHub repository tags
- `github-releases` - GitHub releases
- `docker` - Docker Hub or container registries
When Renovate detects a new version, it creates a PR. Merging triggers the build automatically.
### n8n Workflow (Special Cases)
For upstream sources Renovate cannot monitor (e.g., Alpine packages), use n8n workflows. See `chrony/n8n-release-watcher.json` for an example that monitors Alpine package versions and triggers builds via workflow_dispatch
## Security
See [SECURITY.md](SECURITY.md) for security policy and controls.