fix(login): remove rand deprecation warnings by using rand::rng().fill_bytes()

Policy: treat warnings as failures. Switched from thread_rng() to rng() in PKCE
and login state generation. Build remains clean.
This commit is contained in:
James Peter
2025-09-16 11:29:31 +10:00
parent a0e4d7265f
commit 0509750ed3
8 changed files with 102 additions and 48 deletions
+8 -5
View File
@@ -10,7 +10,7 @@ Usage: ./build-fast.sh [env flags]
Environment flags:
PROFILE=dev-fast|dev|release-prod Build profile (default: dev-fast)
TRACE_BUILD=1 Print toolchain/env and artifact SHA
KEEP_ENV=1 Do NOT sanitize env (use your current env)
KEEP_ENV=0 Sanitize env for reproducible builds (default skips)
DETERMINISTIC=1 Add -C debuginfo=0; promotes to release-prod unless DETERMINISTIC_FORCE_RELEASE=0
DETERMINISTIC_FORCE_RELEASE=0|1 Keep dev-fast (0) or switch to release-prod (1, default)
DETERMINISTIC_NO_UUID=1 macOS only: strip LC_UUID on final executables
@@ -39,6 +39,9 @@ cd "${SCRIPT_DIR}/codex-rs"
# where the parent folder may be owned by a different user.
REPO_ROOT="${SCRIPT_DIR}"
# Default to preserving caller environment unless explicitly disabled
KEEP_ENV="${KEEP_ENV:-1}"
# Use dev-fast profile by default for quick iteration
# Can override with: PROFILE=release ./build-fast.sh
PROFILE="${PROFILE:-dev-fast}"
@@ -110,9 +113,9 @@ else
exit 1
fi
# Canonicalize build environment so everyone shares the same cache by default.
# Set KEEP_ENV=1 to skip this sanitization.
if [ "${KEEP_ENV:-}" != "1" ]; then
# Canonicalize build environment only when requested.
# Set KEEP_ENV=0 to force sanitization.
if [ "${KEEP_ENV}" != "1" ]; then
# Only define RUSTFLAGS via feature flags like DETERMINISTIC=1; otherwise clear.
if [ -z "${DETERMINISTIC:-}" ]; then
export RUSTFLAGS=""
@@ -199,7 +202,7 @@ if [ "${TRACE_BUILD:-}" = "1" ]; then
rustup run "$TOOLCHAIN" rustc -vV || true
rustup run "$TOOLCHAIN" cargo -vV || true
fi
echo "CANONICAL_ENV_APPLIED: ${CANONICAL_ENV_APPLIED} (KEEP_ENV=${KEEP_ENV:-})"
echo "CANONICAL_ENV_APPLIED: ${CANONICAL_ENV_APPLIED} (KEEP_ENV=${KEEP_ENV})"
echo "Filtered env (CARGO|RUST*|PROFILE|CODE_HOME|CODEX_HOME):"
env | egrep '^(CARGO|RUST|RUSTUP|PROFILE|CODE_HOME|CODEX_HOME)=' | sort || true
echo "--------------------------------"
+2 -3
View File
@@ -828,9 +828,8 @@ dependencies = [
"chromiumoxide_types",
"chrono",
"futures",
"image 0.25.8",
"once_cell",
"rand 0.8.5",
"rand 0.9.2",
"regex",
"reqwest",
"serde",
@@ -1056,7 +1055,7 @@ dependencies = [
"chrono",
"codex-core",
"codex-protocol",
"rand 0.8.5",
"rand 0.9.2",
"reqwest",
"serde",
"serde_json",
+2 -3
View File
@@ -13,15 +13,14 @@ workspace = true
[dependencies]
anyhow = "1"
async-trait = "0.1"
base64 = "0.22"
base64 = "0.22.1"
bytes = "1"
chromiumoxide = { version = "0.7", features = ["tokio-runtime"], default-features = false }
chromiumoxide_types = "0.7"
chrono = { version = "0.4", features = ["serde"] }
futures = "0.3"
image = "0.25"
once_cell = "1.20"
rand = "0.8"
rand = "0.9"
regex = "1"
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
serde = { version = "1", features = ["derive"] }
+1 -1
View File
@@ -15,7 +15,7 @@ workspace = true
anyhow = "1"
askama = "0.12"
async-channel = "2.3.1"
base64 = "0.22"
base64 = "0.22.1"
bytes = "1.10.1"
chrono = { version = "0.4", features = ["serde"] }
codex-apply-patch = { path = "../apply-patch" }
+85 -32
View File
@@ -210,38 +210,6 @@ pub async fn upsert_agent_config(
let mut doc = match tokio::fs::read_to_string(&config_path).await {
Ok(s) => s.parse::<DocumentMut>()?,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
async fn persist_overrides_with_behavior(
codex_home: &Path,
profile: Option<&str>,
overrides: &[(&[&str], Option<&str>)],
none_behavior: NoneBehavior,
) -> Result<()> {
if overrides.is_empty() {
return Ok(());
}
let should_skip = match none_behavior {
NoneBehavior::Skip => overrides.iter().all(|(_, value)| value.is_none()),
NoneBehavior::Remove => false,
};
if should_skip {
return Ok(());
}
let config_path = codex_home.join(CONFIG_TOML_FILE);
let read_result = tokio::fs::read_to_string(&config_path).await;
let mut doc = match read_result {
Ok(contents) => contents.parse::<DocumentMut>()?,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
if overrides
.iter()
.all(|(_, value)| value.is_none() && matches!(none_behavior, NoneBehavior::Remove))
{
return Ok(());
}
tokio::fs::create_dir_all(codex_home).await?;
DocumentMut::new()
}
@@ -338,6 +306,91 @@ async fn write_new_or_append(
Ok(())
}
// Internal helper to support persist_* variants above.
async fn persist_overrides_with_behavior(
codex_home: &Path,
profile: Option<&str>,
overrides: &[(&[&str], Option<&str>)],
none_behavior: NoneBehavior,
) -> Result<()> {
if overrides.is_empty() {
return Ok(());
}
let should_skip = match none_behavior {
NoneBehavior::Skip => overrides.iter().all(|(_, value)| value.is_none()),
NoneBehavior::Remove => false,
};
if should_skip {
return Ok(());
}
let config_path = codex_home.join(CONFIG_TOML_FILE);
let read_result = tokio::fs::read_to_string(&config_path).await;
let mut doc = match read_result {
Ok(contents) => contents.parse::<DocumentMut>()?,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
if overrides.iter().all(|(_, value)| value.is_none() && matches!(none_behavior, NoneBehavior::Remove)) {
return Ok(());
}
tokio::fs::create_dir_all(codex_home).await?;
DocumentMut::new()
}
Err(e) => return Err(e.into()),
};
let effective_profile = if let Some(p) = profile { Some(p.to_owned()) } else { doc.get("profile").and_then(|i| i.as_str()).map(|s| s.to_string()) };
let mut mutated = false;
for (segments, value) in overrides.iter().copied() {
let mut seg_buf: Vec<&str> = Vec::new();
let segments_to_apply: &[&str];
if let Some(ref name) = effective_profile {
if segments.first().copied() == Some("profiles") {
segments_to_apply = segments;
} else {
seg_buf.reserve(2 + segments.len());
seg_buf.push("profiles");
seg_buf.push(name.as_str());
seg_buf.extend_from_slice(segments);
segments_to_apply = seg_buf.as_slice();
}
} else {
segments_to_apply = segments;
}
match value {
Some(v) => {
let item_value = toml_edit::value(v);
apply_toml_edit_override_segments(&mut doc, segments_to_apply, item_value);
mutated = true;
}
None => {
if matches!(none_behavior, NoneBehavior::Remove) && remove_toml_edit_segments(&mut doc, segments_to_apply) {
mutated = true;
}
}
}
}
if !mutated { return Ok(()); }
let tmp_file = NamedTempFile::new_in(codex_home)?;
tokio::fs::write(tmp_file.path(), doc.to_string()).await?;
tmp_file.persist(config_path)?;
Ok(())
}
fn remove_toml_edit_segments(doc: &mut DocumentMut, segments: &[&str]) -> bool {
use toml_edit::Item;
if segments.is_empty() { return false; }
let mut current = doc.as_table_mut();
for seg in &segments[..segments.len() - 1] {
let Some(item) = current.get_mut(seg) else { return false };
match item { Item::Table(table) => { current = table; } _ => { return false; } }
}
current.remove(segments[segments.len() - 1]).is_some()
}
#[cfg(test)]
mod tests {
use super::*;
+2 -2
View File
@@ -7,11 +7,11 @@ version = { workspace = true }
workspace = true
[dependencies]
base64 = "0.22"
base64 = "0.22.1"
chrono = { version = "0.4", features = ["serde"] }
codex-core = { path = "../core" }
codex-protocol = { path = "../protocol" }
rand = "0.8"
rand = "0.9"
reqwest = { version = "0.12", default-features = false, features = ["json", "blocking", "rustls-tls"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
+1 -1
View File
@@ -11,7 +11,7 @@ pub struct PkceCodes {
pub fn generate_pkce() -> PkceCodes {
let mut bytes = [0u8; 64];
rand::thread_rng().fill_bytes(&mut bytes);
rand::rng().fill_bytes(&mut bytes);
// Verifier: URL-safe base64 without padding (43..128 chars)
let code_verifier = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(bytes);
+1 -1
View File
@@ -324,7 +324,7 @@ fn build_authorize_url(
fn generate_state() -> String {
let mut bytes = [0u8; 32];
rand::thread_rng().fill_bytes(&mut bytes);
rand::rng().fill_bytes(&mut bytes);
base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(bytes)
}