use axum::{Json, Router, http::StatusCode, response::Html, routing::get};
use serde::Deserialize;
const STATUS_FACTS_JSON: &str = include_str!("public-status.json");
const STATUS_STYLE: &str = include_str!("public_status.css");
const STATUS_SCRIPT: &str = include_str!("public_status.js");
#[derive(Debug, Deserialize)]
struct StatusFacts {
maturity: String,
maturity_summary: String,
spec: SpecFacts,
publication: PublicationFacts,
gap_registry: GapRegistryFacts,
default_off_features: Vec<FeatureFact>,
bounded_capabilities: Vec<BoundedCapability>,
}
#[derive(Debug, Deserialize)]
struct SpecFacts {
normative_version: String,
normative_document: String,
authority_record: String,
engineering_version: String,
engineering_document: String,
v2_3_present_in_repository: bool,
}
#[derive(Debug, Deserialize)]
struct PublicationFacts {
version: String,
observed_at: String,
github_published_at: String,
github_url: String,
native_archive_contents: String,
runtime_deployment_claimed: bool,
pypi_package: String,
}
#[derive(Debug, Deserialize)]
struct GapRegistryFacts {
path: String,
header_amended: String,
header_records_release: String,
note: String,
}
#[derive(Debug, Deserialize)]
struct FeatureFact {
package: String,
feature: String,
boundary: String,
}
#[derive(Debug, Deserialize)]
struct BoundedCapability {
name: String,
posture: String,
}
pub fn public_status_router() -> Router {
Router::new().route("/status", get(handle_public_status))
}
async fn handle_public_status() -> Result<Html<String>, (StatusCode, Json<serde_json::Value>)> {
render_public_status().map(Html).map_err(|reason| {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(serde_json::json!({
"error": "public_status_unavailable",
"reason": reason,
})),
)
})
}
fn render_public_status() -> Result<String, String> {
let facts: StatusFacts = serde_json::from_str(STATUS_FACTS_JSON)
.map_err(|error| format!("public status facts failed to parse: {error}"))?;
if facts.maturity != "beta" {
return Err(format!(
"public status maturity must be beta, found {}",
facts.maturity
));
}
if facts.publication.runtime_deployment_claimed {
return Err(
"public status must not claim runtime deployment for the published release".into(),
);
}
if facts.spec.v2_3_present_in_repository {
return Err(
"public status must not claim a v2.3 specification is in the repository".into(),
);
}
Ok(render_html(&facts))
}
fn render_html(facts: &StatusFacts) -> String {
let mut features = String::new();
for feature in &facts.default_off_features {
features.push_str(&format!(
"<li><code>{}</code> / <code>{}</code> — {}</li>",
escape_html(&feature.package),
escape_html(&feature.feature),
escape_html(&feature.boundary)
));
}
let mut capabilities = String::new();
for capability in &facts.bounded_capabilities {
capabilities.push_str(&format!(
"<li><strong>{}.</strong> {}</li>",
escape_html(&capability.name),
escape_html(&capability.posture)
));
}
let deployment = if facts.publication.runtime_deployment_claimed {
"yes"
} else {
"no"
};
let spec_v23 = if facts.spec.v2_3_present_in_repository {
"present"
} else {
"not present"
};
format!(
r#"<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>EXOCHAIN status</title>
<style>{style}</style>
</head>
<body>
<main>
<p class="dim">EXOCHAIN public status</p>
<h1>{maturity}</h1>
<p>{maturity_summary}</p>
<p>Binary version compiled into this page: <code>v{binary_version}</code>.</p>
<h2>Published release</h2>
<p>Reviewed publication snapshot version <code>v{version}</code>, observed <code>{observed_at}</code>. GitHub Release published <code>{github_published_at}</code>: <a href="{github_url}">{github_url}</a>.</p>
<p>Native archives contain {native_archives}. Runtime deployment claimed by that release: <strong>{deployment}</strong>.</p>
<p>PyPI package observed with that version: <code>{pypi_package}</code>. crates.io and npm packages are listed in <code>governance/releases/published-release-snapshot.json</code>.</p>
<h2>Specification</h2>
<p>Normative specification: v{spec_version} (<code>{spec_document}</code>), decided in <code>{authority}</code>. Engineering elaboration: v{engineering_version} (<code>{engineering_document}</code>), subordinate to the normative specification. A v2.3 specification is {spec_v23} in this repository.</p>
<h2>This process</h2>
<p class="dim">The blocks below are the raw same-origin <code>/health</code> and <code>/ready</code> responses. This page does not invent validator counts, peer counts, committed height, uptime percent, or incidents. <code>/ready</code> is the exo-gateway probe and reports <code>CARGO_PKG_VERSION</code>.</p>
<h3>/health</h3>
<pre id="health-probe">Reading /health.</pre>
<h3>/ready</h3>
<pre id="ready-probe">Reading /ready.</pre>
<h2>Default-off boundaries</h2>
<ul>{features}</ul>
<h2>Bounded capabilities</h2>
<ul>{capabilities}</ul>
<h2>Gap ledger</h2>
<p>{gap_note}</p>
<p class="dim"><code>{gap_path}</code> header amended {gap_amended}; that header records {gap_release}.</p>
<p><a href="/">Node dashboard</a> · <a href="/health">/health</a> · <a href="/ready">/ready</a> · <a href="https://github.com/exochain/exochain">GitHub</a></p>
</main>
<script>{script}</script>
</body>
</html>
"#,
maturity = escape_html(&facts.maturity),
maturity_summary = escape_html(&facts.maturity_summary),
binary_version = escape_html(env!("CARGO_PKG_VERSION")),
version = escape_html(&facts.publication.version),
observed_at = escape_html(&facts.publication.observed_at),
github_published_at = escape_html(&facts.publication.github_published_at),
github_url = escape_html(&facts.publication.github_url),
native_archives = escape_html(&facts.publication.native_archive_contents),
deployment = deployment,
pypi_package = escape_html(&facts.publication.pypi_package),
spec_version = escape_html(&facts.spec.normative_version),
spec_document = escape_html(&facts.spec.normative_document),
authority = escape_html(&facts.spec.authority_record),
engineering_version = escape_html(&facts.spec.engineering_version),
engineering_document = escape_html(&facts.spec.engineering_document),
spec_v23 = spec_v23,
features = features,
capabilities = capabilities,
gap_note = escape_html(&facts.gap_registry.note),
gap_path = escape_html(&facts.gap_registry.path),
gap_amended = escape_html(&facts.gap_registry.header_amended),
gap_release = escape_html(&facts.gap_registry.header_records_release),
style = STATUS_STYLE,
script = STATUS_SCRIPT,
)
}
fn escape_html(input: &str) -> String {
let mut out = String::with_capacity(input.len());
for character in input.chars() {
match character {
'&' => out.push_str("&"),
'<' => out.push_str("<"),
'>' => out.push_str(">"),
'"' => out.push_str("""),
'\'' => out.push_str("'"),
_ => out.push(character),
}
}
out
}
#[cfg(test)]
mod tests {
use std::{fs, path::PathBuf};
use axum::{body::Body, http::Request};
use serde_json::Value;
use tower::ServiceExt;
use super::*;
fn facts() -> StatusFacts {
serde_json::from_str(STATUS_FACTS_JSON).expect("status facts parse")
}
#[test]
fn status_facts_match_last_observed_publication_snapshot() {
let parsed = facts();
assert_eq!(parsed.maturity, "beta");
assert!(!parsed.publication.runtime_deployment_claimed);
assert_eq!(parsed.spec.normative_version, "2.2");
assert!(!parsed.spec.v2_3_present_in_repository);
assert!(
parsed
.publication
.native_archive_contents
.contains("libexo_*.rlib")
);
let snapshot_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../governance/releases/published-release-snapshot.json");
let snapshot: Value = serde_json::from_str(
&fs::read_to_string(&snapshot_path).expect("publication snapshot readable"),
)
.expect("publication snapshot parses");
assert_eq!(
snapshot["version"].as_str(),
Some(parsed.publication.version.as_str())
);
assert_eq!(
snapshot["observed_at"].as_str(),
Some(parsed.publication.observed_at.as_str())
);
assert_eq!(snapshot["github"]["draft"].as_bool(), Some(false));
assert_eq!(snapshot["github"]["prerelease"].as_bool(), Some(false));
assert_eq!(
snapshot["github"]["url"].as_str(),
Some(parsed.publication.github_url.as_str())
);
}
#[test]
fn default_off_features_are_absent_from_cargo_defaults() {
let crates = [
("exochain-proofs", "exo-proofs"),
("exochain-node", "exo-node"),
("exochain-gateway", "exo-gateway"),
];
for feature in &facts().default_off_features {
let directory = crates
.iter()
.find(|(package, _)| *package == feature.package)
.map(|(_, directory)| *directory)
.unwrap_or_else(|| panic!("unmapped package {}", feature.package));
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("..")
.join(directory)
.join("Cargo.toml");
let manifest = fs::read_to_string(&path).expect("crate manifest readable");
assert!(
manifest.contains(&format!("{} =", feature.feature)),
"{} missing from {}",
feature.feature,
path.display()
);
let default_line = manifest
.lines()
.find(|line| line.trim_start().starts_with("default ="))
.unwrap_or_else(|| panic!("default feature line missing in {}", path.display()));
assert!(
!default_line.contains(&feature.feature),
"{} is default-on in {}",
feature.feature,
path.display()
);
}
}
#[tokio::test]
async fn status_route_renders_repository_facts_without_fictional_metrics() {
let app = public_status_router();
let response = app
.oneshot(
Request::builder()
.uri("/status")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), 200);
let body = axum::body::to_bytes(response.into_body(), 1 << 20)
.await
.unwrap();
let html = std::str::from_utf8(&body).unwrap();
assert!(html.contains("beta"));
assert!(html.contains(env!("CARGO_PKG_VERSION")));
assert!(html.contains("not general availability"));
assert!(html.contains("libexo_*.rlib"));
assert!(html.contains("Runtime deployment claimed by that release"));
assert!(html.contains("textContent"));
assert!(html.contains("AbortController"));
assert!(html.contains(&format!("<style>{STATUS_STYLE}</style>")));
assert!(html.contains(&format!("<script>{STATUS_SCRIPT}</script>")));
assert!(html.contains(&format!(
"Binary version compiled into this page: <code>v{}</code>",
env!("CARGO_PKG_VERSION")
)));
assert!(html.contains(&format!(
"Reviewed publication snapshot version <code>v{}</code>",
facts().publication.version
)));
assert!(!html.contains("innerHTML"));
assert!(!html.contains("v0.4.2"));
assert!(!html.contains("alpha-testnet"));
assert!(!html.contains("99.86"));
assert!(html.contains("id=\"health-probe\""));
assert!(html.contains("id=\"ready-probe\""));
let packaged_facts =
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("src/public-status.json");
assert!(
packaged_facts.is_file(),
"status facts must live inside the exochain-node package"
);
}
}