Use codex-utils-template for login error page (#16000)

This commit is contained in:
jif-oai
2026-03-27 14:49:45 +01:00
committed by GitHub
Unverified
parent 6a0c4709ca
commit 270b7655cd
4 changed files with 60 additions and 12 deletions
+1
View File
@@ -2224,6 +2224,7 @@ dependencies = [
"codex-keyring-store",
"codex-protocol",
"codex-terminal-detection",
"codex-utils-template",
"core_test_support",
"keyring",
"once_cell",
+1
View File
@@ -17,6 +17,7 @@ codex-config = { workspace = true }
codex-keyring-store = { workspace = true }
codex-protocol = { workspace = true }
codex-terminal-detection = { workspace = true }
codex-utils-template = { workspace = true }
once_cell = { workspace = true }
os_info = { workspace = true }
rand = { workspace = true }
+5 -5
View File
@@ -101,21 +101,21 @@
<div class="brand-title">Codex login</div>
</div>
<h1>__ERROR_TITLE__</h1>
<p class="message">__ERROR_MESSAGE__</p>
<h1>{{error_title}}</h1>
<p class="message">{{error_message}}</p>
<div class="details">
<div class="details-row">
<strong>Error code</strong>
<code>__ERROR_CODE__</code>
<code>{{error_code}}</code>
</div>
<div class="details-row">
<strong>Details</strong>
<code>__ERROR_DESCRIPTION__</code>
<code>{{error_description}}</code>
</div>
</div>
<p class="help">__ERROR_HELP__</p>
<p class="help">{{error_help}}</p>
</div>
</div>
</body>
+53 -7
View File
@@ -20,6 +20,7 @@ use std::net::TcpStream;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::LazyLock;
use std::thread;
use std::time::Duration;
@@ -35,6 +36,7 @@ use base64::Engine;
use chrono::Utc;
use codex_app_server_protocol::AuthMode;
use codex_client::build_reqwest_client_with_custom_ca;
use codex_utils_template::Template;
use rand::RngCore;
use serde_json::Value as JsonValue;
use tiny_http::Header;
@@ -48,6 +50,10 @@ use tracing::warn;
const DEFAULT_ISSUER: &str = "https://auth.openai.com";
const DEFAULT_PORT: u16 = 1455;
static LOGIN_ERROR_PAGE_TEMPLATE: LazyLock<Template> = LazyLock::new(|| {
Template::parse(include_str!("assets/error.html"))
.unwrap_or_else(|err| panic!("login error page template must parse: {err}"))
});
/// Options for launching the local login callback server.
#[derive(Debug, Clone)]
@@ -1001,7 +1007,6 @@ fn render_login_error_page(
error_code: Option<&str>,
error_description: Option<&str>,
) -> Vec<u8> {
let template = include_str!("assets/error.html");
let code = error_code.unwrap_or("unknown_error");
let (title, display_message, display_description, help_text) =
if is_missing_codex_entitlement_error(code, error_description) {
@@ -1022,12 +1027,15 @@ fn render_login_error_page(
.to_string(),
)
};
template
.replace("__ERROR_TITLE__", &html_escape(&title))
.replace("__ERROR_MESSAGE__", &html_escape(&display_message))
.replace("__ERROR_CODE__", &html_escape(code))
.replace("__ERROR_DESCRIPTION__", &html_escape(&display_description))
.replace("__ERROR_HELP__", &html_escape(&help_text))
LOGIN_ERROR_PAGE_TEMPLATE
.render([
("error_title", html_escape(&title)),
("error_message", html_escape(&display_message)),
("error_code", html_escape(code)),
("error_description", html_escape(&display_description)),
("error_help", html_escape(&help_text)),
])
.unwrap_or_else(|err| panic!("login error page template must render: {err}"))
.into_bytes()
}
@@ -1087,9 +1095,12 @@ mod tests {
use pretty_assertions::assert_eq;
use super::TokenEndpointErrorDetail;
use super::html_escape;
use super::is_missing_codex_entitlement_error;
use super::parse_token_endpoint_error;
use super::redact_sensitive_query_value;
use super::redact_sensitive_url_parts;
use super::render_login_error_page;
use super::sanitize_url_for_logging;
#[test]
@@ -1189,4 +1200,39 @@ mod tests {
"https://example.com/base?token=%3Credacted%3E&env=prod".to_string()
);
}
#[test]
fn render_login_error_page_escapes_dynamic_fields() {
let body = String::from_utf8(render_login_error_page(
"<bad>",
Some("code&value"),
Some("\"quoted\""),
))
.expect("login error page should be utf-8");
assert!(body.contains(&html_escape("Sign-in could not be completed")));
assert!(body.contains("&lt;bad&gt;"));
assert!(body.contains("code&amp;value"));
assert!(body.contains("&quot;quoted&quot;"));
}
#[test]
fn render_login_error_page_uses_entitlement_copy() {
let error_description = Some("missing_codex_entitlement");
assert!(is_missing_codex_entitlement_error(
"access_denied",
error_description
));
let body = String::from_utf8(render_login_error_page(
"access denied",
Some("access_denied"),
error_description,
))
.expect("login error page should be utf-8");
assert!(body.contains("You do not have access to Codex"));
assert!(body.contains("Contact your workspace administrator"));
assert!(!body.contains("missing_codex_entitlement"));
}
}