From 1770bce61c6900f6d6a40cb96b08a54453af85a1 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 15 Jul 2026 11:30:14 +0100 Subject: [PATCH 1/2] docs(configuration): add Configuration Overhaul EPIC spec and 9 subissue specs (#1978) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add planning and spec work for the Configuration Overhaul EPIC targeting config schema v3.0.0 and tracker app v4.0.0. New EPIC and subissue specs: - 1978-configuration-overhaul-epic.md: EPIC spec for all config changes - 1979-1978-copy-configuration-schema-v2-to-v3-baseline.md: copy v2→v3 baseline - 1980-1978-configuration-overhaul-final-cleanup.md: final cleanup subissue - 1981-1978-fix-tsl-config-tls-config-typo.md: fix tsl→tls typo subissue Pre-existing open issues reviewed, refined, and linked to EPIC: - 889-1978-new-config-option-for-logging-style.md (renamed with EPIC prefix) - 1415-1978-use-service-binding-instead-of-socket-addr.md (new, from closed draft) - 1417-1978-add-public-service-url-to-configuration.md (moved from drafts/, renamed) - 1453-1978-ip-bans-reset-interval-configurable.md (new, linked to EPIC) - 1490-1978-decompose-database-config-and-overhaul-secrets.md (new, linked to EPIC) - 1640-1978-per-http-tracker-on-reverse-proxy-setting.md (renamed with EPIC prefix) Also add docs/issues/open/AGENTS.md with file naming conventions for the open/ folder, and extend project-words.txt with colour, colours, reorganisation, and zeroize. --- ...-service-binding-instead-of-socket-addr.md | 155 +++++++++++ ...dd-public-service-url-to-configuration.md} | 45 ++-- ...978-ip-bans-reset-interval-configurable.md | 153 +++++++++++ ...se-database-config-and-overhaul-secrets.md | 253 ++++++++++++++++++ ...-http-tracker-on-reverse-proxy-setting.md} | 86 +++--- .../open/1978-configuration-overhaul-epic.md | 233 ++++++++++++++++ ...-configuration-schema-v2-to-v3-baseline.md | 136 ++++++++++ ...78-configuration-overhaul-final-cleanup.md | 227 ++++++++++++++++ ...981-1978-fix-tsl-config-tls-config-typo.md | 178 ++++++++++++ ...978-new-config-option-for-logging-style.md | 195 ++++++++++++++ docs/issues/open/AGENTS.md | 80 ++++++ project-words.txt | 6 +- 12 files changed, 1678 insertions(+), 69 deletions(-) create mode 100644 docs/issues/open/1415-1978-use-service-binding-instead-of-socket-addr.md rename docs/issues/{drafts/1417-add-public-service-url-to-configuration.md => open/1417-1978-add-public-service-url-to-configuration.md} (65%) create mode 100644 docs/issues/open/1453-1978-ip-bans-reset-interval-configurable.md create mode 100644 docs/issues/open/1490-1978-decompose-database-config-and-overhaul-secrets.md rename docs/issues/open/{1640-per-http-tracker-on-reverse-proxy-setting.md => 1640-1978-per-http-tracker-on-reverse-proxy-setting.md} (86%) create mode 100644 docs/issues/open/1978-configuration-overhaul-epic.md create mode 100644 docs/issues/open/1979-1978-copy-configuration-schema-v2-to-v3-baseline.md create mode 100644 docs/issues/open/1980-1978-configuration-overhaul-final-cleanup.md create mode 100644 docs/issues/open/1981-1978-fix-tsl-config-tls-config-typo.md create mode 100644 docs/issues/open/889-1978-new-config-option-for-logging-style.md create mode 100644 docs/issues/open/AGENTS.md diff --git a/docs/issues/open/1415-1978-use-service-binding-instead-of-socket-addr.md b/docs/issues/open/1415-1978-use-service-binding-instead-of-socket-addr.md new file mode 100644 index 000000000..98f306501 --- /dev/null +++ b/docs/issues/open/1415-1978-use-service-binding-instead-of-socket-addr.md @@ -0,0 +1,155 @@ +--- +doc-type: issue +issue-type: enhancement +status: open +priority: p2 +github-issue: 1415 +spec-path: docs/issues/open/1415-1978-use-service-binding-instead-of-socket-addr.md +branch: "1415-listen-url" +related-pr: null +last-updated-utc: 2026-07-13 21:00 +semantic-links: + skill-links: + - create-issue + related-artifacts: + - packages/configuration/src/v3_0_0/ + - packages/tracker-core/src/lib.rs + - packages/http-core/src/container.rs + - packages/udp-server/src/server/launcher.rs + - src/bootstrap/jobs/ +--- + + + +# Issue #1415 - Use `ServiceBinding` (protocol + address) instead of bare `SocketAddr` for service identity + +> **EPIC position**: Subissue #5 of 9. Independent — no config changes, no overlap with other subissues. Can run in parallel with #1453, #1490, #889. + +## Goal + +Replace bare `SocketAddr` values with `ServiceBinding` (from `torrust-net-primitives`) wherever the socket address is used for service identity — in logs, events, health check info, and metrics. `ServiceBinding` already carries both the protocol scheme and the socket address, so consumers get the full protocol + address context without any new types or external crate changes. + +## Background + +The tracker currently passes `SocketAddr` values around for each service (UDP tracker, HTTP tracker, API, health check). However, the socket address alone lacks the **protocol/scheme** information. When logging startup messages, the code manually constructs URL-like strings: + +```text +UDP TRACKER: Started on: udp://0.0.0.0:6868 +HTTP TRACKER: Started on: http://0.0.0.0:7070 +API: Started on http://0.0.0.0:1212 +``` + +But this protocol context is not available as a first-class value in the places that need it: + +1. **Health check API** (#1409) — needs to expose the service type and address +2. **Metrics** (#1403 / #1414) — needs protocol as a label for Prometheus metrics +3. **Events** — domain events should carry the service protocol, not just the socket address + +The solution is to use the existing `ServiceBinding` type from `torrust-net-primitives` (which already carries `scheme` + `SocketAddr`) wherever bare `SocketAddr` is currently passed. No new types, no external crate changes, no URL path segments. + +### What this issue does NOT do + +- **Does not add URL path segments** (e.g. `/announce`). Path segments are hardcoded per protocol and not useful for service identity. +- **Does not resolve the bind address to a concrete IP**. `ServiceBinding` carries the configured bind address as-is (e.g. `0.0.0.0:7070`). +- **Does not provide a public-facing URL**. That is handled by #1417 (`public_url` config field). + +### Future extension: internal connection URL + +A future issue could build an "internal connection URL" from the OS-resolved IP + hardcoded path segment (e.g. `https://192.168.1.5:7070/announce`). This would be useful when the `public_url` is not configured but the service is bound to a concrete reachable IP. This is deferred — the `public_url` field (#1417) covers the primary use case. + +## Scope + +### In Scope + +- Use `ServiceBinding` (from `torrust-net-primitives`) wherever bare `SocketAddr` is currently passed for service identity: + - Server startup logging + - Health check info structs + - Metrics labels + - Domain events (if applicable) +- No new types — `ServiceBinding` already has `scheme()` and `bind_to()` methods +- No changes to `torrust-net-primitives` external crate + +### Out of Scope + +- Adding URL path segments (e.g. `/announce`) — hardcoded per protocol, not useful for identity +- Resolving bind address to concrete IP — `ServiceBinding` carries the configured address as-is +- Adding a `public_url` config field (tracked in #1417) +- Building an "internal connection URL" from resolved IP + path segment (future extension) +- Changing the tracker protocol types (UDP/HTTP protocol parsing) +- TLS certificate configuration + +## Implementation Plan + +| ID | Status | Task | Notes | +| --- | ------ | ------------------------------------------------------------------------ | ----------------------------------------------------- | +| T1 | TODO | Identify all places where bare `SocketAddr` is used for service identity | Logs, health check, metrics, events, server launchers | +| T2 | TODO | Replace `SocketAddr` with `ServiceBinding` in those places | `ServiceBinding` already has `scheme()` + `bind_to()` | +| T3 | TODO | Update startup logging to use `ServiceBinding` | Replace manual URL string construction | +| T4 | TODO | Update health check info to include `ServiceBinding` | For issue #1409 | +| T5 | TODO | Update metrics to use `ServiceBinding` scheme as a label | For issue #1403/#1414 | +| T6 | TODO | Run `linter all` and tests | | + +## Progress Tracking + +### Workflow Checkpoints + +- [ ] Spec drafted in `docs/issues/drafts/` +- [ ] Spec reviewed and approved by user/maintainer +- [ ] GitHub issue created and issue number added to this spec +- [ ] Implementation completed +- [ ] Automatic verification completed (`linter all`, relevant tests) +- [ ] Manual verification scenarios executed and recorded +- [ ] Acceptance criteria reviewed after implementation +- [ ] Issue closed and spec moved to `docs/issues/open/` + +### Progress Log + +- 2026-07-13 21:00 UTC - josecelano - Initial spec drafted +- 2026-07-14 00:00 UTC - josecelano - Narrowed scope: use existing `ServiceBinding` instead of bare `SocketAddr`; no new types; no external crate changes; no URL path segments. Deferred "internal connection URL" to future extension. + +## Acceptance Criteria + +- [ ] AC1: `ServiceBinding` is used wherever bare `SocketAddr` was used for service identity +- [ ] AC2: Startup logs show protocol + address (e.g. `udp://0.0.0.0:6969`) via `ServiceBinding` +- [ ] AC3: Health check endpoint exposes `ServiceBinding` per service +- [ ] AC4: Metrics include the protocol scheme as a label (from `ServiceBinding`) +- [ ] AC5: No new config field required — `ServiceBinding` is derived from scheme + bind_address +- [ ] AC6: No changes to `torrust-net-primitives` external crate +- [ ] `linter all` exits with code `0` +- [ ] Relevant tests pass + +## Verification Plan + +### Automatic Checks + +- `linter all` +- `cargo test --workspace` + +### Manual Verification Scenarios + +| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | +| --- | --------------------------------- | --------------------------------------------- | ------------------------------------------ | ------ | -------- | +| M1 | Verify listen URL in startup logs | Run tracker locally, check startup log output | Logs show `udp://0.0.0.0:6969` etc. | TODO | | +| M2 | Verify listen URL in health check | `curl http://127.0.0.1:1313/health` | Response includes `listen_url` per service | TODO | | + +### Acceptance Verification + +| AC ID | Status | Evidence | +| ----- | ------ | -------- | +| AC1 | TODO | | +| AC2 | TODO | | +| AC3 | TODO | | +| AC4 | TODO | | +| AC5 | TODO | | + +## Risks and Trade-offs + +- **Scope creep**: This issue touches many packages (server launchers, health check, metrics). Mitigation: keep changes focused on replacing `SocketAddr` with `ServiceBinding` — no refactoring of how addresses are consumed. +- **No external crate changes**: `ServiceBinding` from `torrust-net-primitives` is used as-is. No coordinated release needed. + +## References + +- Related issues: #1409 (health check), #1403/#1414 (metrics) +- Related: `packages/tracker-core/src/lib.rs` +- Related: `packages/http-core/src/container.rs` +- Related: `packages/udp-server/src/server/launcher.rs` diff --git a/docs/issues/drafts/1417-add-public-service-url-to-configuration.md b/docs/issues/open/1417-1978-add-public-service-url-to-configuration.md similarity index 65% rename from docs/issues/drafts/1417-add-public-service-url-to-configuration.md rename to docs/issues/open/1417-1978-add-public-service-url-to-configuration.md index 75b29d119..9a4ed8dea 100644 --- a/docs/issues/drafts/1417-add-public-service-url-to-configuration.md +++ b/docs/issues/open/1417-1978-add-public-service-url-to-configuration.md @@ -1,10 +1,10 @@ --- doc-type: issue issue-type: enhancement -status: draft +status: open priority: p3 github-issue: 1417 -spec-path: docs/issues/drafts/1417-add-public-service-url-to-configuration.md +spec-path: docs/issues/open/1417-1978-add-public-service-url-to-configuration.md branch: "1417-add-public-service-url" related-pr: null last-updated-utc: 2026-06-23 18:45 @@ -15,14 +15,18 @@ semantic-links: - issue #1640 - issue torrust/torrust-tracker-deployer - issue torrust/torrust-tracker-deployer docs/ai-training/dataset/environment-configs/02-full-stack-lxd.json - - packages/configuration/src/v2_0_0/http_tracker.rs - - packages/configuration/src/v2_0_0/udp_tracker.rs + - packages/configuration/src/v3_0_0/http_tracker.rs + - packages/configuration/src/v3_0_0/udp_tracker.rs + - packages/configuration/src/v3_0_0/tracker_api.rs + - packages/configuration/src/v3_0_0/health_check_api.rs --- # Issue #1417 - Include public service URL in configuration +> **EPIC position**: Subissue #4 of 9. Depends on #1640 (subissue #3) for the `Network` block placement decision — `public_url` stays flat (not inside `Network`). Implements after #1640 is complete. + ## Goal Add an optional `public_url` field to each tracker instance (`HttpTracker`, `UdpTracker`) and API service (`HttpApi`, `HealthCheckApi`) so the application knows the public-facing URL for each service regardless of network topology, reverse proxies, or TLS termination. @@ -57,6 +61,7 @@ For example, the [Torrust Tracker Deployer](https://github.com/torrust/torrust-t - Add optional `public_url: Option` field to `HttpTracker`, `UdpTracker`, `HttpApi`, and `HealthCheckApi` - Use a **single URL string** (e.g. `"https://tracker1.example.com/announce"`) — not decomposed into domain/path components, since consumers can parse those as needed +- Validate URL protocol at deserialization time (HTTP tracker → `http://`/`https://`, UDP tracker → `udp://`, API → `http://`/`https://`) - The URL protocol (`https://`) provides TLS status; the domain is extracted by consumers - Document the field in default config examples - No runtime behaviour change — the field is stored in config and available for use by consumers (metrics, logging, etc.) @@ -81,29 +86,39 @@ No changes are needed in this issue — the field just needs to be present in th **Single URL string vs decomposed fields**: The field is a single URL string. Consumers parse protocol, domain, and path as needed. This is the simplest user-facing form and avoids duplicating the deployer's `domain` + `use_tls_proxy` approach. -**Where the field lives**: This field is about **public exposure** (how users reach the service), not **network topology** (how the service connects). It could stay flat on the config struct or join a `Network` block depending on future architecture decisions. For now, keep it flat — issue #1640 establishes the `Network` block, and this field can be placed accordingly. +**Where the field lives**: `public_url` is a **flat field** on each config struct (`HttpTracker`, `UdpTracker`, `HttpApi`, `HealthCheckApi`) — **not inside the `Network` block**. The `Network` block (established by #1640) groups **network topology** concerns (external IP, proxy awareness, socket behaviour). `public_url` is about **public exposure** (how users reach the service) — a different axis. A tracker instance can independently configure both `net.on_reverse_proxy` and `public_url`. + +**Protocol validation**: The URL protocol is validated at deserialization time: + +- HTTP tracker: must use `http://` or `https://` +- UDP tracker: must use `udp://` +- HTTP API / Health Check API: must use `http://` or `https://` + +This catches misconfigurations early (e.g., accidentally setting `public_url = "udp://..."` on an HTTP tracker). ## Implementation Plan -| ID | Status | Task | Notes | -| --- | ------ | ----------------------------------------------------------- | -------------- | -| T1 | TODO | Add `public_url: Option` to `HttpTracker` config | Default `None` | -| T2 | TODO | Add `public_url: Option` to `UdpTracker` config | Default `None` | -| T3 | TODO | Add `public_url: Option` to `HttpApi` config | Default `None` | -| T4 | TODO | Add `public_url: Option` to `HealthCheckApi` config | Default `None` | -| T5 | TODO | Document field in default config examples and crate docs | | -| T6 | TODO | Run `linter all` and tests | | +| ID | Status | Task | Notes | +| --- | ------ | ----------------------------------------------------------- | ------------------------------------------------------------ | +| T1 | TODO | Add `public_url: Option` to `HttpTracker` config | Default `None`; validate protocol is `http://` or `https://` | +| T2 | TODO | Add `public_url: Option` to `UdpTracker` config | Default `None`; validate protocol is `udp://` | +| T3 | TODO | Add `public_url: Option` to `HttpApi` config | Default `None`; validate protocol is `http://` or `https://` | +| T4 | TODO | Add `public_url: Option` to `HealthCheckApi` config | Default `None`; validate protocol is `http://` or `https://` | +| T5 | TODO | Document field in default config examples and crate docs | | +| T6 | TODO | Run `linter all` and tests | | ## Progress Tracking ### Progress Log - 2026-06-23 18:45 UTC - Copilot - Drafted from GitHub issue #1417 and discussions in issue #1640 spec review. +- 2026-07-14 00:00 UTC - josecelano - Resolved placement: `public_url` stays flat (not inside `Network`). Added protocol validation. Updated related-artifacts to v3 paths. ## Acceptance Criteria - [ ] AC1: All config structs gain `public_url: Option` field -- [ ] AC2: Default config examples include the new field (commented or shown) -- [ ] AC3: No runtime behaviour change — field is present for consumer use +- [ ] AC2: Protocol validation rejects mismatched protocols (e.g., `udp://` on HTTP tracker) +- [ ] AC3: Default config examples include the new field (commented or shown) +- [ ] AC4: No runtime behaviour change — field is present for consumer use - [ ] `linter all` exits with code `0` - [ ] Relevant tests pass diff --git a/docs/issues/open/1453-1978-ip-bans-reset-interval-configurable.md b/docs/issues/open/1453-1978-ip-bans-reset-interval-configurable.md new file mode 100644 index 000000000..3bcb988aa --- /dev/null +++ b/docs/issues/open/1453-1978-ip-bans-reset-interval-configurable.md @@ -0,0 +1,153 @@ +--- +doc-type: issue +issue-type: enhancement +status: open +priority: p2 +github-issue: 1453 +spec-path: docs/issues/open/1453-1978-ip-bans-reset-interval-configurable.md +branch: "1453-ip-bans-reset-interval" +related-pr: null +last-updated-utc: 2026-07-13 21:00 +semantic-links: + skill-links: + - create-issue + related-artifacts: + - packages/configuration/src/v3_0_0/ + - packages/udp-core/src/services/banning.rs + - packages/udp-server/src/server/launcher.rs + - src/bootstrap/jobs/ +--- + + + +# Issue #1453 - Allow setting the IP bans reset interval via configuration and remove duplicate execution of cronjob to clean bans + +> **EPIC position**: Subissue #6 of 9. Independent — new `[udp_tracker_server]` section with no overlap. Can run in parallel with #1415, #1490, #889. + +## Goal + +Add a new `[udp_tracker_server]` configuration section with an `ip_bans_reset_interval_in_secs` option, and fix the duplicate spawning of the ban cleanup task (one per UDP server instead of once globally). + +## Background + +The tracker has a `BanService` (in `packages/udp-core/src/services/banning.rs`) that bans client IPs sending many requests with the wrong connection ID. There are two problems: + +### Task 1: Hardcoded interval + +The ban cleanup interval is hardcoded. There is no configuration section for settings that apply to the UDP tracker server as a whole (as opposed to per-instance settings like `bind_address` or `cookie_lifetime`). + +Proposed new config section: + +```toml +[udp_tracker_server] +ip_bans_reset_interval_in_secs = 3600 +``` + +Default value: `86400` (24 hours). + +### Task 2: Duplicate cleanup task + +Every time the tracker starts a new UDP server, it spawns a new task to reset the bans: + +```rust +tokio::spawn(async move { + let mut cleaner_interval = interval(Duration::from_secs(IP_BANS_RESET_INTERVAL_IN_SECS)); + cleaner_interval.tick().await; + loop { + cleaner_interval.tick().await; + ban_cleaner.write().await.reset_bans(); + } +}); +``` + +Since all UDP servers are launched simultaneously at startup, the bans are being reset N times (once per UDP server) instead of once. This is a bug — the cleanup should be spawned once at the main app bootstrapping level. + +## Scope + +### In Scope + +- Add `[udp_tracker_server]` config section with `ip_bans_reset_interval_in_secs: u64` field +- Default value: `86400` (24 hours) +- Move ban cleanup task spawning from per-UDP-server launcher to main app bootstrap +- Ensure only one cleanup task runs regardless of the number of UDP servers +- Update default config examples + +### Out of Scope + +- Changing the `BanService` implementation itself +- Adding similar config sections for other server types (HTTP, API) +- Per-instance ban configuration + +## Implementation Plan + +| ID | Status | Task | Notes | +| --- | ------ | -------------------------------------------------------------------------- | ---------------------------------------------------- | +| T1 | TODO | Add `UdpTrackerServer` config struct with `ip_bans_reset_interval_in_secs` | In `packages/configuration/src/v3_0_0/` | +| T2 | TODO | Add `udp_tracker_server` field to root `Configuration` struct | Optional with default | +| T3 | TODO | Move ban cleanup task from per-server launcher to bootstrap | Spawn once in `src/bootstrap/` or `src/container.rs` | +| T4 | TODO | Read interval from config instead of hardcoded constant | | +| T5 | TODO | Update default config files with new section | | +| T6 | TODO | Run `linter all` and tests | | + +## Progress Tracking + +### Workflow Checkpoints + +- [ ] Spec drafted in `docs/issues/drafts/` +- [ ] Spec reviewed and approved by user/maintainer +- [ ] GitHub issue created and issue number added to this spec +- [ ] Implementation completed +- [ ] Automatic verification completed (`linter all`, relevant tests) +- [ ] Manual verification scenarios executed and recorded +- [ ] Acceptance criteria reviewed after implementation +- [ ] Issue closed and spec moved to `docs/issues/open/` + +### Progress Log + +- 2026-07-13 21:00 UTC - josecelano - Initial spec drafted + +## Acceptance Criteria + +- [ ] AC1: New `[udp_tracker_server]` config section with `ip_bans_reset_interval_in_secs` exists +- [ ] AC2: Default value is `86400` (24 hours) +- [ ] AC3: Ban cleanup task is spawned exactly once at app bootstrap +- [ ] AC4: No duplicate cleanup tasks when multiple UDP servers are configured +- [ ] AC5: Default config files include the new section +- [ ] `linter all` exits with code `0` +- [ ] Relevant tests pass + +## Verification Plan + +### Automatic Checks + +- `linter all` +- `cargo test --workspace` + +### Manual Verification Scenarios + +| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | +| --- | -------------------------- | ------------------------------------------------------------------ | -------------------------------- | ------ | -------- | +| M1 | Verify config parsing | Run tracker with custom `ip_bans_reset_interval_in_secs` in config | Tracker starts, interval is read | TODO | | +| M2 | Verify single cleanup task | Run tracker with 2+ UDP servers, check logs for cleanup task count | Only one cleanup task spawned | TODO | | +| M3 | Verify default value | Run tracker without the new config option | Uses default 86400 interval | TODO | | + +### Acceptance Verification + +| AC ID | Status | Evidence | +| ----- | ------ | -------- | +| AC1 | TODO | | +| AC2 | TODO | | +| AC3 | TODO | | +| AC4 | TODO | | +| AC5 | TODO | | + +## Risks and Trade-offs + +- **New config section**: Adding `[udp_tracker_server]` is a breaking change for config file format. Mitigation: the field is optional with a sensible default. +- **Bootstrap refactoring**: Moving the cleanup task requires understanding the app bootstrap flow. Mitigation: keep the change minimal — just move the spawn call. + +## References + +- Related issues: #1444, #1452 +- Related: `packages/udp-core/src/services/banning.rs` +- Related: `packages/udp-server/src/server/launcher.rs` diff --git a/docs/issues/open/1490-1978-decompose-database-config-and-overhaul-secrets.md b/docs/issues/open/1490-1978-decompose-database-config-and-overhaul-secrets.md new file mode 100644 index 000000000..2adcbc778 --- /dev/null +++ b/docs/issues/open/1490-1978-decompose-database-config-and-overhaul-secrets.md @@ -0,0 +1,253 @@ +--- +doc-type: issue +issue-type: enhancement +status: open +priority: p2 +github-issue: 1490 +spec-path: docs/issues/open/1490-1978-decompose-database-config-and-overhaul-secrets.md +branch: "1490-secrets-overhaul" +related-pr: null +last-updated-utc: 2026-07-13 21:00 +semantic-links: + skill-links: + - create-issue + related-artifacts: + - packages/configuration/src/v3_0_0/ + - packages/configuration/src/v3_0_0/database.rs + - packages/configuration/src/v3_0_0/tracker_api.rs + - packages/configuration/src/lib.rs +--- + + + +# Issue #1490 - Decompose database config and overhaul secrets with `secrecy` crate + +> **EPIC position**: Subissue #7 of 9. Depends on #1640 (subissue #3) — both touch `Core`, so #1640 goes first (removes `core.net`, then #1490 changes `database` type). Can run in parallel with #1415, #1453, #889. + +## Goal + +Decompose the database configuration into driver-specific variants (SQLite, MySQL, PostgreSQL) and replace the manual secret-masking approach with the [`secrecy`](https://docs.rs/secrecy/) crate. This provides systematic protection for API tokens and database passwords, ensuring they are never accidentally exposed via `Debug`, `Display`, tracing instrumentation, or log output. + +## Background + +The Torrust Tracker handles these secrets: + +- **API tokens** — in `[http_api.access_tokens]` (e.g. `admin = "MyAccessToken"`) +- **Database passwords** — embedded in the database connection URL (e.g. `mysql://db_user:db_user_secret_password@mysql:3306/torrust_tracker`) + +Currently, secrets are masked manually via a `mask_secrets()` method that clones the configuration and replaces secret values with `"***"` before logging. This approach has several weaknesses: + +1. **Forgetfulness**: Any new secret added to the config must be manually added to `mask_secrets()`. If forgotten, it leaks. +2. **Tracing instrumentation**: As discovered in issue #1441, secrets can leak via tracing instrumentation even when `mask_secrets()` is called. +3. **No compile-time protection**: There is no type-level distinction between a secret and a regular string. + +### Proposed solution + +Use the [`secrecy`](https://docs.rs/secrecy/) crate, which provides: + +- A `Secret` wrapper type that implements `Debug` and `Display` without exposing the inner value +- Automatic zeroing of memory when the secret is dropped (via `zeroize`) +- Clear type-level distinction between secrets and plain strings + +### Database connection string + +The database configuration currently uses a single `path` string that serves double duty: + +```toml +# SQLite: path is a filesystem path +[core.database] +driver = "sqlite3" +path = "/var/lib/torrust/tracker/database/sqlite3.db" + +# MySQL/PostgreSQL: path is a URL with embedded password +[core.database] +driver = "mysql" +path = "mysql://db_user:db_user_secret_password@mysql:3306/torrust_tracker" +``` + +This design has several problems: + +1. **Field name lies**: `path` means "filesystem path" for SQLite but "connection URL" for MySQL/PostgreSQL +2. **Password hidden in URL**: The password is embedded in a URL string, making it hard to isolate as a secret +3. **Validation is impossible**: You can't validate a SQLite path and a MySQL URL with the same rules +4. **`mask_secrets()` is fragile**: It parses the URL just to mask the password (see `database.rs` lines 49-62) + +This issue decomposes the database config into an enum with driver-specific variants: + +```rust +pub struct ConnectionInfo { + pub host: String, + pub port: u16, + pub user: String, + pub password: Secret, + pub database: String, +} + +pub enum Database { + Sqlite3 { path: String }, + MySQL(ConnectionInfo), + PostgreSQL(ConnectionInfo), +} +``` + +TOML representation: + +```toml +# SQLite +[core.database] +driver = "sqlite3" +path = "/var/lib/torrust/tracker/database/sqlite3.db" + +# MySQL +[core.database] +driver = "mysql" +host = "mysql" +port = 3306 +user = "db_user" +password = "db_user_secret_password" +database = "torrust_tracker" + +# PostgreSQL +[core.database] +driver = "postgresql" +host = "postgres" +port = 5432 +user = "postgres" +password = "postgres_secret_password" +database = "torrust_tracker" +``` + +This is a **breaking change** with no backward-compatibility fallback. Since we are releasing config schema v3.0.0 and tracker v4.0.0, breaking changes are expected and documented. + +### Ripple effect + +~25 files will need changes (see full analysis in spec review). Key consumers: + +| Category | Files | Change | +| ------------------ | ------------------------------------------------------------------ | ----------------------- | +| Config definition | `database.rs`, `core.rs`, `mod.rs` | Enum + `Secret` | +| DB setup dispatch | `tracker-core/src/databases/setup.rs` | Match on enum variant | +| Test helpers | `test-helpers/`, `tracker-core/src/test_helpers.rs`, `fixtures.rs` | Construct enum variant | +| Examples | `http_only_public_tracker.rs`, `udp_only_public_tracker.rs` | Construct enum variant | +| Benchmarks | `persistence-benchmark/` (4 files) | Construct enum variant | +| E2E config builder | `qbittorrent_e2e/tracker/config_builder.rs` | Construct enum variant | +| Default TOML files | `share/default/config/*.toml` (6 files) | New format | +| Inline TOML/docs | `mod.rs` tests, `lib.rs` doc comments, integration tests | New format | + +**AccessTokens `Secret` wrapping (~10 additional files):** + +| Category | Files | Change | +| --------------- | ------------------------------------------------------------ | ---------------------------------------------------- | +| Type alias | `tracker_api.rs` | `HashMap>` | +| Auth middleware | `axum-rest-api-server/src/v1/middlewares/auth.rs` | `t.expose_secret() == token` | +| Test env | `axum-rest-api-server/src/testing/environment.rs` | `.get("admin").map(\|s\| s.expose_secret().clone())` | +| Bootstrap | `src/bootstrap/jobs/tracker_apis.rs`, `src/bootstrap/app.rs` | Remove `mask_secrets()` call | +| Config tests | `tracker_api.rs`, `mod.rs` | Add `.expose_secret()` in assertions | +| `mask_secrets` | `tracker_api.rs`, `mod.rs` | Remove or adapt (Secret handles display) | + +The `rest-api-client` crate and `tracker-core` authentication are **not affected** — they consume plain `String` tokens extracted from the map. + +## Scope + +### In Scope + +- Add `secrecy` crate as a dependency to `packages/configuration` +- Decompose `Database` struct into an enum: `Sqlite3 { path }`, `MySQL(ConnectionInfo)`, `PostgreSQL(ConnectionInfo)` +- Wrap database password in `Secret` (inside `ConnectionInfo`) +- Wrap API tokens in `Secret` (in `HttpApi` config struct) +- Remove manual `mask_secrets()` methods (replaced by type-level protection) +- Update all ~25 consumers to use the new enum variants and `.expose()` for secret access +- Update default config TOML files (6 files) to the new format +- Update inline TOML in tests and doc comments + +### Out of Scope + +- Applying `secrecy` to secrets outside the configuration package +- Changing how secrets are stored or transmitted at runtime +- Encrypting secrets at rest in the config file +- Changing the `Driver` enum in `packages/primitives` (may be deprecated after this change) + +## Implementation Plan + +| ID | Status | Task | Notes | +| --- | ------ | --------------------------------------------------------------- | ------------------------------------------------------------------------- | +| T1 | TODO | Add `secrecy` dependency to `packages/configuration/Cargo.toml` | Latest stable version | +| T2 | TODO | Define `ConnectionInfo` struct and `Database` enum | In `packages/configuration/src/v3_0_0/database.rs` | +| T3 | TODO | Implement serde for `Database` enum (internally tagged) | `driver` field as discriminant; `Sqlite3`, `MySQL`, `PostgreSQL` variants | +| T4 | TODO | Wrap database password in `Secret` | In `ConnectionInfo`; `Sqlite3` variant has no secrets | +| T5 | TODO | Wrap API tokens in `Secret` | In `HttpApi` config struct | +| T6 | TODO | Remove manual `mask_secrets()` methods | No longer needed with type-level protection | +| T7 | TODO | Update `tracker-core/src/databases/setup.rs` dispatch | Match on `Database` enum variant instead of `Driver` | +| T8 | TODO | Update all ~25 consumers (tests, examples, benchmarks, E2E) | Construct enum variants; use `.expose()` for secrets | +| T9 | TODO | Update default config TOML files (6 files) | New per-driver format | +| T10 | TODO | Update inline TOML in tests and doc comments | `mod.rs` tests, `lib.rs`, integration tests | +| T11 | TODO | Run `linter all` and full test suite | | + +## Progress Tracking + +### Workflow Checkpoints + +- [ ] Spec drafted in `docs/issues/drafts/` +- [ ] Spec reviewed and approved by user/maintainer +- [ ] GitHub issue created and issue number added to this spec +- [ ] Implementation completed +- [ ] Automatic verification completed (`linter all`, relevant tests) +- [ ] Manual verification scenarios executed and recorded +- [ ] Acceptance criteria reviewed after implementation +- [ ] Issue closed and spec moved to `docs/issues/open/` + +### Progress Log + +- 2026-07-13 21:00 UTC - josecelano - Initial spec drafted +- 2026-07-14 00:00 UTC - josecelano - Rewrote spec: decomposed `Database` into enum with `ConnectionInfo`; removed backward-compat fallback; added ripple-effect analysis (~25 files); renamed issue title + +## Acceptance Criteria + +- [ ] AC1: `Database` is an enum with `Sqlite3`, `MySQL(ConnectionInfo)`, `PostgreSQL(ConnectionInfo)` variants +- [ ] AC2: `secrecy` crate is used for all secret values (`password` in `ConnectionInfo`, API tokens in `HttpApi`) +- [ ] AC3: `Debug` and `Display` on config structs do not expose secret values +- [ ] AC4: Manual `mask_secrets()` methods are removed +- [ ] AC5: All ~25 consumers compile and pass tests with the new enum + `Secret` +- [ ] AC6: Default config TOML files use the new per-driver format +- [ ] AC7: No secrets leak in logs or tracing output +- [ ] `linter all` exits with code `0` +- [ ] Relevant tests pass + +## Verification Plan + +### Automatic Checks + +- `linter all` +- `cargo test --workspace` + +### Manual Verification Scenarios + +| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | +| --- | ------------------------------------ | ------------------------------------------------ | ------------------------ | ------ | -------- | +| M1 | Verify secrets masked in logs | Run tracker, check startup log for config output | Secrets show as `***` | TODO | | +| M2 | Verify Debug output masks secrets | `println!("{:?}", config)` in test or debug | Secrets show as `***` | TODO | | +| M3 | Verify secrets accessible via expose | Write test that reads a secret via `.expose()` | Returns the actual value | TODO | | + +### Acceptance Verification + +| AC ID | Status | Evidence | +| ----- | ------ | -------- | +| AC1 | TODO | | +| AC2 | TODO | | +| AC3 | TODO | | +| AC4 | TODO | | +| AC5 | TODO | | +| AC6 | TODO | | + +## Risks and Trade-offs + +- **Breaking change for database config**: The `Database` struct becomes an enum; the old `path` field is removed with no backward-compatibility fallback. Mitigation: this is part of the v3.0.0 config schema bump where breaking changes are expected and documented. +- **Consumer updates (~25 files)**: Every place that constructs or reads a `Database` value needs updating. Mitigation: the compiler will catch all mismatches; changes are mechanical (construct enum variant, use `.expose()` for secrets). +- **Performance**: `secrecy` adds zeroize-on-drop overhead. Mitigation: negligible for config values read once at startup. + +## References + +- Related issues: #1441 (secret leak via tracing) +- Related: `packages/configuration/src/v2_0_0/database.rs` +- Related: `packages/configuration/src/v2_0_0/tracker_api.rs` +- Related: [secrecy crate docs](https://docs.rs/secrecy/) diff --git a/docs/issues/open/1640-per-http-tracker-on-reverse-proxy-setting.md b/docs/issues/open/1640-1978-per-http-tracker-on-reverse-proxy-setting.md similarity index 86% rename from docs/issues/open/1640-per-http-tracker-on-reverse-proxy-setting.md rename to docs/issues/open/1640-1978-per-http-tracker-on-reverse-proxy-setting.md index 3666ca291..ba6a61471 100644 --- a/docs/issues/open/1640-per-http-tracker-on-reverse-proxy-setting.md +++ b/docs/issues/open/1640-1978-per-http-tracker-on-reverse-proxy-setting.md @@ -4,7 +4,7 @@ issue-type: enhancement status: open priority: p2 github-issue: 1640 -spec-path: docs/issues/open/1640-per-http-tracker-on-reverse-proxy-setting.md +spec-path: docs/issues/open/1640-1978-per-http-tracker-on-reverse-proxy-setting.md branch: "1640-move-network-to-per-instance-config" related-pr: null last-updated-utc: 2026-06-23 18:30 @@ -14,14 +14,10 @@ semantic-links: related-artifacts: - docs/adrs/20260617093046_reject_wildcard_external_ip.md - issue #1417 - - issue #1671 - - issue torrust/torrust-tracker-deployer - - issue torrust/torrust-tracker-deployer pull/273 - - issue torrust/torrust-tracker-deployer docs/ai-training/dataset/environment-configs/02-full-stack-lxd.json - - packages/configuration/src/v2_0_0/http_tracker.rs - - packages/configuration/src/v2_0_0/udp_tracker.rs - - packages/configuration/src/v2_0_0/network.rs - - packages/configuration/src/v2_0_0/core.rs + - packages/configuration/src/v3_0_0/http_tracker.rs + - packages/configuration/src/v3_0_0/udp_tracker.rs + - packages/configuration/src/v3_0_0/network.rs + - packages/configuration/src/v3_0_0/core.rs - packages/tracker-core/src/announce_handler.rs - packages/tracker-core/src/lib.rs - packages/http-core/src/container.rs @@ -52,6 +48,8 @@ semantic-links: # Issue #1640 - Move `on_reverse_proxy` to per-tracker config (and relocate `Network`) +> **EPIC position**: Subissue #3 of 9. Depends on #2 (tsl→tls typo fix). Must be implemented before #1417 (public_url) and #1490 (secrets) — both reference the `Network` block established here. Both #1640 and #1490 touch `Core`, so #1640 goes first. + ## Goal Give each tracker instance (`HttpTracker` and `UdpTracker`) its own `Network` config block containing `external_ip`, `on_reverse_proxy`, and `ipv6_v6only`. Remove the shared `[core.net]` section and make the domain-layer `AnnounceHandler` accept `external_ip` as a per-call parameter. @@ -201,6 +199,8 @@ We considered moving `bind_address` into `Network` since it is a networking conc This is a **breaking configuration change**. Users upgrading to the new tracker version (4.0.0) must update their `tracker.toml`: +> **Note on versioning**: The tracker application and the configuration schema use independent version systems. The tracker app goes from 3.0.0 → 4.0.0, while the config schema goes from 2.0.0 → 3.0.0. This allows them to evolve independently — the configuration crate can also be used partially in other projects. + **Before:** ```toml @@ -268,47 +268,28 @@ These fields (`domain`, `use_tls_proxy`) describe how each tracker instance is e > > This issue only addresses `on_reverse_proxy`; TLS configuration remains a separate concern. -#### From Issue #1417 — Public Service URL +### Related Issue: #1417 — Public Service URL (implemented in this EPIC) -Issue [#1417](https://github.com/torrust/torrust-tracker/issues/1417) proposes adding a `public_url` field to each tracker instance: +Issue [#1417](https://github.com/torrust/torrust-tracker/issues/1417) adds an optional `public_url: Option` field to each tracker instance (`HttpTracker`, `UdpTracker`) and API service (`HttpApi`, `HealthCheckApi`). This field is **implemented in this EPIC** (not a future extension) but lives as a **flat field** on each config struct — **not inside `Network`**. + +**Why flat, not inside `Network`**: The `Network` block groups **network topology** concerns (how the tracker connects: external IP, proxy awareness, socket behaviour). `public_url` is about **public exposure** (how users reach the tracker). It's a different axis — one tracker instance might have both a `net.on_reverse_proxy` setting and a `public_url`, and they are independently configurable. ```toml [[http_trackers]] -public_url = "https://tracker.torrust-demo.com/announce" bind_address = "0.0.0.0:7070" -``` - -This would allow the tracker to emit the correct public URL in metrics, logs, and API responses, regardless of whether it runs behind a reverse proxy. This is also a per-instance networking concern. - -**Decision for #1417**: Store the full URL as a single string (`public_url = "https://tracker1.example.com/announce"`). Consumers can parse out the protocol (→ TLS status), domain, and path segment as needed — no need to decompose the config field. In fact `public_url` subsumes the deployer's `domain` + `use_tls_proxy` approach entirely: the protocol tells us if TLS is used, and the domain is extracted from the URL. The tracker config should use the simplest user-facing form. - -#### How these would compose - -A future expanded `Network` block could look like: +public_url = "https://tracker.torrust-demo.com/announce" -```json -{ - "http_trackers": [ - { - "bind_address": "0.0.0.0:7070", - "net": { - "external_ip": "203.0.113.5", - "on_reverse_proxy": true, - "ipv6_v6only": false, - "public_url": "https://tracker1.example.com/announce" - } - } - ] -} +[http_trackers.net] +external_ip = "203.0.113.5" +on_reverse_proxy = true +ipv6_v6only = false ``` -(`public_url` subsumes `domain` and `use_tls_proxy` — the URL's protocol tells us if TLS is used, and the domain is extracted from the URL. The deployer's separate fields are a deployer-internal concern.) +**Design decision (July 2026)**: The field is a full URL string (`"https://tracker1.example.com/announce"`). The URL protocol is validated: HTTP trackers must use `http://` or `https://`, UDP trackers must use `udp://`. This is simpler than decomposed fields (domain + path) and consumers can parse the URL as needed. The full URL also subsumes the deployer's `domain` + `use_tls_proxy` approach — the protocol tells us if TLS is used, and the domain is extracted from the URL. -Or these could remain as flat fields on `HttpTracker`/`UdpTracker` depending on how they are consumed. The important thing is that the config structure supports per-instance values — which this issue establishes. +### Full config types (this issue + #1417) -### Full future config types (this issue + proposed extensions) - -Below is how the full types would look after this issue's changes plus the proposed future fields (from deployer and #1417). Fields marked `†` are implemented in this issue; fields marked `*` are proposals for future issues. +Below is how the full types would look after this issue's changes plus #1417 (`public_url`). Fields marked `†` are implemented in this issue; fields marked `‡` are implemented in #1417. ```rust /// Per-instance network topology config. @@ -330,11 +311,11 @@ pub struct HttpTracker { // Instance metadata pub tracker_usage_statistics: bool, + // Public exposure — how users reach this tracker + pub public_url: Option, // ‡ #1417 — full URL (e.g. "https://tracker1.example.com/announce") + // Network topology (grouped) pub net: Network, // † new - - // Future extensions (proposed, not in this issue): - // pub public_url: Option, // * #1417 — full URL for metrics/logs. Subsumes domain + TLS detection via URL parsing. } /// Server-layer config for each UDP tracker. @@ -344,11 +325,11 @@ pub struct UdpTracker { pub tracker_usage_statistics: bool, pub max_connection_id_errors_per_ip: u32, + // Public exposure — how users reach this tracker + pub public_url: Option, // ‡ #1417 — full URL (e.g. "udp://tracker1.example.com:6969") + // Network topology (grouped) pub net: Network, // † new - - // Future extensions (proposed, not in this issue): - // pub public_url: Option, // * #1417 } /// Core — no longer has any networking config. @@ -365,15 +346,13 @@ pub struct Core { } ``` -**Rationale for grouping `external_ip` + `on_reverse_proxy` + `ipv6_v6only`**: - -These three fields define how the tracker instance is seen on the network and how it behaves at the socket/protocol level: +**Rationale for keeping `public_url` flat (not inside `Network`)**: -- `external_ip`: the public IP identity -- `on_reverse_proxy`: whether the instance trusts proxy headers -- `ipv6_v6only`: whether the socket accepts dual-stack or IPv6-only +The `Network` block groups **network topology** concerns — how the tracker instance connects to the network (external IP, proxy awareness, socket behaviour). `public_url` is about **public exposure** — how users reach the tracker. These are different axes: -Future fields like `public_url` is about **public exposure** (how users reach the tracker) rather than **network topology** (how the tracker connects). It could stay flat or join `Network` depending on how it is consumed. The boundary is deliberately flexible — `Network` is not a fixed category but a pragmatic grouping of related concerns. +- A tracker behind a reverse proxy might have `net.on_reverse_proxy = true` and `public_url = "https://tracker.example.com/announce"` +- A directly-exposed tracker might have `net.on_reverse_proxy = false` and `public_url = "http://tracker.example.com:7070/announce"` +- Both fields are independently configurable; nesting one inside the other would be misleading The `AnnounceHandler` in `tracker-core` stops reading from `self.config.net.external_ip` and instead accepts it as a parameter: @@ -537,6 +516,7 @@ Append one line per meaningful update. - 2026-06-23 16:00 UTC - Copilot - Rewrote spec with full architectural vision: per-instance `Network` for all three fields, phased implementation with baby steps + draft PR. - 2026-06-23 17:45 UTC - Copilot - Added design note on `bind_address` staying flat, future extensions section (`domain`, `use_tls_proxy`, `public_url`) referencing deployer and issue #1417. - 2026-06-23 18:30 UTC - Copilot - Completed deep review against ADRs 20260617093046, 20260620000000, 20260527175600 and issues #1417, #1671. Added compatibility table and migration note. +- 2026-07-14 00:00 UTC - josecelano - Resolved #1417 relationship: `public_url` is in this EPIC (not future), stays flat (not inside `Network`). Replaced "Future Extensions" section with "Related Issue: #1417" section. Updated config types to show `public_url` as `‡` field. Added versioning note (app 4.0.0, config schema 3.0.0). ## Acceptance Criteria diff --git a/docs/issues/open/1978-configuration-overhaul-epic.md b/docs/issues/open/1978-configuration-overhaul-epic.md new file mode 100644 index 000000000..74c79519a --- /dev/null +++ b/docs/issues/open/1978-configuration-overhaul-epic.md @@ -0,0 +1,233 @@ +--- +doc-type: epic +status: open +github-issue: 1978 +spec-path: docs/issues/open/1978-configuration-overhaul-epic.md +epic-owner: josecelano +last-updated-utc: 2026-07-13 21:00 +semantic-links: + skill-links: + - create-issue + related-artifacts: + - packages/configuration/src/v2_0_0/ + - packages/configuration/src/lib.rs + - docs/issues/open/1417-1978-add-public-service-url-to-configuration.md + - docs/issues/open/1640-1978-per-http-tracker-on-reverse-proxy-setting.md + - docs/adrs/20260617093046_reject_wildcard_external_ip.md +--- + + + +# EPIC #1978 - Configuration Overhaul (schema v3.0.0) + +## Goal + +Overhaul the Torrust Tracker configuration to schema version **3.0.0**, incorporating +multiple pending enhancements, security improvements, and structural changes — +many of which are breaking changes that justify the schema version bump. + +Deliver a cleaner, more extensible, and more secure configuration model that +supports modern deployment scenarios (reverse proxies, TLS, multi-instance +metrics, logging flexibility, secrets management). + +## Why This Is Needed + +The current configuration schema (`v2.0.0`) has accumulated several limitations: + +1. **No public URL awareness** — the application cannot know its own public-facing URLs + (#1417), which breaks metrics aggregation, API discoverability, and logging in + reverse-proxy setups. +2. **Global `on_reverse_proxy`** — the setting applies to all HTTP trackers, preventing + mixed deployments where some trackers are behind a proxy and others are not (#1640). +3. **Secrets exposure risk** — API tokens and database passwords can leak via tracing + instrumentation and debug output; no systematic protection (#1490). +4. **Hardcoded IP bans reset interval** — the ban cleanup interval is hardcoded, and the + cleanup task is spawned once per UDP server instead of once globally (#1453). +5. **Missing protocol context in service identity** — bare `SocketAddr` is used where + `ServiceBinding` (protocol + address) would provide richer context for logs, health + checks, and metrics (#1415). +6. **No logging style configuration** — `TraceStyle` is hardcoded to `Default`, not + configurable (#889). Additionally, the `threshold` field name is misleading — it + should be renamed to `trace_filter` to match `tracing` crate terminology. + +Several of these changes are **breaking** (schema reorganisation, field renames, +removal of global `[core.net]`), making this the right time to bump the schema +version from `2.0.0` to `3.0.0`. + +## Scope + +### In Scope + +- Bump configuration schema version from `2.0.0` to `3.0.0` +- Copy `v2_0_0` module to `v3_0_0` as the starting point for breaking changes +- Copy crate-root `logging.rs` into both versioned modules (making each self-contained) +- All six configuration enhancements listed below +- Final cleanup: remove global re-exports, migrate all consumers to explicit v3 imports +- Migration path / backward compatibility considerations where feasible + +### Out of Scope + +- Extracting `packages/configuration` into sub-packages (tracked in #1669 EPIC) +- Non-configuration changes to the tracker core or protocol packages +- Changes to the deployer's environment config format (tracked in torrust-tracker-deployer) + +## Subissues + +Status values: `TODO`, `IN_PROGRESS`, `BLOCKED`, `DONE`. + +| Order | Issue | Local Spec | Status | Notes | +| ----- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ------ | -------------------------------------------------------------------------------- | +| 1 | [#1979](../../issues/1979) — Copy `v2_0_0` → `v3_0_0` as baseline | `docs/issues/open/1979-1978-copy-configuration-schema-v2-to-v3-baseline.md` | TODO | Foundation: all other subissues depend on this | +| 2 | [#1981](../../issues/1981) — Fix `tsl_config` → `tls_config` typo | `docs/issues/open/1981-1978-fix-tsl-config-tls-config-typo.md` | TODO | Mechanical rename; ~21 files; do early to avoid conflicts with #5 | +| 3 | [#1640](../../issues/1640) — Support per-HTTP-tracker `on_reverse_proxy` setting | `docs/issues/open/1640-1978-per-http-tracker-on-reverse-proxy-setting.md` | TODO | Heaviest change (~30 files); establishes per-instance `Network` block | +| 4 | [#1417](../../issues/1417) — Include public service URL in configuration | `docs/issues/open/1417-1978-add-public-service-url-to-configuration.md` | TODO | Depends on #3 for `Network` placement decision; adds flat `public_url` field | +| 5 | [#1415](../../issues/1415) — Use `ServiceBinding` instead of bare `SocketAddr` for service identity | `docs/issues/open/1415-1978-use-service-binding-instead-of-socket-addr.md` | TODO | Independent; no config changes; can be parallel with #6, #7, #8 | +| 6 | [#1453](../../issues/1453) — IP bans reset interval configurable + fix duplicate cleanup | `docs/issues/open/1453-1978-ip-bans-reset-interval-configurable.md` | TODO | Independent; new `[udp_tracker_server]` section; can be parallel with #5, #7, #8 | +| 7 | [#1490](../../issues/1490) — Decompose database config and overhaul secrets with `secrecy` crate | `docs/issues/open/1490-1978-decompose-database-config-and-overhaul-secrets.md` | TODO | After #3 (both touch `Core`); can be parallel with #5, #6, #8 | +| 8 | [#889](../../issues/889) — New config option for logging style | `docs/issues/open/889-1978-new-config-option-for-logging-style.md` | TODO | Independent; can be parallel with #5, #6, #7 | +| 9 | [#1980](../../issues/1980) — Final cleanup: remove global re-exports, migrate consumers to explicit v3 imports | `docs/issues/open/1980-1978-configuration-overhaul-final-cleanup.md` | TODO | Must be last; depends on ALL other subissues | + +## Delivery Strategy + +### Dependency graph + +```mermaid +graph TD + sub1["1. Copy v2→v3 baseline"] --> sub2["2. Fix tsl→tls typo"] + sub1 --> sub3["3. #1640 Network block"] + sub1 --> sub5["5. #1415 ServiceBinding"] + sub1 --> sub6["6. #1453 IP bans"] + sub1 --> sub8["8. #889 Logging style"] + sub2 --> sub3 + sub3 --> sub4["4. #1417 public_url"] + sub3 --> sub7["7. #1490 Secrets/secrecy"] + sub4 --> sub9["9. Final cleanup"] + sub5 --> sub9 + sub6 --> sub9 + sub7 --> sub9 + sub8 --> sub9 +``` + +### Critical path + +```text +1 → 2 → 3 → 4 → 9 +1 → 2 → 3 → 7 → 9 +``` + +Subissues #5, #6, #8 are independent and can run in parallel with the critical path. + +### Conflict hotspots + +| File(s) | Touched by | Mitigation | +| ----------------------------------- | ---------------------- | ---------------------------------------------------------------- | +| `v3_0_0/http_tracker.rs` | #2, #3, #4 | Implement sequentially: #2 → #3 → #4 | +| `v3_0_0/core.rs` | #3, #7 | #3 first (removes `core.net`), then #7 (changes `database` type) | +| `src/bootstrap/` | #3, #5, #6, #7, #8, #9 | Sequential order; #9 resolves all import paths last | +| `share/default/config/` | ALL | Each subissue updates its relevant section; #9 does final pass | +| `test-helpers/src/configuration.rs` | #2, #3, #7, #9 | Sequential; each appends to test config defaults | + +### Phase 0: Foundation + +- **Subissue #1** — Copy `v2_0_0` → `v3_0_0`; copy `logging.rs` into both; expose modules in `lib.rs` +- **Subissue #2** — Fix `tsl_config` → `tls_config` typo (must be done before #3 to avoid conflicts) + +### Phase 1: Structural changes (sequential) + +- **Subissue #3** (#1640) — Per-instance `Network` block. Heaviest change (~30 files). Establishes the `Network` struct that #4 references. +- **Subissue #7** (#1490) — Database enum decomposition + `secrecy` crate. After #3 (both touch `Core`). ~35 files. +- **Subissue #4** (#1417) — `public_url` flat field. After #3 (depends on `Network` placement decision). ~6 files. + +### Phase 2: Independent changes (parallel) + +These can run in any order or in parallel branches: + +- **Subissue #5** (#1415) — `ServiceBinding` instead of `SocketAddr`. No config changes. ~10 files. +- **Subissue #6** (#1453) — IP bans reset interval + fix duplicate cleanup. Isolated new config section. ~5 files. +- **Subissue #8** (#889) — Logging style config. Isolated to `Logging` struct. ~5 files. + +### Phase 3: Integration + +- **Subissue #9** — Final cleanup: remove global re-exports, migrate all ~30 consumers to explicit `v3_0_0` imports. Remove crate-root `logging.rs`. Keep `v2_0_0` module deprecated. + +For each subissue implementation in this EPIC, the default completion policy is: + +1. Run automatic checks (`linter all`, relevant tests, pre-push checks when applicable). +2. Run manual verification scenarios and record evidence. +3. Re-review acceptance criteria after implementation and update verification evidence. + +## Progress Tracking + +### Workflow Checkpoints + +- [ ] Epic spec drafted in `docs/issues/drafts/` +- [ ] Epic spec reviewed and approved by user/maintainer +- [ ] GitHub epic issue created and issue number added to this spec +- [ ] Subissues created and linked in this spec +- [ ] Subissue statuses kept up to date in the `Subissues` table +- [ ] For each implemented subissue: automatic checks completed and recorded +- [ ] For each implemented subissue: manual verification completed and recorded +- [ ] For each implemented subissue: acceptance criteria reviewed post-implementation +- [ ] Epic acceptance criteria reviewed and checked off +- [x] Epic spec drafted in `docs/issues/open/1978-configuration-overhaul-epic.md` +- [x] Epic spec reviewed and approved by user/maintainer +- [x] GitHub epic issue created: #1978 +- [ ] Subissues created and linked in this spec +- [ ] Subissue statuses kept up to date in the `Subissues` table +- [ ] For each implemented subissue: automatic checks completed and recorded +- [ ] For each implemented subissue: manual verification completed and recorded +- [ ] For each implemented subissue: acceptance criteria reviewed post-implementation +- [ ] Epic acceptance criteria reviewed and checked off +- [ ] Epic issue closed and spec moved from `docs/issues/open/` to `docs/issues/closed/` + +### Progress Log + +- 2026-07-13 21:00 UTC - josecelano - Initial EPIC spec drafted +- 2026-07-13 21:00 UTC - josecelano - Added subissue specs for copy-v2-to-v3, #1415, #1453, #1490, #889 +- 2026-07-14 00:00 UTC - josecelano - Fixed #889 field name: `log_level` → `threshold` (the field was renamed in commit 287e4842; GitHub issue #889 description was outdated) +- 2026-07-14 00:00 UTC - josecelano - Added subissue #8 (final cleanup: remove global re-exports, migrate consumers to explicit v3 imports). Updated Phase 1 to include copying crate-root `logging.rs` into versioned modules. Updated Phase 4 to deprecate (not remove) v2_0_0. +- 2026-07-14 00:00 UTC - josecelano - Resolved #1417 vs #1640 `public_url` placement: flat field (not inside `Network`). Added protocol validation. Updated both specs. +- 2026-07-14 00:00 UTC - josecelano - Rewrote #1490 spec: decomposed `Database` into enum (`Sqlite3`, `MySQL(ConnectionInfo)`, `PostgreSQL(ConnectionInfo)`); removed backward-compat fallback; added ripple-effect analysis (~25 files). Renamed issue title. +- 2026-07-15 00:00 UTC - josecelano - Dependency analysis complete. Reordered subissues: #1640 before #1417 (Network block first), #1490 after #1640 (both touch Core). Independent subissues (#1415, #1453, #889) can run in parallel. Added dependency graph and conflict hotspot table. +- 2026-07-15 00:00 UTC - josecelano - GitHub issues created: EPIC #1978, #1979 (copy baseline), #1980 (final cleanup), #1981 (tsl typo). Specs moved to `docs/issues/open/` with issue number prefix. + +## Acceptance Criteria + +- [ ] All required subissues are created and linked. +- [ ] Implementation order is explicit and justified. +- [ ] Dependencies and blockers are documented and current. +- [ ] Epic status reflects actual state of linked subissues. +- [ ] Every completed subissue includes automated verification evidence. +- [ ] Every completed subissue includes manual verification evidence. +- [ ] Every completed subissue includes post-implementation acceptance criteria review. +- [ ] Documentation and governance updates are included when required. + +### Acceptance Verification + +| AC ID | Status (`TODO`/`DONE`) | Evidence | +| ----- | ---------------------- | ----------------------------------------- | +| AC1 | TODO | All subissues created and linked | +| AC2 | TODO | Schema v3.0.0 is active and functional | +| AC3 | TODO | All six enhancements are implemented | +| AC4 | TODO | `linter all` passes | +| AC5 | TODO | All tests pass (`cargo test --workspace`) | +| AC6 | TODO | Default config files updated to v3.0.0 | + +## Risks and Trade-offs + +1. **Breaking changes for all users**: Schema bump means all existing `tracker.toml` files + need updating. Mitigation: clear migration guide and changelog. +2. **Parallel implementation collisions**: Multiple subissues modifying the same `v3_0_0` + namespace could conflict. Mitigation: implement sequentially or coordinate branches + carefully; subissue #1 (copy baseline) must be merged first. +3. **Scope creep**: More configuration changes may be discovered during implementation. + Mitigation: document new findings as separate subissues or follow-up EPICs. +4. **Backward compatibility**: Some consumers (deployer, helm charts, docker-compose files) + may need coordinated updates. Mitigation: coordinate with deployer team. + +## References + +- Related issues: #1417, #1640, #1490, #1453, #1415, #889 +- Related PRs: #1937 (spec for #1640) +- Related ADRs: `docs/adrs/20260617093046_reject_wildcard_external_ip.md` +- Related EPICs: #1669 (package overhaul) diff --git a/docs/issues/open/1979-1978-copy-configuration-schema-v2-to-v3-baseline.md b/docs/issues/open/1979-1978-copy-configuration-schema-v2-to-v3-baseline.md new file mode 100644 index 000000000..2f9c3a12d --- /dev/null +++ b/docs/issues/open/1979-1978-copy-configuration-schema-v2-to-v3-baseline.md @@ -0,0 +1,136 @@ +--- +doc-type: issue +issue-type: task +status: open +priority: p0 +github-issue: 1979 +spec-path: docs/issues/open/1979-1978-copy-configuration-schema-v2-to-v3-baseline.md +branch: "config-copy-v2-to-v3-baseline" +related-pr: null +last-updated-utc: 2026-07-13 21:00 +semantic-links: + skill-links: + - create-issue + related-artifacts: + - packages/configuration/src/v2_0_0/ + - packages/configuration/src/lib.rs + - share/default/config/ +--- + + + +# Issue #1979 - Copy configuration schema v2_0_0 to v3_0_0 as baseline + +> **EPIC position**: Subissue #1 of 9 in EPIC #1978. **Foundation — all other subissues depend on this.** Must be merged before any other subissue begins. + +## Goal + +Copy the entire `packages/configuration/src/v2_0_0/` module to `packages/configuration/src/v3_0_0/` as the starting point for all breaking changes in the Configuration Overhaul EPIC. Also copy the crate-root `logging.rs` (which contains `TraceStyle`, `setup()`, and `tracing_init()`) into both `v2_0_0/` and `v3_0_0/` so each versioned module is fully self-contained (data types + behaviour). Wire `v3_0_0` as the default schema version while keeping `v2_0_0` available for backward compatibility during the transition. + +## Background + +The Configuration Overhaul EPIC groups multiple breaking changes to the configuration schema. Rather than modifying `v2_0_0` in place (which would break existing consumers), we create a new `v3_0_0` module as a copy of `v2_0_0`. Each subsequent subissue in the EPIC applies its changes to the `v3_0_0` module only. + +This approach: + +- Keeps `v2_0_0` intact for any consumers that still need it +- Provides a clean baseline for all v3 changes +- Allows incremental migration — each subissue modifies only the v3 types +- Makes it easy to compare v2 vs v3 during review +- Makes each versioned module fully self-contained by copying the crate-root `logging.rs` (which contains `TraceStyle`, `setup()`, and `tracing_init()`) into both `v2_0_0/` and `v3_0_0/` + +## Scope + +### In Scope + +- Copy `packages/configuration/src/v2_0_0/` → `packages/configuration/src/v3_0_0/` +- Copy `packages/configuration/src/logging.rs` into `v2_0_0/logging.rs` and `v3_0_0/logging.rs` (making each versioned module self-contained) +- Update `packages/configuration/src/lib.rs` to expose both `v2_0_0` and `v3_0_0` modules +- Wire `v3_0_0` as the default schema version used by the application +- Update `share/default/config/` files to reference `schema_version = "3.0.0"` +- Ensure all existing tests still pass (v2_0_0 unchanged) +- Add basic smoke tests for v3_0_0 deserialization + +### Out of Scope + +- Any functional changes to the configuration types (those come in subsequent subissues) +- Removing `v2_0_0` module (deprecated but kept for transition) +- Updating consumers outside `packages/configuration` (done in Phase 4 of the EPIC) + +## Implementation Plan + +| ID | Status | Task | Notes | +| --- | ------ | ------------------------------------------------------------ | ----------------------------------------------------------------------------- | +| T1 | TODO | Copy `v2_0_0/` directory to `v3_0_0/` | `cp -r packages/configuration/src/v2_0_0/ packages/configuration/src/v3_0_0/` | +| T2 | TODO | Update `v3_0_0/mod.rs` to use `crate::v3_0_0` internal paths | Fix module references within the copied files | +| T3 | TODO | Copy `logging.rs` into `v2_0_0/logging.rs` | Crate-root `logging.rs` (TraceStyle, setup, tracing_init) → v2_0_0 | +| T4 | TODO | Copy `logging.rs` into `v3_0_0/logging.rs` | Same content as T3; v3 gets its own copy | +| T5 | TODO | Update `lib.rs` to expose `pub mod v3_0_0` | Alongside existing `pub mod v2_0_0` | +| T6 | TODO | Update default config files to `schema_version = "3.0.0"` | In `share/default/config/` | +| T7 | TODO | Wire application entry point to use `v3_0_0` by default | Update `lib.rs` or `container.rs` default schema selection | +| T8 | TODO | Add smoke tests: deserialize default v3 config | Verify v3_0_0 can parse the default config | +| T9 | TODO | Run `linter all` and full test suite | | + +## Progress Tracking + +### Workflow Checkpoints + +- [ ] Spec drafted in `docs/issues/drafts/` +- [ ] Spec reviewed and approved by user/maintainer +- [ ] GitHub issue created and issue number added to this spec +- [ ] Implementation completed +- [ ] Automatic verification completed (`linter all`, relevant tests) +- [ ] Manual verification scenarios executed and recorded +- [ ] Acceptance criteria reviewed after implementation +- [ ] Issue closed and spec moved to `docs/issues/open/` + +### Progress Log + +- 2026-07-13 21:00 UTC - josecelano - Initial spec drafted +- 2026-07-15 00:00 UTC - josecelano - GitHub issue #1979 created; spec moved to `docs/issues/open/1979-configuration-overhaul-copy-v2-to-v3-baseline.md` + +## Acceptance Criteria + +- [ ] AC1: `packages/configuration/src/v3_0_0/` exists as an exact copy of `v2_0_0/` +- [ ] AC2: `lib.rs` exposes both `v2_0_0` and `v3_0_0` modules +- [ ] AC3: Application uses `v3_0_0` by default +- [ ] AC4: All existing tests pass (v2 unchanged) +- [ ] AC5: Default config files reference `schema_version = "3.0.0"` +- [ ] `linter all` exits with code `0` +- [ ] Relevant tests pass + +## Verification Plan + +### Automatic Checks + +- `linter all` +- `cargo test --workspace` + +### Manual Verification Scenarios + +| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | +| --- | ----------------------------- | ----------------------------------------------------------- | -------------------------------- | ------ | -------- | +| M1 | Verify v3 module exists | `ls packages/configuration/src/v3_0_0/` | Lists same files as `v2_0_0/` | TODO | | +| M2 | Verify default config uses v3 | `cargo run -- --help` or check default config output | Shows `schema_version = "3.0.0"` | TODO | | +| M3 | Verify v2 config still loads | Run tracker with explicit `schema_version = "2.0.0"` config | Tracker starts successfully | TODO | | + +### Acceptance Verification + +| AC ID | Status | Evidence | +| ----- | ------ | -------- | +| AC1 | TODO | | +| AC2 | TODO | | +| AC3 | TODO | | +| AC4 | TODO | | +| AC5 | TODO | | + +## Risks and Trade-offs + +- **Dual maintenance**: Both v2 and v3 modules exist simultaneously, meaning bug fixes may need to be applied to both. Mitigation: v2 is deprecated; only critical fixes are backported. +- **Module path confusion**: Internal `crate::v2_0_0` references in copied files need updating to `crate::v3_0_0`. Mitigation: thorough search-and-replace after copy. + +## References + +- EPIC: Configuration Overhaul (schema v3.0.0) +- Related: `packages/configuration/src/v2_0_0/` +- Related: `packages/configuration/src/lib.rs` diff --git a/docs/issues/open/1980-1978-configuration-overhaul-final-cleanup.md b/docs/issues/open/1980-1978-configuration-overhaul-final-cleanup.md new file mode 100644 index 000000000..c7771071c --- /dev/null +++ b/docs/issues/open/1980-1978-configuration-overhaul-final-cleanup.md @@ -0,0 +1,227 @@ +--- +doc-type: issue +issue-type: task +status: open +priority: p1 +github-issue: 1980 +spec-path: docs/issues/open/1980-1978-configuration-overhaul-final-cleanup.md +branch: "config-final-cleanup" +related-pr: null +last-updated-utc: 2026-07-14 00:00 +semantic-links: + skill-links: + - create-issue + related-artifacts: + - packages/configuration/src/lib.rs + - packages/configuration/src/logging.rs + - packages/configuration/src/v2_0_0/ + - packages/configuration/src/v3_0_0/ + - src/app.rs + - src/bootstrap/ + - packages/tracker-core/src/ + - packages/http-core/src/ + - packages/udp-core/src/ + - packages/udp-server/src/ + - packages/axum-http-server/src/ + - packages/axum-rest-api-server/src/ + - packages/rest-api-runtime-adapter/src/ + - packages/test-helpers/src/ + - packages/tracker-client/ + - contrib/dev-tools/ +--- + + + +# Issue #1980 - Final cleanup: remove global re-exports, migrate all consumers to explicit versioned imports + +> **EPIC position**: Subissue #9 of 9 in EPIC #1978 — **must be last.** Depends on ALL other subissues being complete. + +## Goal + +After all v3 schema changes are implemented, perform the final cleanup: + +1. Migrate all consumers from global re-exports (`pub type Core = v2_0_0::core::Core`) to explicit versioned imports (`use torrust_tracker_configuration::v3_0_0::core::Core`) +2. Remove the global re-exports from `packages/configuration/src/lib.rs` +3. Remove the crate-root `packages/configuration/src/logging.rs` (now duplicated inside `v2_0_0/` and `v3_0_0/`) +4. Apply any other cleanup discovered during the EPIC implementation + +## Background + +The `packages/configuration/src/lib.rs` currently re-exports all v2 types as global aliases: + +```rust +pub type Configuration = v2_0_0::Configuration; +pub type Core = v2_0_0::core::Core; +pub type Logging = v2_0_0::logging::Logging; +pub type HttpApi = v2_0_0::tracker_api::HttpApi; +pub type HttpTracker = v2_0_0::http_tracker::HttpTracker; +pub type UdpTracker = v2_0_0::udp_tracker::UdpTracker; +pub type Database = v2_0_0::database::Database; +pub type Threshold = v2_0_0::logging::Threshold; +``` + +These re-exports silently couple consumers to a specific schema version. When the EPIC switches the default to v3, consumers that use `torrust_tracker_configuration::Core` would silently get a different type — potentially breaking at compile time in confusing ways. + +The decision is to **remove all global re-exports** and force consumers to import from explicit versioned paths. This is a breaking change that is appropriate for the major version bump accompanying this EPIC. + +Similarly, the crate-root `logging.rs` (which contains `TraceStyle`, `setup()`, and `tracing_init()`) was copied into both `v2_0_0/` and `v3_0_0/` during subissue #1. The original crate-root file should be removed. + +## Scope + +### In Scope + +- Migrate all ~30 consumer files from global re-exports to explicit `v3_0_0` imports +- Remove global type aliases from `packages/configuration/src/lib.rs` +- Remove crate-root `packages/configuration/src/logging.rs` +- Update `pub mod logging;` in `lib.rs` (remove or redirect) +- Ensure all tests pass after migration +- Any additional cleanup items discovered during EPIC implementation + +### Out of Scope + +- Removing `v2_0_0/` module (it stays deprecated for backward compatibility) +- Changes to the v3 schema itself (already done in previous subissues) + +## Consumer Migration Map + +The following files import from global re-exports and need updating. Each import `torrust_tracker_configuration::X` becomes `torrust_tracker_configuration::v3_0_0::::X`. + +### Core consumers (~15 files) + +| File | Current Import | New Import | +| ------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `packages/tracker-core/src/announce_handler.rs` | `use torrust_tracker_configuration::Core` | `use torrust_tracker_configuration::v3_0_0::core::Core` | +| `packages/tracker-core/src/container.rs` | `use torrust_tracker_configuration::Core` | `use torrust_tracker_configuration::v3_0_0::core::Core` | +| `packages/tracker-core/src/authentication/service.rs` | `use torrust_tracker_configuration::Core` | `use torrust_tracker_configuration::v3_0_0::core::Core` | +| `packages/tracker-core/src/databases/setup.rs` | `use torrust_tracker_configuration::Core` | `use torrust_tracker_configuration::v3_0_0::core::Core` | +| `packages/tracker-core/src/torrent/manager.rs` | `use torrust_tracker_configuration::Core` | `use torrust_tracker_configuration::v3_0_0::core::Core` | +| `packages/tracker-core/src/whitelist/authorization.rs` | `use torrust_tracker_configuration::Core` | `use torrust_tracker_configuration::v3_0_0::core::Core` | +| `packages/http-core/src/services/announce.rs` | `use torrust_tracker_configuration::Core` | `use torrust_tracker_configuration::v3_0_0::core::Core` | +| `packages/http-core/src/services/scrape.rs` | `use torrust_tracker_configuration::Core` | `use torrust_tracker_configuration::v3_0_0::core::Core` | +| `packages/http-core/src/container.rs` | `use torrust_tracker_configuration::{Core, HttpTracker}` | `use torrust_tracker_configuration::v3_0_0::{core::Core, http_tracker::HttpTracker}` | +| `packages/udp-core/src/container.rs` | `use torrust_tracker_configuration::{Core, UdpTracker}` | `use torrust_tracker_configuration::v3_0_0::{core::Core, udp_tracker::UdpTracker}` | +| `packages/udp-server/src/container.rs` | `use torrust_tracker_configuration::Core` | `use torrust_tracker_configuration::v3_0_0::core::Core` | +| `packages/udp-server/src/handlers/announce.rs` | `use torrust_tracker_configuration::Core` | `use torrust_tracker_configuration::v3_0_0::core::Core` | +| `packages/rest-api-runtime-adapter/src/v1/container.rs` | `use torrust_tracker_configuration::{Core, HttpApi, HttpTracker, UdpTracker}` | `use torrust_tracker_configuration::v3_0_0::{core::Core, tracker_api::HttpApi, http_tracker::HttpTracker, udp_tracker::UdpTracker}` | +| `src/bootstrap/jobs/torrent_cleanup.rs` | `use torrust_tracker_configuration::Core` | `use torrust_tracker_configuration::v3_0_0::core::Core` | + +### Configuration consumers (~10 files) + +| File | Current Import | New Import | +| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `src/app.rs` | `use torrust_tracker_configuration::{Configuration, HttpTracker, UdpTracker}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, http_tracker::HttpTracker, udp_tracker::UdpTracker}` | +| `src/container.rs` | `use torrust_tracker_configuration::{Configuration, HttpApi}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, tracker_api::HttpApi}` | +| `src/bootstrap/app.rs` | `use torrust_tracker_configuration::{Configuration, logging}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, logging}` | +| `src/bootstrap/config.rs` | `use torrust_tracker_configuration::{Configuration, Info}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, Info}` | +| `src/bootstrap/jobs/http_tracker_core.rs` | `use torrust_tracker_configuration::Configuration` | `use torrust_tracker_configuration::v3_0_0::Configuration` | +| `src/bootstrap/jobs/torrent_repository.rs` | `use torrust_tracker_configuration::Configuration` | `use torrust_tracker_configuration::v3_0_0::Configuration` | +| `src/bootstrap/jobs/tracker_core.rs` | `use torrust_tracker_configuration::Configuration` | `use torrust_tracker_configuration::v3_0_0::Configuration` | +| `src/bootstrap/jobs/activity_metrics_updater.rs` | `use torrust_tracker_configuration::Configuration` | `use torrust_tracker_configuration::v3_0_0::Configuration` | +| `src/console/ci/qbittorrent_e2e/tracker/config_builder.rs` | `use torrust_tracker_configuration::{Configuration, HealthCheckApi, HttpApi, HttpTracker, UdpTracker}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, health_check_api::HealthCheckApi, tracker_api::HttpApi, http_tracker::HttpTracker, udp_tracker::UdpTracker}` | + +### Test/example/bench consumers (~10 files) + +| File | Current Import | New Import | +| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `packages/test-helpers/src/configuration.rs` | `use torrust_tracker_configuration::{Configuration, HttpApi, HttpTracker, Threshold, UdpTracker}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, tracker_api::HttpApi, http_tracker::HttpTracker, logging::Threshold, udp_tracker::UdpTracker}` | +| `packages/test-helpers/src/logging.rs` | `use torrust_tracker_configuration::logging::TraceStyle` | `use torrust_tracker_configuration::v3_0_0::logging::TraceStyle` | +| `packages/axum-http-server/src/server.rs` (tests) | `use torrust_tracker_configuration::{Configuration, logging}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, logging}` | +| `packages/axum-http-server/src/testing/environment.rs` | `use torrust_tracker_configuration::{Core, HttpTracker}` | `use torrust_tracker_configuration::v3_0_0::{core::Core, http_tracker::HttpTracker}` | +| `packages/axum-rest-api-server/src/server.rs` (tests) | `use torrust_tracker_configuration::{Configuration, logging}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, logging}` | +| `packages/axum-rest-api-server/src/testing/environment.rs` | `use torrust_tracker_configuration::{Configuration, logging}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, logging}` | +| `packages/axum-http-server/examples/http_only_public_tracker.rs` | `use torrust_tracker_configuration::{Core, HttpTracker}` | `use torrust_tracker_configuration::v3_0_0::{core::Core, http_tracker::HttpTracker}` | +| `packages/udp-server/examples/udp_only_public_tracker.rs` | `use torrust_tracker_configuration::{Core, UdpTracker}` | `use torrust_tracker_configuration::v3_0_0::{core::Core, udp_tracker::UdpTracker}` | +| `packages/http-core/benches/helpers/util.rs` | `use torrust_tracker_configuration::{Configuration, Core}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, core::Core}` | +| `contrib/dev-tools/analysis/workspace-coupling/tests/parse_imports.rs` | `use torrust_tracker_configuration::{Core, UdpTracker}` | `use torrust_tracker_configuration::v3_0_0::{core::Core, udp_tracker::UdpTracker}` | + +### `logging` module consumers + +Files that import `torrust_tracker_configuration::logging` (the module, not the type): + +| File | Current Import | New Import | +| ---------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| `src/bootstrap/app.rs` | `use torrust_tracker_configuration::{Configuration, logging}` then `logging::setup(...)` | `use torrust_tracker_configuration::v3_0_0::{Configuration, logging}` then `logging::setup(...)` | +| `packages/axum-http-server/src/server.rs` (tests) | `use torrust_tracker_configuration::{Configuration, logging}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, logging}` | +| `packages/axum-rest-api-server/src/server.rs` (tests) | `use torrust_tracker_configuration::{Configuration, logging}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, logging}` | +| `packages/axum-rest-api-server/src/testing/environment.rs` | `use torrust_tracker_configuration::{Configuration, logging}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, logging}` | +| `packages/udp-server/src/server/mod.rs` (tests) | `use torrust_tracker_configuration::{Configuration, logging}` | `use torrust_tracker_configuration::v3_0_0::{Configuration, logging}` | +| `packages/test-helpers/src/logging.rs` | `use torrust_tracker_configuration::logging::TraceStyle` | `use torrust_tracker_configuration::v3_0_0::logging::TraceStyle` | + +## Implementation Plan + +| ID | Status | Task | Notes | +| --- | ------ | ------------------------------------------------------- | ------------------------------------------- | +| T1 | TODO | Migrate all consumer imports to explicit `v3_0_0` paths | ~30 files; see Consumer Migration Map above | +| T2 | TODO | Remove global type aliases from `lib.rs` | `pub type Configuration = ...` etc. | +| T3 | TODO | Remove crate-root `logging.rs` | Already copied into `v2_0_0/` and `v3_0_0/` | +| T4 | TODO | Remove `pub mod logging;` from `lib.rs` | Or redirect to versioned module if needed | +| T5 | TODO | Apply any additional cleanup discovered during EPIC | Document in progress log | +| T6 | TODO | Run `linter all` and full test suite | | + +## Progress Tracking + +### Workflow Checkpoints + +- [ ] Spec drafted in `docs/issues/drafts/` +- [ ] Spec reviewed and approved by user/maintainer +- [ ] GitHub issue created and issue number added to this spec +- [ ] Implementation completed +- [ ] Automatic verification completed (`linter all`, relevant tests) +- [ ] Manual verification scenarios executed and recorded +- [ ] Acceptance criteria reviewed after implementation +- [ ] Issue closed and spec moved to `docs/issues/open/` + +### Progress Log + +- 2026-07-14 00:00 UTC - josecelano - Initial spec drafted +- 2026-07-15 00:00 UTC - josecelano - GitHub issue #1980 created; spec moved to `docs/issues/open/1980-configuration-overhaul-final-cleanup.md` + +## Acceptance Criteria + +- [ ] AC1: All consumer imports use explicit `v3_0_0` paths (no global re-export usage remains) +- [ ] AC2: Global type aliases removed from `packages/configuration/src/lib.rs` +- [ ] AC3: Crate-root `packages/configuration/src/logging.rs` removed +- [ ] AC4: `pub mod logging;` removed or redirected in `lib.rs` +- [ ] AC5: All tests pass with the new import paths +- [ ] AC6: `v2_0_0` module remains available (deprecated but not removed) +- [ ] `linter all` exits with code `0` +- [ ] Relevant tests pass + +## Verification Plan + +### Automatic Checks + +- `linter all` +- `cargo test --workspace` +- `cargo build --workspace` (verify no broken imports) + +### Manual Verification Scenarios + +| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | +| --- | --------------------------------- | ----------------------------------------- | -------------------------- | ------- | -------- | ----------- | ---------- | -------- | ---------------- | --------------------------------- | ---- | --- | +| M1 | Verify no global re-export usage | `rg "torrust_tracker_configuration::(Core | Configuration | Logging | HttpApi | HttpTracker | UdpTracker | Database | Threshold)[^:]"` | No matches (all use v3_0_0 paths) | TODO | | +| M2 | Verify v2 module still accessible | `cargo doc --document-private-items` | v2_0_0 types documented | TODO | | +| M3 | Verify v3 module is the default | Check `lib.rs` for `LATEST_VERSION` | `LATEST_VERSION = "3.0.0"` | TODO | | + +### Acceptance Verification + +| AC ID | Status | Evidence | +| ----- | ------ | -------- | +| AC1 | TODO | | +| AC2 | TODO | | +| AC3 | TODO | | +| AC4 | TODO | | +| AC5 | TODO | | +| AC6 | TODO | | + +## Risks and Trade-offs + +- **Large diff**: ~30 files changed in one subissue. Mitigation: the changes are mechanical (search-and-replace import paths); each file change is trivial. +- **Merge conflicts**: Other subissues may touch the same consumer files. Mitigation: this subissue runs last (Phase 4), after all v3 schema changes are merged. +- **Breaking change for external consumers**: Any external crate depending on `torrust-tracker-configuration` must update imports. Mitigation: this is expected for a major version bump; documented in changelog. + +## References + +- EPIC: Configuration Overhaul (schema v3.0.0) +- Related: `packages/configuration/src/lib.rs` +- Related: `packages/configuration/src/logging.rs` diff --git a/docs/issues/open/1981-1978-fix-tsl-config-tls-config-typo.md b/docs/issues/open/1981-1978-fix-tsl-config-tls-config-typo.md new file mode 100644 index 000000000..e284446fd --- /dev/null +++ b/docs/issues/open/1981-1978-fix-tsl-config-tls-config-typo.md @@ -0,0 +1,178 @@ +--- +doc-type: issue +issue-type: task +status: open +priority: p1 +github-issue: 1981 +spec-path: docs/issues/open/1981-1978-fix-tsl-config-tls-config-typo.md +branch: "config-fix-tsl-typo" +related-pr: null +last-updated-utc: 2026-07-14 00:00 +semantic-links: + skill-links: + - create-issue + related-artifacts: + - packages/configuration/src/v3_0_0/http_tracker.rs + - packages/configuration/src/v3_0_0/tracker_api.rs + - packages/configuration/src/v3_0_0/mod.rs + - packages/configuration/src/lib.rs + - packages/axum-server/src/tsl.rs + - packages/axum-http-server/src/server.rs + - packages/axum-http-server/src/testing/environment.rs + - packages/axum-http-server/examples/http_only_public_tracker.rs + - packages/axum-rest-api-server/src/lib.rs + - packages/axum-rest-api-server/src/server.rs + - packages/axum-rest-api-server/src/testing/environment.rs + - packages/test-helpers/src/configuration.rs + - src/bootstrap/jobs/http_tracker.rs + - src/bootstrap/jobs/tracker_apis.rs + - docs/containers.md + - docs/issues/open/1640-per-http-tracker-on-reverse-proxy-setting.md +--- + + + +# Issue #1981 - Fix `tsl_config` → `tls_config` typo + +> **EPIC position**: Subissue #2 of 9 in EPIC #1978. Depends on #1979. Must be implemented **before #1640** (#3) to avoid merge conflicts on `http_tracker.rs`. + +## Goal + +Fix the pervasive typo `tsl_config` → `tls_config` across the entire codebase. This is a pre-existing typo (TLS, not TSL) that has propagated into ~13 Rust source files and ~8 documentation files. Since we are releasing config schema v3.0.0, this is the right time to fix it. + +## Background + +The codebase consistently uses `tsl_config` instead of `tls_config`: + +```rust +// packages/configuration/src/v2_0_0/http_tracker.rs +pub tsl_config: Option, + +// packages/configuration/src/v2_0_0/tracker_api.rs +pub tsl_config: Option, + +// packages/configuration/src/lib.rs +pub struct TslConfig { ... } +``` + +The struct name `TslConfig` and all field names `tsl_config` should be `TlsConfig` / `tls_config`. This is a purely mechanical rename with no behavioural change. + +## Scope + +### In Scope + +- Rename `TslConfig` → `TlsConfig` in `packages/configuration/src/lib.rs` +- Rename `tsl_config` → `tls_config` in all config struct fields (`HttpTracker`, `HttpApi`) +- Rename `tsl_config` → `tls_config` in all consumers (~13 Rust files) +- Rename `tsl_config` → `tls_config` in all documentation (~8 markdown files) +- Rename `packages/axum-server/src/tsl.rs` → `packages/axum-server/src/tls.rs` +- Update all `use` imports referencing the old module path + +### Out of Scope + +- Any functional changes to TLS configuration +- Changing the TLS implementation itself + +## Implementation Plan + +| ID | Status | Task | Notes | +| --- | ------ | ----------------------------------------- | ------------------------------------------------------------------------- | +| T1 | TODO | Rename `TslConfig` → `TlsConfig` struct | In `packages/configuration/src/lib.rs` | +| T2 | TODO | Rename `tsl_config` → `tls_config` fields | In `HttpTracker` and `HttpApi` config structs | +| T3 | TODO | Rename `tsl.rs` → `tls.rs` | In `packages/axum-server/src/`; update `mod.rs` | +| T4 | TODO | Update all Rust consumers (~13 files) | Search-and-replace `tsl_config` → `tls_config`, `TslConfig` → `TlsConfig` | +| T5 | TODO | Update all documentation (~8 files) | Search-and-replace in markdown files | +| T6 | TODO | Run `linter all` and full test suite | | + +## Consumer Files + +### Rust source files (~13) + +| File | Change | +| ---------------------------------------------------------------- | --------------------------------- | +| `packages/configuration/src/lib.rs` | `TslConfig` → `TlsConfig` | +| `packages/configuration/src/v3_0_0/http_tracker.rs` | Field + default method | +| `packages/configuration/src/v3_0_0/tracker_api.rs` | Field + default method | +| `packages/configuration/src/v3_0_0/mod.rs` | Doc comments | +| `packages/axum-server/src/tsl.rs` → `tls.rs` | File rename + function signatures | +| `packages/axum-http-server/src/server.rs` | Field access | +| `packages/axum-http-server/src/testing/environment.rs` | Field access | +| `packages/axum-http-server/examples/http_only_public_tracker.rs` | Field access + comment | +| `packages/axum-rest-api-server/src/lib.rs` | Doc comments | +| `packages/axum-rest-api-server/src/server.rs` | Field access | +| `packages/axum-rest-api-server/src/testing/environment.rs` | Field access | +| `packages/test-helpers/src/configuration.rs` | Field access | +| `src/bootstrap/jobs/http_tracker.rs` | Field access | +| `src/bootstrap/jobs/tracker_apis.rs` | Field access | + +### Documentation files (~8) + +| File | Change | +| ---------------------------------------------------------------------------------- | ---------------------------- | +| `docs/containers.md` | TOML examples | +| `docs/issues/open/1640-per-http-tracker-on-reverse-proxy-setting.md` | Code examples + design notes | +| `docs/issues/closed/1860-1669-evaluate-tslconfig-move-to-axum-server/ISSUE.md` | References | +| `docs/issues/open/1669-overhaul-packages/DECISIONS.md` | References | +| `docs/issues/open/1669-overhaul-packages/workspace-coupling-report-*.md` (3 files) | References | + +## Progress Tracking + +### Workflow Checkpoints + +- [ ] Spec drafted in `docs/issues/drafts/` +- [ ] Spec reviewed and approved by user/maintainer +- [ ] GitHub issue created and issue number added to this spec +- [ ] Implementation completed +- [ ] Automatic verification completed (`linter all`, relevant tests) +- [ ] Manual verification scenarios executed and recorded +- [ ] Acceptance criteria reviewed after implementation +- [ ] Issue closed and spec moved to `docs/issues/open/` + +### Progress Log + +- 2026-07-14 00:00 UTC - josecelano - Initial spec drafted +- 2026-07-15 00:00 UTC - josecelano - GitHub issue #1981 created; spec moved to `docs/issues/open/1981-configuration-overhaul-fix-tsl-typo.md` + +## Acceptance Criteria + +- [ ] AC1: `TslConfig` is renamed to `TlsConfig` everywhere +- [ ] AC2: `tsl_config` is renamed to `tls_config` everywhere +- [ ] AC3: `packages/axum-server/src/tsl.rs` is renamed to `tls.rs` +- [ ] AC4: All tests pass +- [ ] `linter all` exits with code `0` +- [ ] Relevant tests pass + +## Verification Plan + +### Automatic Checks + +- `linter all` +- `cargo test --workspace` +- `rg "tsl_config\|TslConfig"` — should return zero matches + +### Manual Verification Scenarios + +| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | +| --- | ---------------------------- | ---------------------------- | --------------------------- | ------ | -------- | +| M1 | Verify no tsl_config remains | `rg "tsl_config\|TslConfig"` | Zero matches | TODO | | +| M2 | Verify tracker starts | `cargo run` | Tracker starts successfully | TODO | | + +### Acceptance Verification + +| AC ID | Status | Evidence | +| ----- | ------ | -------- | +| AC1 | TODO | | +| AC2 | TODO | | +| AC3 | TODO | | +| AC4 | TODO | | + +## Risks and Trade-offs + +- **Large diff**: ~21 files changed. Mitigation: all changes are mechanical search-and-replace; no behavioural change. +- **Merge conflicts with other EPIC subissues**: Other subissues modify the same files (e.g., #1640 touches `http_tracker.rs`). Mitigation: implement this subissue early (before #1640) to avoid conflicts. + +## References + +- EPIC: Configuration Overhaul (schema v3.0.0) +- Related: `packages/configuration/src/lib.rs` (TslConfig definition) +- Related: `packages/axum-server/src/tsl.rs` diff --git a/docs/issues/open/889-1978-new-config-option-for-logging-style.md b/docs/issues/open/889-1978-new-config-option-for-logging-style.md new file mode 100644 index 000000000..df5d0dee8 --- /dev/null +++ b/docs/issues/open/889-1978-new-config-option-for-logging-style.md @@ -0,0 +1,195 @@ +--- +doc-type: issue +issue-type: enhancement +status: open +priority: p2 +github-issue: 889 +spec-path: docs/issues/open/889-1978-new-config-option-for-logging-style.md +branch: "889-logging-style" +related-pr: null +last-updated-utc: 2026-07-13 21:00 +semantic-links: + skill-links: + - create-issue + related-artifacts: + - packages/configuration/src/v3_0_0/ + - packages/configuration/src/v3_0_0/logging.rs + - packages/configuration/src/logging.rs + - src/bootstrap/ +--- + + + +# Issue #889 - New config option for logging style + +> **EPIC position**: Subissue #8 of 9. Independent — only modifies `Logging` struct. Can run in parallel with #1415, #1453, #1490. + +## Goal + +Make the tracing logging style configurable from the configuration file. Replace the hardcoded `TraceStyle::Default` with a user-selectable option, and rename `threshold` to `trace_filter` for clarity and consistency with `tracing` crate terminology. + +## Background + +After migrating from `log` to the `tracing` crate (PR #888), the codebase supports multiple tracing output styles via the `TraceStyle` enum: + +```rust +#[derive(Debug)] +pub enum TraceStyle { + Default, + Pretty(bool), + Compact, + Json, +} +``` + +However, the style is currently hardcoded to `TraceStyle::Default`. Users cannot change it without modifying the source code. + +### TraceStyle enum redesign + +The current `TraceStyle` enum has two problems: + +1. **`Default` is a concrete style, not a sentinel** — it's the standard human-readable format. Renamed to `Full` for clarity. +2. **`Pretty(bool)` carries a boolean** — the bool controls `display_filename` (whether file paths appear in log output). This is a cross-cutting option that applies to all styles, not just Pretty. Dropped the boolean; `display_filename` defaults to `false` (no file paths). Can be added as a separate `[logging]` field later if users request it. + +New enum: + +```rust +pub enum TraceStyle { + Full, // was Default — standard human-readable output (default) + Pretty, // was Pretty(false) — pretty-printed with colours + Compact, // compact single-line output + Json, // structured JSON output +} +``` + +### Architecture note: `logging.rs` location + +Currently, the `TraceStyle` enum and `setup()`/`tracing_init()` functions live in `packages/configuration/src/logging.rs` (crate root), while the `Logging` struct and `Threshold` enum live in `packages/configuration/src/v2_0_0/logging.rs`. The crate-root code depends on versioned types via global re-exports (`pub type Logging = v2_0_0::logging::Logging`). + +As part of this EPIC, each versioned module (`v2_0_0/`, `v3_0_0/`) will become **fully self-contained** — data types + behaviour. The crate-root `logging.rs` will be copied into both `v2_0_0/` and `v3_0_0/`, and the global re-exports will be removed. This is handled by subissue #1 (copy baseline) and the caller-migration subissue. + +This subissue (#889) only modifies the **v3** copy of `logging.rs`. + +### Proposed config changes + +**Current config:** + +```toml +[logging] +threshold = "info" +``` + +**New config:** + +```toml +[logging] +trace_filter = "info" +trace_style = "full" +``` + +Where `trace_style` accepts one of: + +| Value | TraceStyle variant | Description | +| ----------- | ------------------ | -------------------------------------------- | +| `"full"` | `Full` | Standard human-readable output (default) | +| `"pretty"` | `Pretty` | Pretty-printed with colours | +| `"compact"` | `Compact` | Compact single-line output | +| `"json"` | `Json` | Structured JSON output (for log aggregation) | + +All four variants are simple unit variants — no boolean parameters. The `display_filename` option (previously the `Pretty(bool)` parameter) is dropped; it defaults to `false` and can be added as a separate `[logging]` field later if users request it. + +## Scope + +### In Scope + +- Rename `threshold` → `trace_filter` in the `[logging]` config section +- Redesign `TraceStyle` enum: rename `Default` → `Full`, drop `Pretty(bool)` → `Pretty` (unit variant) +- Add `trace_style` field to the `[logging]` config section +- Wire the config value into the tracing subscriber initialization +- Update default config files +- Support all four `TraceStyle` variants + +### Out of Scope + +- Adding more tracing configuration options (e.g. per-module filter levels, `display_filename`) +- Auto-detection of terminal colour support (can be added later) + +## Implementation Plan + +| ID | Status | Task | Notes | +| --- | ------ | -------------------------------------------------------------------------- | --------------------------------------------------------------- | +| T0 | TODO | Copy `packages/configuration/src/logging.rs` into `v3_0_0/` | Make v3 logging module self-contained (data types + behaviour) | +| T1 | TODO | Rename `threshold` → `trace_filter` in `Logging` config struct | In `packages/configuration/src/v3_0_0/logging.rs` | +| T2 | TODO | Redesign `TraceStyle` enum: `Default`→`Full`, drop `Pretty(bool)`→`Pretty` | Four unit variants; no boolean parameters | +| T3 | TODO | Add `trace_style: TraceStyle` field to `Logging` config struct | Default: `TraceStyle::Full` | +| T4 | TODO | Implement deserialization for `TraceStyle` | From string values: `"full"`, `"pretty"`, `"compact"`, `"json"` | +| T5 | TODO | Wire `trace_style` into tracing subscriber initialization | In `v3_0_0/logging.rs` `setup()` function | +| T6 | TODO | Update default config files | Replace `threshold` with `trace_filter` + `trace_style` | +| T7 | TODO | Run `linter all` and tests | | + +## Progress Tracking + +### Workflow Checkpoints + +- [ ] Spec drafted in `docs/issues/drafts/` +- [ ] Spec reviewed and approved by user/maintainer +- [ ] GitHub issue created and issue number added to this spec +- [ ] Implementation completed +- [ ] Automatic verification completed (`linter all`, relevant tests) +- [ ] Manual verification scenarios executed and recorded +- [ ] Acceptance criteria reviewed after implementation +- [ ] Issue closed and spec moved to `docs/issues/open/` + +### Progress Log + +- 2026-07-13 21:00 UTC - josecelano - Initial spec drafted +- 2026-07-14 00:00 UTC - josecelano - Fixed field name: `log_level` → `threshold` (the field was renamed from `log_level` to `threshold` in commit 287e4842; the GitHub issue #889 description is outdated) +- 2026-07-14 00:00 UTC - josecelano - Redesigned `TraceStyle` enum: renamed `Default` → `Full`, dropped `Pretty(bool)` → `Pretty` (unit variant). The `display_filename` boolean is dropped (defaults to `false`); can be added as a separate config field later. + +## Acceptance Criteria + +- [ ] AC1: `threshold` is renamed to `trace_filter` in the config +- [ ] AC2: New `trace_style` field is configurable with values `"full"`, `"pretty"`, `"compact"`, `"json"` +- [ ] AC3: Default `trace_style` is `"full"` (backward-compatible behaviour) +- [ ] AC4: Tracing subscriber uses the configured style +- [ ] AC5: Default config files are updated +- [ ] `linter all` exits with code `0` +- [ ] Relevant tests pass + +## Verification Plan + +### Automatic Checks + +- `linter all` +- `cargo test --workspace` + +### Manual Verification Scenarios + +| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | +| --- | --------------------------- | ------------------------------------------- | ------------------------------- | ------ | -------- | +| M1 | Verify default style | Run tracker without `trace_style` in config | Uses `"full"` (Default) style | TODO | | +| M2 | Verify JSON style | Set `trace_style = "json"`, run tracker | Output is JSON-formatted | TODO | | +| M3 | Verify compact style | Set `trace_style = "compact"`, run tracker | Output is compact single-line | TODO | | +| M4 | Verify pretty style | Set `trace_style = "pretty"`, run tracker | Output is pretty-printed | TODO | | +| M5 | Verify `trace_filter` works | Set `trace_filter = "warn"`, run tracker | Only warn+ level messages shown | TODO | | + +### Acceptance Verification + +| AC ID | Status | Evidence | +| ----- | ------ | -------- | +| AC1 | TODO | | +| AC2 | TODO | | +| AC3 | TODO | | +| AC4 | TODO | | +| AC5 | TODO | | + +## Risks and Trade-offs + +- **Breaking change**: Renaming `threshold` to `trace_filter` breaks existing configs. Mitigation: part of the v3.0.0 schema bump where breaking changes are expected. +- **`TraceStyle` enum redesign**: Renaming `Default` → `Full` and dropping `Pretty(bool)` → `Pretty` is a breaking change for any code that constructs `TraceStyle` values directly. Mitigation: the enum is internal to the configuration crate; external consumers use the TOML string values which remain stable (`"full"`, `"pretty"`, `"compact"`, `"json"`). + +## References + +- Related issues: #878 (comment) +- Related PRs: #888 (log to tracing migration), #896 (enable colour in console output) +- Related: `packages/configuration/src/v2_0_0/logging.rs` diff --git a/docs/issues/open/AGENTS.md b/docs/issues/open/AGENTS.md new file mode 100644 index 000000000..2ad5a15af --- /dev/null +++ b/docs/issues/open/AGENTS.md @@ -0,0 +1,80 @@ +# Agents Instructions — `docs/issues/open/` + +## File Naming Conventions + +Spec files in this folder follow one of these naming patterns: + +### Standalone issue (not part of an EPIC) + +```text +{ISSUE_NUMBER}-{short-description}.md +``` + +Example: + +```text +1875-review-lto-fat-in-dev-profile.md +``` + +### EPIC spec + +```text +{EPIC_ISSUE_NUMBER}-{short-description}.md +``` + +Example: + +```text +1978-configuration-overhaul-epic.md +``` + +### Subissue (part of an EPIC) + +```text +{SUB_ISSUE_NUMBER}-{EPIC_ISSUE_NUMBER}-{short-description}.md +``` + +Where: + +- `{SUB_ISSUE_NUMBER}` — GitHub issue number of the subissue itself +- `{EPIC_ISSUE_NUMBER}` — GitHub issue number of the parent EPIC + +Example: + +```text +1979-1978-copy-configuration-schema-v2-to-v3-baseline.md +``` + +### Subissue with explicit implementation order + +An optional `si-{N}` segment can be added between the EPIC number and the description when +the implementation order within the EPIC is significant and worth surfacing in the filename: + +```text +{SUB_ISSUE_NUMBER}-{EPIC_ISSUE_NUMBER}-si-{ORDER}-{short-description}.md +``` + +Where: + +- `si-{N}` — "subissue N" in the EPIC's implementation order + +Example: + +```text +1969-1938-si-8-eliminate-unwraps-from-rest-api-client.md +``` + +## Key Rule + +**The most important part is the issue number prefix.** It makes it easy to locate any spec +from a GitHub issue number and vice versa. Always start the filename with the GitHub issue +number. + +## Summary Table + +| Pattern | Example | +| ------------------- | ---------------------------------------------------------- | +| Standalone | `1875-review-lto-fat-in-dev-profile.md` | +| EPIC | `1978-configuration-overhaul-epic.md` | +| Subissue | `1979-1978-copy-configuration-schema-v2-to-v3-baseline.md` | +| Subissue with order | `1969-1938-si-8-eliminate-unwraps-from-rest-api-client.md` | diff --git a/project-words.txt b/project-words.txt index 001a380d6..b8e1714df 100644 --- a/project-words.txt +++ b/project-words.txt @@ -70,6 +70,8 @@ clippy cloneable codecov codegen +colour +colours commiter completei composecheck @@ -239,6 +241,7 @@ multimap myacicontext mysqladmin mysqld +ñaca Naim nanos newkey @@ -314,6 +317,7 @@ recompiles recvspace referer Registar +reorganisation reorganising repomix repr @@ -460,5 +464,5 @@ Xunlei xxxxxxxxxxxxxxxxxxxxd yyyyyyyyyyyyyyyyyyyyd zerocopy +zeroize zstd -ñaca From dfe7b71d56d0eefef447999052bc2e41188c4dd6 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 15 Jul 2026 11:48:59 +0100 Subject: [PATCH 2/2] docs(configuration): address Copilot PR review comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix stale spec filenames in progress log entries for issues #1979, #1980, and #1981 (old intermediate names → correct final names) - Replace .expose() with .expose_secret() in 4 places in spec #1490 (the correct secrecy crate API is ExposeSecret::expose_secret()) - Replace scheme() + bind_to() with protocol() + bind_address() in 2 places in spec #1415 (actual ServiceBinding API from torrust-net-primitives) - Fix malformed markdown table in spec #1980 where unescaped | in an rg command broke the table columns Addresses review comments on PR #1982. --- ...e-service-binding-instead-of-socket-addr.md | 18 +++++++++--------- ...ose-database-config-and-overhaul-secrets.md | 16 ++++++++-------- ...y-configuration-schema-v2-to-v3-baseline.md | 2 +- ...978-configuration-overhaul-final-cleanup.md | 12 ++++++------ ...1981-1978-fix-tsl-config-tls-config-typo.md | 2 +- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/issues/open/1415-1978-use-service-binding-instead-of-socket-addr.md b/docs/issues/open/1415-1978-use-service-binding-instead-of-socket-addr.md index 98f306501..9f1238311 100644 --- a/docs/issues/open/1415-1978-use-service-binding-instead-of-socket-addr.md +++ b/docs/issues/open/1415-1978-use-service-binding-instead-of-socket-addr.md @@ -66,7 +66,7 @@ A future issue could build an "internal connection URL" from the OS-resolved IP - Health check info structs - Metrics labels - Domain events (if applicable) -- No new types — `ServiceBinding` already has `scheme()` and `bind_to()` methods +- No new types — `ServiceBinding` already has `protocol()` and `bind_address()` methods - No changes to `torrust-net-primitives` external crate ### Out of Scope @@ -80,14 +80,14 @@ A future issue could build an "internal connection URL" from the OS-resolved IP ## Implementation Plan -| ID | Status | Task | Notes | -| --- | ------ | ------------------------------------------------------------------------ | ----------------------------------------------------- | -| T1 | TODO | Identify all places where bare `SocketAddr` is used for service identity | Logs, health check, metrics, events, server launchers | -| T2 | TODO | Replace `SocketAddr` with `ServiceBinding` in those places | `ServiceBinding` already has `scheme()` + `bind_to()` | -| T3 | TODO | Update startup logging to use `ServiceBinding` | Replace manual URL string construction | -| T4 | TODO | Update health check info to include `ServiceBinding` | For issue #1409 | -| T5 | TODO | Update metrics to use `ServiceBinding` scheme as a label | For issue #1403/#1414 | -| T6 | TODO | Run `linter all` and tests | | +| ID | Status | Task | Notes | +| --- | ------ | ------------------------------------------------------------------------ | ------------------------------------------------------------ | +| T1 | TODO | Identify all places where bare `SocketAddr` is used for service identity | Logs, health check, metrics, events, server launchers | +| T2 | TODO | Replace `SocketAddr` with `ServiceBinding` in those places | `ServiceBinding` already has `protocol()` + `bind_address()` | +| T3 | TODO | Update startup logging to use `ServiceBinding` | Replace manual URL string construction | +| T4 | TODO | Update health check info to include `ServiceBinding` | For issue #1409 | +| T5 | TODO | Update metrics to use `ServiceBinding` scheme as a label | For issue #1403/#1414 | +| T6 | TODO | Run `linter all` and tests | | ## Progress Tracking diff --git a/docs/issues/open/1490-1978-decompose-database-config-and-overhaul-secrets.md b/docs/issues/open/1490-1978-decompose-database-config-and-overhaul-secrets.md index 2adcbc778..5e26201a1 100644 --- a/docs/issues/open/1490-1978-decompose-database-config-and-overhaul-secrets.md +++ b/docs/issues/open/1490-1978-decompose-database-config-and-overhaul-secrets.md @@ -156,7 +156,7 @@ The `rest-api-client` crate and `tracker-core` authentication are **not affected - Wrap database password in `Secret` (inside `ConnectionInfo`) - Wrap API tokens in `Secret` (in `HttpApi` config struct) - Remove manual `mask_secrets()` methods (replaced by type-level protection) -- Update all ~25 consumers to use the new enum variants and `.expose()` for secret access +- Update all ~25 consumers to use the new enum variants and `.expose_secret()` for secret access - Update default config TOML files (6 files) to the new format - Update inline TOML in tests and doc comments @@ -178,7 +178,7 @@ The `rest-api-client` crate and `tracker-core` authentication are **not affected | T5 | TODO | Wrap API tokens in `Secret` | In `HttpApi` config struct | | T6 | TODO | Remove manual `mask_secrets()` methods | No longer needed with type-level protection | | T7 | TODO | Update `tracker-core/src/databases/setup.rs` dispatch | Match on `Database` enum variant instead of `Driver` | -| T8 | TODO | Update all ~25 consumers (tests, examples, benchmarks, E2E) | Construct enum variants; use `.expose()` for secrets | +| T8 | TODO | Update all ~25 consumers (tests, examples, benchmarks, E2E) | Construct enum variants; use `.expose_secret()` for secrets | | T9 | TODO | Update default config TOML files (6 files) | New per-driver format | | T10 | TODO | Update inline TOML in tests and doc comments | `mod.rs` tests, `lib.rs`, integration tests | | T11 | TODO | Run `linter all` and full test suite | | @@ -222,11 +222,11 @@ The `rest-api-client` crate and `tracker-core` authentication are **not affected ### Manual Verification Scenarios -| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | -| --- | ------------------------------------ | ------------------------------------------------ | ------------------------ | ------ | -------- | -| M1 | Verify secrets masked in logs | Run tracker, check startup log for config output | Secrets show as `***` | TODO | | -| M2 | Verify Debug output masks secrets | `println!("{:?}", config)` in test or debug | Secrets show as `***` | TODO | | -| M3 | Verify secrets accessible via expose | Write test that reads a secret via `.expose()` | Returns the actual value | TODO | | +| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | +| --- | ------------------------------------------- | ----------------------------------------------------- | ------------------------ | ------ | -------- | +| M1 | Verify secrets masked in logs | Run tracker, check startup log for config output | Secrets show as `***` | TODO | | +| M2 | Verify Debug output masks secrets | `println!("{:?}", config)` in test or debug | Secrets show as `***` | TODO | | +| M3 | Verify secrets accessible via expose_secret | Write test that reads a secret via `.expose_secret()` | Returns the actual value | TODO | | ### Acceptance Verification @@ -242,7 +242,7 @@ The `rest-api-client` crate and `tracker-core` authentication are **not affected ## Risks and Trade-offs - **Breaking change for database config**: The `Database` struct becomes an enum; the old `path` field is removed with no backward-compatibility fallback. Mitigation: this is part of the v3.0.0 config schema bump where breaking changes are expected and documented. -- **Consumer updates (~25 files)**: Every place that constructs or reads a `Database` value needs updating. Mitigation: the compiler will catch all mismatches; changes are mechanical (construct enum variant, use `.expose()` for secrets). +- **Consumer updates (~25 files)**: Every place that constructs or reads a `Database` value needs updating. Mitigation: the compiler will catch all mismatches; changes are mechanical (construct enum variant, use `.expose_secret()` for secrets). - **Performance**: `secrecy` adds zeroize-on-drop overhead. Mitigation: negligible for config values read once at startup. ## References diff --git a/docs/issues/open/1979-1978-copy-configuration-schema-v2-to-v3-baseline.md b/docs/issues/open/1979-1978-copy-configuration-schema-v2-to-v3-baseline.md index 2f9c3a12d..d7c89f594 100644 --- a/docs/issues/open/1979-1978-copy-configuration-schema-v2-to-v3-baseline.md +++ b/docs/issues/open/1979-1978-copy-configuration-schema-v2-to-v3-baseline.md @@ -87,7 +87,7 @@ This approach: ### Progress Log - 2026-07-13 21:00 UTC - josecelano - Initial spec drafted -- 2026-07-15 00:00 UTC - josecelano - GitHub issue #1979 created; spec moved to `docs/issues/open/1979-configuration-overhaul-copy-v2-to-v3-baseline.md` +- 2026-07-15 00:00 UTC - josecelano - GitHub issue #1979 created; spec moved to `docs/issues/open/1979-1978-copy-configuration-schema-v2-to-v3-baseline.md` ## Acceptance Criteria diff --git a/docs/issues/open/1980-1978-configuration-overhaul-final-cleanup.md b/docs/issues/open/1980-1978-configuration-overhaul-final-cleanup.md index c7771071c..3617a61a9 100644 --- a/docs/issues/open/1980-1978-configuration-overhaul-final-cleanup.md +++ b/docs/issues/open/1980-1978-configuration-overhaul-final-cleanup.md @@ -174,7 +174,7 @@ Files that import `torrust_tracker_configuration::logging` (the module, not the ### Progress Log - 2026-07-14 00:00 UTC - josecelano - Initial spec drafted -- 2026-07-15 00:00 UTC - josecelano - GitHub issue #1980 created; spec moved to `docs/issues/open/1980-configuration-overhaul-final-cleanup.md` +- 2026-07-15 00:00 UTC - josecelano - GitHub issue #1980 created; spec moved to `docs/issues/open/1980-1978-configuration-overhaul-final-cleanup.md` ## Acceptance Criteria @@ -197,11 +197,11 @@ Files that import `torrust_tracker_configuration::logging` (the module, not the ### Manual Verification Scenarios -| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | -| --- | --------------------------------- | ----------------------------------------- | -------------------------- | ------- | -------- | ----------- | ---------- | -------- | ---------------- | --------------------------------- | ---- | --- | -| M1 | Verify no global re-export usage | `rg "torrust_tracker_configuration::(Core | Configuration | Logging | HttpApi | HttpTracker | UdpTracker | Database | Threshold)[^:]"` | No matches (all use v3_0_0 paths) | TODO | | -| M2 | Verify v2 module still accessible | `cargo doc --document-private-items` | v2_0_0 types documented | TODO | | -| M3 | Verify v3 module is the default | Check `lib.rs` for `LATEST_VERSION` | `LATEST_VERSION = "3.0.0"` | TODO | | +| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | +| --- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ------ | -------- | +| M1 | Verify no global re-export usage | `rg 'torrust_tracker_configuration::(Core\|Configuration\|Logging\|HttpApi\|HttpTracker\|UdpTracker\|Database\|Threshold)[^:]'` | No matches (all use v3_0_0 paths) | TODO | | +| M2 | Verify v2 module still accessible | `cargo doc --document-private-items` | v2_0_0 types documented | TODO | | +| M3 | Verify v3 module is the default | Check `lib.rs` for `LATEST_VERSION` | `LATEST_VERSION = "3.0.0"` | TODO | | ### Acceptance Verification diff --git a/docs/issues/open/1981-1978-fix-tsl-config-tls-config-typo.md b/docs/issues/open/1981-1978-fix-tsl-config-tls-config-typo.md index e284446fd..2ade26fdd 100644 --- a/docs/issues/open/1981-1978-fix-tsl-config-tls-config-typo.md +++ b/docs/issues/open/1981-1978-fix-tsl-config-tls-config-typo.md @@ -131,7 +131,7 @@ The struct name `TslConfig` and all field names `tsl_config` should be `TlsConfi ### Progress Log - 2026-07-14 00:00 UTC - josecelano - Initial spec drafted -- 2026-07-15 00:00 UTC - josecelano - GitHub issue #1981 created; spec moved to `docs/issues/open/1981-configuration-overhaul-fix-tsl-typo.md` +- 2026-07-15 00:00 UTC - josecelano - GitHub issue #1981 created; spec moved to `docs/issues/open/1981-1978-fix-tsl-config-tls-config-typo.md` ## Acceptance Criteria