Fix docs
All checks were successful
Build and Publish Docker Image / test (push) Successful in 1m34s
Build and Publish Docker Image / build-and-push (push) Successful in 13s

This commit is contained in:
Andras Schmelczer 2026-10-27 21:56:39 +00:00
commit 147fcd3c28
2 changed files with 61 additions and 26 deletions

View file

@ -58,7 +58,7 @@ This is a Rust-based Docker Compose updater service that automatically updates i
- **Configuration-driven**: All behavior controlled through `config.yaml` including paths, schedules, registries, and update strategies. - **Configuration-driven**: All behavior controlled through `config.yaml` including paths, schedules, registries, and update strategies.
- **Preserves formatting**: Uses line-by-line regex parsing rather than full YAML parsing to maintain comments and formatting. - **Preserves formatting**: Uses line-by-line regex parsing rather than full YAML parsing to maintain comments and formatting.
- **Flexible update strategies**: Supports different version update approaches (latest patch of previous minor, latest patch, latest minor, latest). - **Flexible update strategies**: Supports `LatestPatchOfPreviousMinor` (the highest patch of the newest available release line below the latest published line) and `Latest`. Both only apply targets newer than the current version.
- **Registry abstraction**: Generic registry client that works with multiple container registries. - **Registry abstraction**: Generic registry client that works with multiple container registries.
- **Health monitoring**: Built-in health server for monitoring service status. - **Health monitoring**: Built-in health server for monitoring service status.
@ -80,4 +80,4 @@ The system supports different update strategies defined in `config.rs`:
- Unit tests are embedded in each module using `#[cfg(test)]` - Unit tests are embedded in each module using `#[cfg(test)]`
- Integration tests are in the `tests/` directory - Integration tests are in the `tests/` directory
- Uses `tempfile` for testing file operations - Uses `tempfile` for testing file operations
- Tests cover compose file parsing, image reference parsing, and scheduler creation - Tests cover compose file parsing, image reference parsing, and scheduler creation

View file

