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
46 changes: 44 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@ jobs:
with:
node-version: 24
cache: npm
cache-dependency-path: |
package-lock.json
tracker/package-lock.json
- run: npm ci
- run: npm ci --prefix tracker
- name: Check JavaScript syntax
run: find src tests -name '*.js' -print0 | xargs -0 -n1 node --check
run: find src tests tracker/src tracker/public tracker/tests -name '*.js' -print0 | xargs -0 -n1 node --check
- name: Parse YAML
run: ruby -e 'require "yaml"; Dir[".github/**/*.yml", "compose*.yml"].flatten.each { |file| YAML.load_file(file) }'
run: ruby -e 'require "yaml"; Dir[".github/**/*.yml", "compose*.yml", "tracker/compose.yml"].flatten.each { |file| YAML.load_file(file) }'
- run: git diff --check

test:
Expand All @@ -34,21 +38,47 @@ jobs:
with:
node-version: 24
cache: npm
cache-dependency-path: |
package-lock.json
tracker/package-lock.json
- run: npm ci
- run: npm ci --prefix tracker
- run: npm test
- run: npm test --prefix tracker

integration-test:
needs: test
runs-on: ubuntu-latest
timeout-minutes: 10
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: container_pilot
POSTGRES_USER: tracker
POSTGRES_PASSWORD: tracker-integration-password
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U tracker -d container_pilot"
--health-interval 5s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
cache-dependency-path: |
package-lock.json
tracker/package-lock.json
- run: npm ci
- run: npm ci --prefix tracker
- run: npm run test:integration
- run: npm run test:integration --prefix tracker
env:
DATABASE_URL: postgresql://tracker:tracker-integration-password@127.0.0.1:5432/container_pilot

security-check:
needs: lint
Expand All @@ -60,8 +90,13 @@ jobs:
with:
node-version: 24
cache: npm
cache-dependency-path: |
package-lock.json
tracker/package-lock.json
- run: npm ci
- run: npm ci --prefix tracker
- run: npm audit --omit=dev --audit-level=high
- run: npm audit --prefix tracker --omit=dev --audit-level=high

docker-build:
needs: [integration-test, security-check]
Expand All @@ -78,3 +113,10 @@ jobs:
platforms: linux/amd64,linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max
- uses: docker/build-push-action@v6
with:
context: ./tracker
push: false
platforms: linux/amd64,linux/arm64
cache-from: type=gha,scope=tracker
cache-to: type=gha,mode=max,scope=tracker
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## Unreleased

## 0.9.0-rc.11

- Added explicit opt-in anonymous telemetry with a live payload preview, daily jittered reporting, fail-open delivery, local reset/server deletion controls, and persistent update and rollback counters.
- Added a separately deployable PostgreSQL telemetry tracker with a write-only public listener, authenticated internal dashboard, strict schema/rate/body limits, retention, migrations, and hardened Compose/reverse-proxy examples.

## 0.9.0-rc.10

- Restored an anonymized product dashboard preview to the English and German README files.
Expand Down
15 changes: 13 additions & 2 deletions README.de.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<h1>Docker Update Manager – Container Pilot</h1>
<p><strong>Moderne deutsche Weboberfläche zur kontrollierten Prüfung und Installation von Docker-Image-Updates.</strong></p>
<p>
<img alt="Version 0.9.0 RC10" src="https://img.shields.io/badge/Version-0.9.0--rc.10-d97706">
<img alt="Version 0.9.0 RC11" src="https://img.shields.io/badge/Version-0.9.0--rc.11-d97706">
<img alt="Node.js 24" src="https://img.shields.io/badge/Node.js-24-339933?logo=nodedotjs&logoColor=white">
<img alt="Docker" src="https://img.shields.io/badge/Docker-Compose-2496ed?logo=docker&logoColor=white">
<img alt="Oberfläche Deutsch" src="https://img.shields.io/badge/Oberfläche-Deutsch-d97706">
Expand All @@ -18,7 +18,7 @@

Der Schwerpunkt liegt auf einem nachvollziehbaren Update-Workflow mit **konfigurierbaren Prüfintervallen, Freigabe pro Container, optionaler Sofortinstallation und automatischem Rollback**. Bei Images mit einem festen Tag prüft Container Pilot zusätzlich, ob ein `latest`-Tag vorhanden ist. In der Weboberfläche kann bewusst zwischen einem Update des bestehenden Tags und einem Wechsel auf `latest` entschieden werden. Die Automatik wechselt niemals selbstständig den Tag.

