fix(mysql): [#410] Fix multiple MySQL configuration issues#424
Merged
josecelano merged 4 commits intotorrust:mainfrom Apr 8, 2026
Merged
Conversation
Bug 2 fix from issue torrust#410. - Add optional root_password field to environment config JSON schema - MysqlConfig.root_password is Password (non-optional); domain always has a value - MysqlConfigRaw.root_password is Option<Password> for backward compat with persisted environments that pre-date this field - Add src/shared/secrets/random.rs: generate_random_password() -> Password using rand::rng(), mixed charset (lower+upper+digit+symbol), length 32, satisfies MySQL validate_password MEDIUM policy - Generate root_password once in TryFrom<DatabaseSection> at environment creation time (not at render time) so it is stable across re-renders - Remove format!("{password}_root") derivation from create_mysql_contexts - Update spec docs/issues/410-bug-multiple-mysql-configuration-issues.md to reflect the actual implementation
Phase 3 fix from issue torrust#410. - Add percent-encoding = "2.0" to Cargo.toml - TrackerServiceConfig: add optional database_path field (Some for MySQL, None for SQLite) with serde skip_serializing_if so it only appears in template context for MySQL - EnvContext::new_with_mysql: percent-encode username and password using a custom USERINFO_ENCODE AsciiSet (encodes @, :, /, #, ?, %, + but NOT unreserved chars like _ so tracker_user stays tracker_user, not tracker%5Fuser) - Build full MySQL DSN and store in tracker.database_path - EnvContext::new_with_mysql: add mysql_host (String) and mysql_port (u16) params so the DSN can be constructed without needing domain types at the infra layer - templates/docker-compose/.env.tera: add TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__PATH inside the Tracker Service Configuration section (inside {%- if mysql %} block); move before MySQL section - templates/docker-compose/docker-compose.yml.tera: inject the new env var into the tracker service environment section, conditionally on {%- if mysql %} - templates/tracker/tracker.toml.tera: remove mysql path = line; replace with a comment explaining the env var override (no Tera tag needed — comment is static) - TrackerContext: remove MysqlTemplateConfig struct and mysql field entirely; the MySQL case only needs database_driver = mysql now - Add tests: percent-encoded DSN, alphanumeric DSN, database_path None for SQLite - Update project_generator.rs test: hardcoded template updated and assertions changed to confirm driver = mysql and absence of path/password lines - Update issue doc: mark all Phase 1-4 items [x]; add Phase 5 status note - 2314 tests pass
- cspell: add USERINFO, userinfo, CSPRNG, plainpassword to project-words.txt - clippy: use map_or_else instead of map().unwrap_or_else() in tracker_core_section.rs - clippy: backtick MySQL and SQLite in doc comments (doc_markdown) - clippy: add #[allow(clippy::too_many_arguments)] to new_with_mysql - clippy: change mysql_host and host from String to &str (needless_pass_by_value) - clippy: add # Panics section to generate_random_password docs - clippy: replace redundant closures with char::is_uppercase/is_lowercase - rustfmt: run cargo fmt - docs: mark Phase 5 and all acceptance criteria as complete in issue torrust#410
Member
Author
|
ACK afabd0c |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes three related MySQL configuration bugs discovered during the Hetzner demo deployment (#405).
Closes #410
Bug 1 — MySQL DSN hardcoded in
tracker.tomlwith no URL-encodingProblem: The tracker config template interpolated raw credentials directly into the DSN URL. Passwords with URL-reserved characters (
@,:,/,+) produced malformed DSNs and broke MySQL connectivity. The plaintext password also ended up in a mounted config file instead of an env var.Fix:
percent-encodingcrate; built a customUSERINFO_ENCODEAsciiSetthat preserves RFC 3986 unreserved chars (sotracker_useris not over-encoded)EnvContext::new_with_mysql) and stored asTORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__PATHin.envdocker-compose.yml.terainjects the new env var into the tracker containertracker.toml.terano longer contains the DSN; a static comment explains the injectionMysqlTemplateConfigremoved entirelyBug 2 — MySQL root password not configurable
Problem: Root password was unconditionally derived as
{app_password}_root, giving users no way to supply their own value and making it entirely predictable.Fix:
root_passwordfield to the environment config JSON schemagenerate_random_password()insrc/shared/secrets/random.rs(32-char, mixed charset, satisfies MySQL MEDIUM policy)TryFrom<DatabaseSection>), not at render time, so it stays stable across re-renderscreate_mysql_contextsno longer contains any derivation logicBug 3 — No validation that MySQL app username is not
"root"Problem: The MySQL Docker image rejects
MYSQL_USER=root, but the deployer only validated for an empty username, deferring the error to Docker startup time.Fix:
ReservedUsernamevariant toMysqlConfigErrorwith an actionablehelp()messageMysqlConfig::new()rejects"root"immediately with a clear errorTesting
cargo test)tracker_p@ss!word#1— confirmed@→%40,#→%23in the rendered.envcargo run --bin linter all)cargo machetereports no unused dependencies./scripts/pre-commit.sh)Checklist
MysqlConfig::new()rejects"root"withReservedUsernameerrorroot_passwordis configurable and generated at creation time when omittedtracker.tomlno longer contains the database passwordcargo machetereports no unused dependencies