@ -64,8 +64,6 @@ services:
- GITHUB_TOKEN=${GITHUB_TOKEN} - GITHUB_TOKEN=${GITHUB_TOKEN}
- RUST_LOG=info - RUST_LOG=info
volumes: volumes:
# Mount Docker socket (read-only for security)
- /var/run/docker.sock:/var/run/docker.sock:ro
# Mount compose files directory # Mount compose files directory
- ./compose-files:/app/compose-files:rw - ./compose-files:/app/compose-files:rw
# Mount configuration # Mount configuration
@ -109,18 +107,42 @@ images if retries are exhausted. Warnings include the image and backend.
## Update Strategies ## Update Strategies
The service supports three intelligent update strategies, defaulting to the most conservative: The service supports two update strategies, defaulting to `LatestPatchOfPreviousMinor`.
Both strategies consider only parseable registry tags with the same prefix and
suffix as the current tag. A selected target is applied only when its version is
strictly greater than the current version. Equal or older targets leave the
Compose file unchanged, so neither strategy downgrades an image.
### `LatestPatchOfPreviousMinor` ### `LatestPatchOfPreviousMinor`
- **Predictable**: Always updates to the latest patch of the previous minor version
- **Consistent Behaviour**: Never updates to the current latest minor Selects the highest patch in the newest available release line below the latest
- **Example**: `1.5.3` → `1.4.8` published line. A release line is a `(major, minor)` pair. Selection uses the
available registry versions; it does not subtract one from the installed minor
version. It can skip missing minor lines or cross a major-version gap. If there
is no older matching release line, no target is selected.
The following examples use illustrative registry tag sets:
| Current tag | Available matching registry tags | Selected target | Result |
| --- | --- | --- | --- |
| `1.3.2` | `1.3.2`, `1.4.7`, `1.4.8`, `1.5.3` | `1.4.8` | Update to `1.4.8` |
| `1.4.8` | `1.3.2`, `1.4.7`, `1.4.8`, `1.5.3` | `1.4.8` | Unchanged: equal version |
| `1.5.3` | `1.3.2`, `1.4.7`, `1.4.8`, `1.5.3` | `1.4.8` | Unchanged: downgrade prevented |
| `2.1.0` | `2.1.0`, `2.3.5`, `2.5.2` | `2.3.5` | Update to `2.3.5`, skipping the missing `2.4` line |
| `4.0.15` | `4.0.15`, `4.0.19`, `5.14` | `4.0.19` | Update to `4.0.19` across the gap below `5.14` |
| `1.5.1` | `1.5.1`, `1.5.3` | None | Unchanged: only one release line available |
### `Latest` ### `Latest`
- **Aggressive**: Updates to the absolute latest available version
- **Cutting Edge**: Useful for development environments Selects the highest available matching version, including major-version updates.
- **Example**: `1.5.3` → `2.1.0` The same no-downgrade guard applies:
| Current tag | Available matching registry tags | Selected target | Result |
| --- | --- | --- | --- |
| `1.5.3` | `1.4.8`, `1.5.3`, `2.1.0` | `2.1.0` | Update to `2.1.0` |
| `2.1.0` | `1.4.8`, `1.5.3`, `2.1.0` | `2.1.0` | Unchanged: equal version |
| `2.1.0` | `1.4.8`, `1.5.3` | `1.5.3` | Unchanged: downgrade prevented |
## Advanced Version Handling ## Advanced Version Handling
@ -171,29 +193,31 @@ registries:
## Supported Image Formats ## Supported Image Formats
The updater handles various image naming conventions: The updater handles various image naming conventions. These examples show image
references; update targets depend on the strategy and available registry tags as
described above.
```yaml ```text
# Standard Docker Hub images # Standard Docker Hub images
nginx:1.21.0 → nginx:1.20.6 nginx:1.21.0
ubuntu:20.04 → ubuntu:18.04 ubuntu:24.10
# Namespaced images # Namespaced images
bitnami/nginx:1.21.0 → bitnami/nginx:1.20.6 bitnami/nginx:1.21.0
library/postgres:13.7 → library/postgres:12.11 library/postgres:13.7
# Custom registries # Custom registries
ghcr.io/user/app:v1.0.0 → ghcr.io/user/app:v0.9.5 ghcr.io/user/app:v1.0.0
registry.example.com/team/service:2.1.3 → registry.example.com/team/service:2.0.9 registry.example.com/team/service:2.1.3
# Complex versioning # Complex versioning
nginx:1.21.0-alpine → nginx:1.20.6-alpine nginx:1.21.0-alpine
postgres:13.7-bullseye → postgres:12.11-bullseye postgres:13.7-bullseye
redis:v7.0.0-alpine3.16 → redis:v6.2.7-alpine3.16 redis:v7.0.0-alpine3.16
# Local development (typically ignored) # Local development (ignored by the Quick Start ignore_images configuration)
localhost:5000/myapp:latest → [ignored by default] localhost:5000/myapp:latest
127.0.0.1:8080/service:dev → [ignored by default] 127.0.0.1:8080/service:dev
``` ```
## Health Monitoring & Observability ## Health Monitoring & Observability
@ -226,11 +250,22 @@ The service reports:
- **Non-Root Execution**: Designed to run as non-root user in containers - **Non-Root Execution**: Designed to run as non-root user in containers
- **Minimal Attack Surface**: Alpine Linux base image with minimal packages - **Minimal Attack Surface**: Alpine Linux base image with minimal packages
- **Read-Only Docker Socket**: Only requires read access to Docker socket - **No Docker Daemon Access Required**: Queries registries and edits Compose files without a Docker socket mount
- **Secret Management**: All tokens provided via environment variables - **Secret Management**: All tokens provided via environment variables
- **Input Validation**: Comprehensive validation of all configuration inputs - **Input Validation**: Comprehensive validation of all configuration inputs
- **Error Sanitisation**: No sensitive information leaked in error messages - **Error Sanitisation**: No sensitive information leaked in error messages
Mount only the Compose files to update and the configuration file. The updater
does not use the Docker daemon or restart running containers.
A `:ro` bind mount restricts filesystem changes to the socket path; it does not
make Docker API requests read-only. A process that can connect to the socket can
still send mutating requests. Docker daemon access can grant root authority on
the host; see [Docker's socket access guidance](https://docs.docker.com/engine/security/protect-access/).
If a future feature needs daemon access, enforce an API authorization boundary,
such as a [Docker authorization plugin](https://docs.docker.com/engine/extend/plugins_authorization/),
with an explicit policy limiting permitted requests.
## Development ## Development
### Building from Source ### Building from Source