> **Projektstatus:** Version 0.9.0-rc.10 ist ein Release Candidate. Die Update-Engine besitzt Healthcheck-Validierung, Aktionssperren, Self-Updates und Docker-Integrationstests. Vor dem Stable-Release ist ein kontrollierter Praxistest mit den eigenen Stacks vorgesehen.
> **Projektstatus:** Version 0.9.0-rc.11 ist ein Release Candidate. Die Update-Engine besitzt Healthcheck-Validierung, Aktionssperren, Self-Updates und Docker-Integrationstests. Vor dem Stable-Release ist ein kontrollierter Praxistest mit den eigenen Stacks vorgesehen.

## Einblick

Expand Down Expand Up @@ -51,6 +51,15 @@ Der Schwerpunkt liegt auf einem nachvollziehbaren Update-Workflow mit **konfigur
| **Benutzer** | Administrator- und Viewer-Konten über die Weboberfläche verwalten |
| **Ereignisse** | Prüf-, Update-, Fehler-, Benutzer- und Anmeldeereignisse in einem eigenen Menüpunkt nachvollziehen |
| **Systemupdate** | GitHub Releases prüfen und Container Pilot über einen getrennten Helfer mit Healthcheck und automatischer Wiederherstellung aktualisieren |
| **Anonyme Nutzungsstatistiken** | Freiwillig und standardmäßig deaktiviert; exakte Daten vor dem Versand anzeigen, sofort senden, deaktivieren, Identität zurücksetzen oder Serverdaten löschen |

## Freiwillige anonyme Nutzungsstatistiken

Container Pilot enthält eine freiwillige und besonders datensparsame Nutzungsstatistik. Sie soll uns helfen zu verstehen, wie sich das Projekt in realen Installationen und unterschiedlichen Einsatzszenarien verhält. **Die Funktion ist standardmäßig ausgeschaltet und überträgt nichts, bis ein Administrator sie ausdrücklich aktiviert.**

Nach der Aktivierung wird nur das kleinste sinnvoll nutzbare Maß an zusammengefassten technischen Daten übertragen, beispielsweise Container-Pilot- und Docker-Version, Architektur, allgemeines Betriebssystem, aggregierte Containerzahlen, verwendete Funktionskategorien und kumulierte Update-Ergebnisse. Container- oder Image-Namen, IP-Adressen, Hostnamen, Registry-Domains, Zugangsdaten, Umgebungsvariablen, Mount-Pfade und Anwendungsdaten werden niemals übertragen. Die Weboberfläche zeigt vor dem Versand exakt den aktuellen Payload; die Funktion kann jederzeit deaktiviert und die zugehörigen Daten können gelöscht werden.

Wir freuen uns über jeden Administrator, der diese Funktion freiwillig aktiviert. Die anonymen Erkenntnisse aus dem praktischen Einsatz helfen uns, Kompatibilität, Zuverlässigkeit und Zugänglichkeit gezielt zu verbessern, damit Container Pilot in möglichst vielen Umgebungen und für möglichst viele Menschen gut funktioniert. Alle Einzelheiten stehen unter [Telemetrie und Datenschutz](docs/telemetry.md).

## Architektur: Weboberfläche, Docker API und Registry

Expand Down Expand Up @@ -131,6 +140,8 @@ Sitzungen bleiben zwölf Stunden gültig und werden beim Ändern des eigenen Ken

## Sicherheit im Docker-Betrieb

Anonyme Nutzungsstatistiken sind freiwillig, standardmäßig deaktiviert und transparent unter [Telemetrie und Datenschutz](docs/telemetry.md) dokumentiert.

Der eingebundene Docker-Socket ermöglicht weitreichende Kontrolle über den Docker-Host. Container Pilot gehört deshalb ausschließlich in eine vertrauenswürdige Verwaltungsumgebung.

