Skip to content

Commit e601f27

Browse files
authored
Merge pull request #6525 from Turbo87/secrecy
Use `secrecy` crate for database URLs and git credentials
2 parents 3bad8ac + bd37930 commit e601f27

File tree

8 files changed

+37
-25
lines changed

8 files changed

+37
-25
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cargo-registry-index/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ anyhow = "=1.0.71"
1717
base64 = "=0.13.1"
1818
dotenvy = "=0.15.7"
1919
git2 = "=0.17.1"
20+
secrecy = "=0.8.0"
2021
serde = { version = "=1.0.163", features = ["derive"] }
2122
serde_json = "=1.0.96"
2223
tempfile = "=3.5.0"

cargo-registry-index/credentials.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
use anyhow::{anyhow, Context};
2+
use secrecy::{ExposeSecret, SecretString};
23
use std::io::Write;
34

45
#[derive(Clone)]
56
pub enum Credentials {
67
Missing,
7-
Http { username: String, password: String },
8-
Ssh { key: String },
8+
Http {
9+
username: String,
10+
password: SecretString,
11+
},
12+
Ssh {
13+
key: SecretString,
14+
},
915
}
1016

1117
impl Credentials {
12-
pub(crate) fn ssh_key(&self) -> Option<&str> {
18+
pub(crate) fn ssh_key(&self) -> Option<&SecretString> {
1319
match self {
1420
Credentials::Ssh { key } => Some(key),
1521
_ => None,
@@ -48,7 +54,7 @@ impl Credentials {
4854
.context("Failed to create temporary file")?;
4955

5056
temp_key_file
51-
.write_all(key.as_bytes())
57+
.write_all(key.expose_secret().as_bytes())
5258
.context("Failed to write SSH key to temporary file")?;
5359

5460
Ok(temp_key_file.into_temp_path())

cargo-registry-index/repo.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::credentials::Credentials;
22
use anyhow::{anyhow, Context};
3+
use secrecy::{ExposeSecret, SecretString};
34
use std::path::{Path, PathBuf};
45
use std::process::Command;
56
use tempfile::TempDir;
@@ -13,10 +14,10 @@ pub struct RepositoryConfig {
1314
impl RepositoryConfig {
1415
pub fn from_environment() -> Self {
1516
let username = dotenvy::var("GIT_HTTP_USER");
16-
let password = dotenvy::var("GIT_HTTP_PWD");
17+
let password = dotenvy::var("GIT_HTTP_PWD").map(SecretString::from);
1718
let http_url = dotenvy::var("GIT_REPO_URL");
1819

19-
let ssh_key = dotenvy::var("GIT_SSH_KEY");
20+
let ssh_key = dotenvy::var("GIT_SSH_KEY").map(SecretString::from);
2021
let ssh_url = dotenvy::var("GIT_SSH_REPO_URL");
2122

2223
match (username, password, http_url, ssh_key, ssh_url) {
@@ -29,12 +30,11 @@ impl RepositoryConfig {
2930
let index_location =
3031
Url::parse(&ssh_url).expect("failed to parse GIT_SSH_REPO_URL");
3132

32-
let credentials = Credentials::Ssh {
33-
key: String::from_utf8(
34-
base64::decode(encoded_key).expect("failed to base64 decode the ssh key"),
35-
)
36-
.expect("failed to convert the ssh key to a string"),
37-
};
33+
let key = base64::decode(encoded_key.expose_secret())
34+
.expect("failed to base64 decode the ssh key");
35+
let key =
36+
String::from_utf8(key).expect("failed to convert the ssh key to a string");
37+
let credentials = Credentials::Ssh { key: key.into() };
3838

3939
Self {
4040
index_location,

src/bin/background-worker.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use cargo_registry::worker::cloudfront::CloudFront;
2020
use cargo_registry::{background_jobs::*, db, ssh};
2121
use cargo_registry_index::{Repository, RepositoryConfig};
2222
use reqwest::blocking::Client;
23+
use secrecy::ExposeSecret;
2324
use std::sync::{Arc, Mutex};
2425
use std::thread::sleep;
2526
use std::time::{Duration, Instant};
@@ -49,7 +50,7 @@ fn main() {
4950
}
5051
}
5152

52-
let db_url = db::connection_url(&config.db, &config.db.primary.url);
53+
let db_url = db::connection_url(&config.db, config.db.primary.url.expose_secret());
5354

5455
let job_start_timeout = dotenvy::var("BACKGROUND_JOB_TIMEOUT")
5556
.unwrap_or_else(|_| "30".into())

src/config/database_pools.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
1414
use crate::config::Base;
1515
use crate::{env, Env};
16+
use secrecy::SecretString;
1617

1718
pub struct DatabasePools {
1819
/// Settings for the primary database. This is usually writeable, but will be read-only in
@@ -32,7 +33,7 @@ pub struct DatabasePools {
3233

3334
#[derive(Debug)]
3435
pub struct DbPoolConfig {
35-
pub url: String,
36+
pub url: SecretString,
3637
pub read_only_mode: bool,
3738
pub pool_size: u32,
3839
pub min_idle: Option<u32>,
@@ -53,8 +54,8 @@ impl DatabasePools {
5354
///
5455
/// This function panics if `DB_OFFLINE=leader` but `READ_ONLY_REPLICA_URL` is unset.
5556
pub fn full_from_environment(base: &Base) -> Self {
56-
let leader_url = env("DATABASE_URL");
57-
let follower_url = dotenvy::var("READ_ONLY_REPLICA_URL").ok();
57+
let leader_url = env("DATABASE_URL").into();
58+
let follower_url = dotenvy::var("READ_ONLY_REPLICA_URL").map(Into::into).ok();
5859
let read_only_mode = dotenvy::var("READ_ONLY_MODE").is_ok();
5960

6061
let primary_pool_size = match dotenvy::var("DB_PRIMARY_POOL_SIZE") {
@@ -136,7 +137,7 @@ impl DatabasePools {
136137
pub fn test_from_environment() -> Self {
137138
DatabasePools {
138139
primary: DbPoolConfig {
139-
url: env("TEST_DATABASE_URL"),
140+
url: env("TEST_DATABASE_URL").into(),
140141
read_only_mode: false,
141142
pool_size: 1,
142143
min_idle: None,

src/db.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use diesel::prelude::*;
22
use diesel::r2d2::{self, ConnectionManager, CustomizeConnection};
33
use prometheus::Histogram;
4+
use secrecy::{ExposeSecret, SecretString};
45
use std::sync::{Arc, Mutex, MutexGuard};
56
use std::{
67
ops::{Deref, DerefMut},
@@ -27,12 +28,12 @@ pub enum DieselPool {
2728

2829
impl DieselPool {
2930
pub(crate) fn new(
30-
url: &str,
31+
url: &SecretString,
3132
config: &config::DatabasePools,
3233
r2d2_config: r2d2::Builder<ConnectionManager<PgConnection>>,
3334
time_to_obtain_connection_metric: Histogram,
3435
) -> Result<DieselPool, PoolError> {
35-
let manager = ConnectionManager::new(connection_url(config, url));
36+
let manager = ConnectionManager::new(connection_url(config, url.expose_secret()));
3637

3738
// For crates.io we want the behavior of creating a database pool to be slightly different
3839
// than the defaults of R2D2: the library's build() method assumes its consumers always
@@ -69,8 +70,8 @@ impl DieselPool {
6970
}
7071
}
7172

72-
pub(crate) fn new_test(config: &config::DatabasePools, url: &str) -> DieselPool {
73-
let mut conn = PgConnection::establish(&connection_url(config, url))
73+
pub(crate) fn new_test(config: &config::DatabasePools, url: &SecretString) -> DieselPool {
74+
let mut conn = PgConnection::establish(&connection_url(config, url.expose_secret()))
7475
.expect("failed to establish connection");
7576
conn.begin_test_transaction()
7677
.expect("failed to begin test transaction");
@@ -167,7 +168,7 @@ impl DerefMut for DieselPooledConn<'_> {
167168
pub fn oneoff_connection_with_config(
168169
config: &config::DatabasePools,
169170
) -> ConnectionResult<PgConnection> {
170-
let url = connection_url(config, &config.primary.url);
171+
let url = connection_url(config, config.primary.url.expose_secret());
171172
PgConnection::establish(&url)
172173
}
173174

src/tests/util/test_app.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use cargo_registry::swirl::Runner;
1313
use diesel::PgConnection;
1414
use oauth2::{ClientId, ClientSecret};
1515
use reqwest::{blocking::Client, Proxy};
16+
use secrecy::ExposeSecret;
1617
use std::collections::HashSet;
1718

1819
struct TestAppInner {
@@ -201,17 +202,17 @@ impl TestAppBuilder {
201202
// The schema will be cleared up once the app is dropped.
202203
let (primary_db_chaosproxy, replica_db_chaosproxy, fresh_schema) =
203204
if !self.config.use_test_database_pool {
204-
let fresh_schema = FreshSchema::new(&self.config.db.primary.url);
205+
let fresh_schema = FreshSchema::new(self.config.db.primary.url.expose_secret());
205206
let (primary_proxy, url) =
206207
ChaosProxy::proxy_database_url(fresh_schema.database_url()).unwrap();
207-
self.config.db.primary.url = url;
208+
self.config.db.primary.url = url.into();
208209

209210
let replica_proxy = match self.test_database {
210211
TestDatabase::SlowRealPool { replica: true } => {
211212
let (replica_proxy, url) =
212213
ChaosProxy::proxy_database_url(fresh_schema.database_url()).unwrap();
213214
self.config.db.replica = Some(DbPoolConfig {
214-
url,
215+
url: url.into(),
215216
read_only_mode: true,
216217
pool_size: 1,
217218
min_idle: None,

0 commit comments

Comments
 (0)