mirror of
https://github.com/openai/codex.git
synced 2026-04-29 00:55:38 +00:00
## Why
`codex-core` has accumulated config loading, requirements parsing, constraint logic, and config-layer state handling in one large crate. This refactor pulls that cohesive subsystem into a dedicated crate so we can reduce the compile/test surface area of `codex-core` and make future config work more isolated.
This is part of the broader goal of right-sizing crates to reduce monolithic rebuild cost and improve incremental development speed.
## What Changed
### New crate
- Added a new workspace crate: `codex-rs/config` (`codex-config`)
- Added workspace wiring in `codex-rs/Cargo.toml`
- Added dependency from `codex-core` to `codex-config`
### Moved config internals from `core` to `config`
Moved these modules into `codex-config`:
- `core/src/config/constraint.rs` -> `config/src/constraint.rs`
- `core/src/config_loader/cloud_requirements.rs` -> `config/src/config_loader/cloud_requirements.rs`
- `core/src/config_loader/config_requirements.rs` -> `config/src/config_loader/config_requirements.rs`
- `core/src/config_loader/fingerprint.rs` -> `config/src/config_loader/fingerprint.rs`
- `core/src/config_loader/merge.rs` -> `config/src/config_loader/merge.rs`
- `core/src/config_loader/overrides.rs` -> `config/src/config_loader/overrides.rs`
- `core/src/config_loader/requirements_exec_policy.rs` -> `config/src/config_loader/requirements_exec_policy.rs`
- `core/src/config_loader/state.rs` -> `config/src/config_loader/state.rs`
### Removed shim modules in `core`
After the move, the temporary one-line `pub use` shim files under `core/src/config_loader/` were deleted so history is a clean move/delete rather than introducing extra permanent forwarding modules.
`core/src/config_loader/mod.rs` now imports/re-exports directly from `codex_config`, including direct use of `build_cli_overrides_layer` and test-only access to `version_for_toml`.
### Follow-on fixes for direct imports
- Updated `core/src/config_loader/macos.rs` to use `super::{ConfigRequirementsToml, ConfigRequirementsWithSources, RequirementSource}`.
- Updated `core/src/config_loader/tests.rs` imports to reference `crate::config_loader` re-exports and `codex_config` exec-policy TOML types.
## Behavior and API Notes
- Config behavior is intended to be unchanged.
- `codex-core` continues to expose the same config-loader-facing API surface to its internal callers via `core/src/config_loader/mod.rs` re-exports.
- The main functional change is crate ownership and dependency direction, not config semantics.
## Validation
Ran:
- `cargo test -p codex-config`
- `cargo test -p codex-core --no-run`
- `cargo test -p codex-core config_loader::tests::load_requirements_toml_produces_expected_constraints`
- `cargo test -p codex-core config_loader::tests::requirements_exec_policy_tests::parses_single_prefix_rule_from_raw_toml`
- `just fmt`
- `just fix -p codex-config -p codex-core`
- `just fix -p codex-core`
All listed commands completed successfully in this workspace environment.
68 lines
2.0 KiB
Rust
68 lines
2.0 KiB
Rust
use codex_app_server_protocol::ConfigLayerMetadata;
|
|
use serde_json::Value as JsonValue;
|
|
use sha2::Digest;
|
|
use sha2::Sha256;
|
|
use std::collections::HashMap;
|
|
use toml::Value as TomlValue;
|
|
|
|
pub(super) fn record_origins(
|
|
value: &TomlValue,
|
|
meta: &ConfigLayerMetadata,
|
|
path: &mut Vec<String>,
|
|
origins: &mut HashMap<String, ConfigLayerMetadata>,
|
|
) {
|
|
match value {
|
|
TomlValue::Table(table) => {
|
|
for (key, val) in table {
|
|
path.push(key.clone());
|
|
record_origins(val, meta, path, origins);
|
|
path.pop();
|
|
}
|
|
}
|
|
TomlValue::Array(items) => {
|
|
for (idx, item) in (0_i32..).zip(items.iter()) {
|
|
path.push(idx.to_string());
|
|
record_origins(item, meta, path, origins);
|
|
path.pop();
|
|
}
|
|
}
|
|
_ => {
|
|
if !path.is_empty() {
|
|
origins.insert(path.join("."), meta.clone());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn version_for_toml(value: &TomlValue) -> String {
|
|
let json = serde_json::to_value(value).unwrap_or(JsonValue::Null);
|
|
let canonical = canonical_json(&json);
|
|
let serialized = serde_json::to_vec(&canonical).unwrap_or_default();
|
|
let mut hasher = Sha256::new();
|
|
hasher.update(serialized);
|
|
let hash = hasher.finalize();
|
|
let hex = hash
|
|
.iter()
|
|
.map(|byte| format!("{byte:02x}"))
|
|
.collect::<String>();
|
|
format!("sha256:{hex}")
|
|
}
|
|
|
|
fn canonical_json(value: &JsonValue) -> JsonValue {
|
|
match value {
|
|
JsonValue::Object(map) => {
|
|
let mut sorted = serde_json::Map::new();
|
|
let mut keys = map.keys().cloned().collect::<Vec<_>>();
|
|
keys.sort();
|
|
for key in keys {
|
|
if let Some(val) = map.get(&key) {
|
|
sorted.insert(key, canonical_json(val));
|
|
}
|
|
}
|
|
JsonValue::Object(sorted)
|
|
}
|
|
JsonValue::Array(items) => JsonValue::Array(items.iter().map(canonical_json).collect()),
|
|
other => other.clone(),
|
|
}
|
|
}
|