- Weboberfläche nicht ungeschützt im öffentlichen Internet bereitstellen
Expand Down
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<p>A Docker update manager with a Web UI, per-container policies, health checks, and automatic rollback.</p>
<p><strong>A safer Watchtower alternative focused on control and recovery.</strong></p>
<p>
<img alt="Version 0.9.0 RC10" src="https://img.shields.io/badge/version-0.9.0--rc.10-d97706">
<img alt="Version 0.9.0 RC11" src="https://img.shields.io/badge/version-0.9.0--rc.11-d97706">
<img alt="Docker Compose" src="https://img.shields.io/badge/Docker-Compose-2496ed?logo=docker&logoColor=white">
<img alt="AMD64 and ARM64" src="https://img.shields.io/badge/platform-amd64%20%7C%20arm64-2496ed">
<img alt="MIT License" src="https://img.shields.io/badge/license-MIT-7c3aed">
Expand Down Expand Up @@ -72,6 +72,15 @@ Detect → Decide → Update → Verify → Recover
- Container configuration reconstruction, including mounts, networks, ports, environment, and restart policy
- Safe self-update flow through a separate helper container
- Opt-in Watchtower policy import with a read-only preview and per-rule confirmation
- Optional anonymous usage statistics with an exact payload preview and full administrator control

## Optional anonymous usage statistics

Container Pilot includes voluntary, privacy-minimizing usage statistics to help us understand how the project behaves across real installations and different deployment scenarios. **The feature is disabled by default and sends nothing until an administrator explicitly enables it.**

When enabled, only the smallest useful set of aggregated technical data is reported, such as the Container Pilot and Docker versions, architecture, general operating system, aggregate container counts, enabled feature categories, and cumulative update results. Container Pilot never reports container or image names, IP addresses, hostnames, registry domains, credentials, environment variables, mount paths, or application data. The Web UI shows the exact payload before it is sent, and reporting can be disabled or deleted at any time.

We appreciate every administrator who voluntarily enables this feature. These anonymous field insights help us prioritize compatibility, reliability, and accessibility work so Container Pilot can serve as many environments and users as possible. Full details are available in [Telemetry and privacy](docs/telemetry.md).

## Important safety boundary

