Skip to content

Commit afabd0c

Browse files
committed
chore(mysql): fix linting issues from Phase 5
- 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
1 parent d465611 commit afabd0c

8 files changed

Lines changed: 37 additions & 27 deletions

File tree

docs/issues/410-bug-multiple-mysql-configuration-issues.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -313,10 +313,10 @@ Tasks are ordered from simplest to most complex.
313313

314314
### Phase 5: Linting and pre-commit
315315

316-
- [ ] Run linters: `cargo run --bin linter all`
317-
- [ ] Run pre-commit: `./scripts/pre-commit.sh`
316+
- [x] Run linters: `cargo run --bin linter all`
317+
- [x] Run pre-commit: `./scripts/pre-commit.sh`
318318

319-
> **Status**: Phases 1–4 complete and committed. Phase 5 pending.
319+
> **Status**: Phases 1–5 complete and committed.
320320
321321
## Acceptance Criteria
322322

@@ -326,7 +326,7 @@ Tasks are ordered from simplest to most complex.
326326
327327
**Quality Checks**:
328328

329-
- [ ] Pre-commit checks pass: `./scripts/pre-commit.sh`
329+
- [x] Pre-commit checks pass: `./scripts/pre-commit.sh`
330330

331331
**Task-Specific Criteria — Bug 3 (reserved username)**:
332332

@@ -365,7 +365,7 @@ Tasks are ordered from simplest to most complex.
365365
a valid, correctly encoded DSN in the `.env` file (verified with `tracker_p@ss!word#1`)
366366
- [x] A MySQL password with only alphanumeric characters is rendered unchanged
367367
- [x] `MysqlTemplateConfig` no longer exists in `tracker_config/context.rs`
368-
- [ ] `cargo machete` reports no unused dependencies
368+
- [x] `cargo machete` reports no unused dependencies
369369

370370
## Manual E2E Verification Test
371371

project-words.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,10 @@ zcat
540540
zeroize
541541
zoneinfo
542542
zstd
543+
CSPRNG
544+
USERINFO
545+
plainpassword
546+
userinfo
543547
Émojis
544548
значение
545549
ключ

src/application/command_handlers/create/config/tracker/tracker_core_section.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,7 @@ impl TryFrom<DatabaseSection> for DatabaseConfig {
9494
root_password,
9595
} => {
9696
let root_password = root_password
97-
.map(|p| Password::from(p.as_str()))
98-
.unwrap_or_else(generate_random_password);
97+
.map_or_else(generate_random_password, |p| Password::from(p.as_str()));
9998
let config = MysqlConfig::new(
10099
host,
101100
port,

src/application/services/rendering/docker_compose.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ impl DockerComposeTemplateRenderingService {
107107
DatabaseConfig::Mysql(mysql_config) => self.create_mysql_contexts(
108108
admin_token.to_string(),
109109
tracker,
110-
mysql_config.host().to_string(),
110+
mysql_config.host(),
111111
mysql_config.port(),
112112
mysql_config.database_name().to_string(),
113113
mysql_config.username().to_string(),
@@ -215,7 +215,7 @@ impl DockerComposeTemplateRenderingService {
215215
&self,
216216
admin_token: String,
217217
tracker: TrackerServiceContext,
218-
host: String,
218+
host: &str,
219219
port: u16,
220220
database_name: String,
221221
username: String,

src/domain/tracker/config/core/database/mysql.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub enum MysqlConfigError {
1919
/// Username cannot be empty
2020
#[error("MySQL username cannot be empty")]
2121
EmptyUsername,
22-
/// Username `root` is reserved by the MySQL Docker image
22+
/// Username `root` is reserved by the `MySQL` Docker image
2323
#[error("MySQL username \"root\" is reserved and cannot be used as the app database username")]
2424
ReservedUsername,
2525
}

src/infrastructure/templating/docker_compose/template/wrappers/env/context.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use serde::Serialize;
1212

1313
use crate::infrastructure::templating::TemplateMetadata;
1414

15-
/// Characters that must be percent-encoded in the userinfo (user/password) part of a MySQL DSN URL.
15+
/// Characters that must be percent-encoded in the userinfo (user/password) part of a `MySQL` DSN URL.
1616
///
1717
/// Encodes delimiters that have structural meaning in the URL authority component:
1818
/// - `@` — userinfo/host separator
@@ -45,9 +45,9 @@ pub struct TrackerServiceConfig {
4545
/// Database driver type ("sqlite3" or "mysql")
4646
/// Controls which config template the container entrypoint uses
4747
pub database_driver: String,
48-
/// Percent-encoded MySQL DSN for `TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__PATH`
48+
/// Percent-encoded `MySQL` DSN for `TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__PATH`
4949
///
50-
/// Only populated when MySQL is configured; `None` for SQLite.
50+
/// Only populated when `MySQL` is configured; `None` for `SQLite`.
5151
/// Username and password are percent-encoded with `NON_ALPHANUMERIC` to handle
5252
/// URL-reserved characters (e.g. `@`, `+`, `/`, `:`).
5353
#[serde(skip_serializing_if = "Option::is_none")]
@@ -171,21 +171,22 @@ impl EnvContext {
171171
/// "tracker_db".to_string(),
172172
/// "tracker_user".to_string(),
173173
/// "user_pass".to_string(),
174-
/// "mysql".to_string(),
174+
/// "mysql",
175175
/// 3306,
176176
/// );
177177
/// assert_eq!(context.tracker.database_driver, "mysql");
178178
/// assert!(context.mysql.is_some());
179179
/// ```
180180
#[must_use]
181+
#[allow(clippy::too_many_arguments)]
181182
pub fn new_with_mysql(
182183
metadata: TemplateMetadata,
183184
tracker_api_admin_token: String,
184185
mysql_root_password: String,
185186
mysql_database: String,
186187
mysql_user: String,
187188
mysql_password: String,
188-
mysql_host: String,
189+
mysql_host: &str,
189190
mysql_port: u16,
190191
) -> Self {
191192
let encoded_user = utf8_percent_encode(&mysql_user, &USERINFO_ENCODE).to_string();
@@ -321,7 +322,7 @@ mod tests {
321322
"tracker_db".to_string(),
322323
"tracker_user".to_string(),
323324
"user_pass".to_string(),
324-
"mysql".to_string(),
325+
"mysql",
325326
3306,
326327
);
327328

@@ -358,7 +359,7 @@ mod tests {
358359
"db".to_string(),
359360
"user".to_string(),
360361
"pass".to_string(),
361-
"mysql".to_string(),
362+
"mysql",
362363
3306,
363364
);
364365

@@ -387,7 +388,7 @@ mod tests {
387388
"tracker_db".to_string(),
388389
"tracker_user".to_string(),
389390
"user_pass".to_string(),
390-
"mysql".to_string(),
391+
"mysql",
391392
3306,
392393
);
393394

@@ -411,7 +412,7 @@ mod tests {
411412
"tracker".to_string(),
412413
"tracker_user".to_string(),
413414
"p@ss:w/ord+1".to_string(),
414-
"mysql".to_string(),
415+
"mysql",
415416
3306,
416417
);
417418

@@ -434,7 +435,7 @@ mod tests {
434435
"tracker".to_string(),
435436
"tracker_user".to_string(),
436437
"plainpassword123".to_string(),
437-
"mysql".to_string(),
438+
"mysql",
438439
3306,
439440
);
440441

src/shared/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ pub use command::{CommandError, CommandExecutor, CommandResult};
1919
pub use domain_name::{DomainName, DomainNameError};
2020
pub use email::{Email, EmailError};
2121
pub use error::{ErrorKind, Traceable};
22-
pub use secrets::{ApiToken, ExposeSecret, Password, PlainApiToken, PlainPassword, generate_random_password};
22+
pub use secrets::{
23+
generate_random_password, ApiToken, ExposeSecret, Password, PlainApiToken, PlainPassword,
24+
};
2325
pub use service_endpoint::{InvalidServiceEndpointUrl, ServiceEndpoint};
2426
pub use username::{Username, UsernameError};

src/shared/secrets/random.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Cryptographically random password generation
22
3-
use rand::Rng as _;
43
use rand::seq::IndexedRandom as _;
54
use rand::seq::SliceRandom as _;
5+
use rand::Rng as _;
66

77
use super::password::Password;
88

@@ -25,11 +25,16 @@ fn full_charset() -> Vec<u8> {
2525
/// reseeded — suitable for secrets in rand 0.9 (direct `OsRng` no longer
2626
/// implements the high-level `Rng` trait required by `choose`/`shuffle`)
2727
/// - `choose`: avoids modulo bias — uniform distribution
28-
/// - Explicit class inclusion: satisfies MySQL `validate_password` MEDIUM policy
28+
/// - Explicit class inclusion: satisfies `MySQL` `validate_password` MEDIUM policy
2929
/// - Shuffle: removes structural bias from fixed positions
3030
///
3131
/// The generated password is 32 characters long and always contains at least
3232
/// one lowercase letter, one uppercase letter, one digit, and one symbol.
33+
///
34+
/// # Panics
35+
///
36+
/// Panics if any character set constant is empty, which cannot happen in practice
37+
/// as they are defined as non-empty byte string literals.
3338
#[must_use]
3439
pub fn generate_random_password() -> Password {
3540
let mut rng = rand::rng();
@@ -78,12 +83,11 @@ mod tests {
7883
let s = pwd.expose_secret();
7984

8085
assert_eq!(s.len(), 32, "password must be 32 characters");
81-
assert!(s.chars().any(|c| c.is_uppercase()), "must contain uppercase");
82-
assert!(s.chars().any(|c| c.is_lowercase()), "must contain lowercase");
86+
assert!(s.chars().any(char::is_uppercase), "must contain uppercase");
87+
assert!(s.chars().any(char::is_lowercase), "must contain lowercase");
8388
assert!(s.chars().any(|c| c.is_ascii_digit()), "must contain digit");
8489
assert!(
85-
s.chars()
86-
.any(|c| "!@#$%^&*()-_=+[]{}<>?".contains(c)),
90+
s.chars().any(|c| "!@#$%^&*()-_=+[]{}<>?".contains(c)),
8791
"must contain symbol"
8892
);
8993
assert!(s.is_ascii(), "must be ASCII (safe in .env files and shell)");

0 commit comments

Comments
 (0)