core-agent-ide/codex-rs/network-proxy/src/metadata.rs
viyatb-oai 2bced810da
feat(network-proxy): structured policy signaling and attempt correlation to core (#11662)
## Summary
When network requests were blocked, downstream code often had to infer
ask vs deny from free-form response text. That was brittle and led to
incorrect approval behavior.
This PR fixes the proxy side so blocked decisions are structured and
request metadata survives reliably.

## Description
- Blocked proxy responses now carry consistent structured policy
decision data.
- Request attempt metadata is preserved across proxy env paths
(including ALL_PROXY flows).
- Header stripping was tightened so we still remove unsafe forwarding
headers, but keep metadata needed for policy handling.
- Block messages were clarified (for example, allowlist miss vs explicit
deny).
- Added unified violation log entries so policy failures can be
inspected in one place.
- Added/updated tests for these behaviors.

---------

Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
2026-02-13 09:01:11 +00:00

50 lines
1.7 KiB
Rust

use base64::Engine;
use base64::engine::general_purpose::STANDARD;
use rama_http::HeaderValue;
pub const NETWORK_ATTEMPT_USERNAME_PREFIX: &str = "codex-net-attempt-";
pub fn proxy_username_for_attempt_id(attempt_id: &str) -> String {
format!("{NETWORK_ATTEMPT_USERNAME_PREFIX}{attempt_id}")
}
pub fn attempt_id_from_proxy_authorization(header: Option<&HeaderValue>) -> Option<String> {
let header = header?;
let raw = header.to_str().ok()?;
let encoded = raw.strip_prefix("Basic ")?;
let decoded = STANDARD.decode(encoded.trim()).ok()?;
let decoded = String::from_utf8(decoded).ok()?;
let username = decoded
.split_once(':')
.map(|(user, _)| user)
.unwrap_or(decoded.as_str());
let attempt_id = username.strip_prefix(NETWORK_ATTEMPT_USERNAME_PREFIX)?;
if attempt_id.is_empty() {
None
} else {
Some(attempt_id.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
use base64::engine::general_purpose::STANDARD;
#[test]
fn parses_attempt_id_from_proxy_authorization_header() {
let encoded = STANDARD.encode(format!("{NETWORK_ATTEMPT_USERNAME_PREFIX}abc123:"));
let header = HeaderValue::from_str(&format!("Basic {encoded}")).unwrap();
assert_eq!(
attempt_id_from_proxy_authorization(Some(&header)),
Some("abc123".to_string())
);
}
#[test]
fn ignores_non_attempt_proxy_authorization_header() {
let encoded = STANDARD.encode("normal-user:password");
let header = HeaderValue::from_str(&format!("Basic {encoded}")).unwrap();
assert_eq!(attempt_id_from_proxy_authorization(Some(&header)), None);
}
}