Expand All @@ -97,6 +106,7 @@ Read [Security](docs/security.md), [Updates](docs/updates.md), and [Rollback](do
- [Release-candidate testing](docs/testing.md)
- [Webhook notifications](docs/notifications.md)
- [Private registries](docs/private-registries.md)
- [Telemetry and privacy](docs/telemetry.md)
- [Project website](https://deepzone.github.io/container-pilot/)
- [Roadmap](ROADMAP.md)
- [Changelog](CHANGELOG.md)
Expand All @@ -109,7 +119,7 @@ Published multi-architecture images are available from:
ghcr.io/deepzone/container-pilot
```

- Complete version tags such as `0.9.0-rc.10` are fixed release references and must never be reused.
- Complete version tags such as `0.9.0-rc.11` are fixed release references and must never be reused.
- Release candidates use the `rc` channel once published by the release workflow.
- `latest`, major, and minor aliases are reserved for stable releases.
- Successful builds from `main` use the moving `edge` tag and a commit-specific `sha-*` tag. They are development builds, not releases.
Expand Down Expand Up @@ -140,6 +150,8 @@ npm run test:integration

## Contributing and security

Anonymous usage statistics are optional, disabled by default, and documented transparently in [Telemetry and privacy](docs/telemetry.md).

Contributions are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request.

Do not publish credentials, tokens, private image names, internal addresses, or complete state files in issues. Report vulnerabilities according to [SECURITY.md](SECURITY.md).
Expand Down
2 changes: 1 addition & 1 deletion compose.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
services:
container-pilot:
image: ${CP_IMAGE:-ghcr.io/deepzone/container-pilot:0.9.0-rc.10}
image: ${CP_IMAGE:-ghcr.io/deepzone/container-pilot:0.9.0-rc.11}
container_name: container-pilot
restart: unless-stopped
init: true
Expand Down
2 changes: 1 addition & 1 deletion docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Then open `https://YOUR-DOCKER-HOST:3080`. See [HTTPS and reverse proxy](reverse
The Compose file defaults to the current release candidate until the first stable release exists. To select an explicit published image without editing the file:

```bash
CP_IMAGE=ghcr.io/deepzone/container-pilot:0.9.0-rc.10 docker compose up -d
CP_IMAGE=ghcr.io/deepzone/container-pilot:0.9.0-rc.11 docker compose up -d
```

After a stable release is published, select the stable channel with `CP_IMAGE=ghcr.io/deepzone/container-pilot:latest` and `CP_SELF_UPDATE_CHANNEL=stable`. The `latest` tag is never published for a release candidate.
Expand Down
4 changes: 2 additions & 2 deletions docs/releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

[Documentation index](../README.md) · [Installation](installation.md)

Container Pilot uses [Semantic Versioning](https://semver.org/). Release candidates use tags such as `v0.9.0-rc.10`; stable releases use tags such as `v1.0.0`.
Container Pilot uses [Semantic Versioning](https://semver.org/). Release candidates use tags such as `v0.9.0-rc.11`; stable releases use tags such as `v1.0.0`.

## Channels

| Git tag | Published image tags | Intended use |
| --- | --- | --- |
| `v0.9.0-rc.10` | `0.9.0-rc.10`, `rc` | controlled release-candidate testing |
| `v0.9.0-rc.11` | `0.9.0-rc.11`, `rc` | controlled release-candidate testing |
| `v1.2.3` | `1.2.3`, `1.2`, `1`, `latest`, `stable` | stable installations |
| push to `main` | `edge`, `sha-<commit>` | development testing only |

Expand Down
37 changes: 37 additions & 0 deletions docs/telemetry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Anonymous usage statistics

Container Pilot telemetry is optional, transparent, and disabled by default. It starts only after an administrator explicitly enables **Anonymous Usage Statistics** in the web interface. Existing state files are migrated with telemetry switched off.

## Data sent

When enabled, Container Pilot sends schema version 1 to `POST https://cp-track.noisens.de/api/v1/telemetry` at most once every 24 hours. Startup uses a random delay of two to fifteen minutes. The endpoint can be overridden with `CP_TELEMETRY_URL`; production endpoints must use HTTPS, while HTTP is accepted only for localhost tests.

The report contains:

- a random UUID v4 installation ID and a SHA-256 hash of a random deletion token;
- Container Pilot version and release channel;
- normalized architecture, Docker/API version, general OS name, and kernel major/minor;
- aggregate container counts: total, running, stopped, healthcheck, and automatic-update policy counts;
- Boolean feature adoption for Watchtower migration, native HTTPS, private registry configuration, and webhooks;
- Boolean registry categories: Docker Hub, GHCR, GitLab, and generic OCI;
- cumulative successful/failed update and automatic/manual rollback counters.

The raw delete token remains only in local Container Pilot state. The tracker stores only its hash. Counters are cumulative; the tracker keeps the latest value per installation and derives changes between reports instead of adding cumulative totals repeatedly.

## Data never sent

Container Pilot does not send hostnames, Docker host names, IP or MAC addresses, machine IDs, hardware serials, container names or IDs, images, tags, digests, repository names, registry domains or URLs, labels, Compose metadata, networks, volumes, mounts, paths, ports, environment variables, usernames, passwords, tokens, secrets, certificates, keys, browser information, application data, or file contents.

The tracker does not persist remote IP addresses and never logs complete payloads. The public listener exposes only ingest, installation deletion, and health routes. Statistics and installation data are available only through a separately bound internal dashboard listener with authentication.

## Controls and transparency

The telemetry dialog shows enabled state, shortened installation ID, last successful report, last attempt, safe status, and next scheduled report. **Preview data** builds the live payload with the exact same function used by **Send now**; it contains no example or hidden fields.

Disabling telemetry stops future requests without deleting local counters. **Reset telemetry identity** removes the local installation ID, delete token, timestamps, and status. Enabling telemetry again creates a new cryptographically random identity. **Delete server data** authenticates to the public deletion endpoint with the local delete token, deletes the installation and all reports, and then resets the local identity.

## Failure behavior

Telemetry has an eight-second timeout and is fail-open. DNS, connection, timeout, TLS, HTTP, rate-limit, invalid-response, and tracker errors are reduced to a non-sensitive local status. They never stop or delay scans, updates, rollbacks, UI actions, or the Container Pilot process.

Privacy principles: opt-in instead of opt-out, transparent instead of hidden, aggregated instead of detailed, and minimal instead of curious.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "container-pilot",
"version": "0.9.0-rc.10",
"version": "0.9.0-rc.11",
"private": true,
"type": "module",
"scripts": {
Expand Down
1 change: 1 addition & 0 deletions src/public/app.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading