Skip to content

Commit 7a419b2

Browse files
skullcmdclaude
andcommitted
feat(public): unified policy page with sub-tabs (scanning + data + identity)
Extracted #scanning-policy, #scanner-identity, #data-policy from public-site.html into a single templates/public/policy.html with path-driven sub-tab activation. Routes /scanning-policy, /scanner-identity, /data-policy now serve this page; the active sub-tab is determined by the request path (JS reads window.location.pathname; falls back to direct linking if JS disabled). Test: public_policy_routes_serve_policy_content (GETs each path, asserts 200 + all three section ids present). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ef60f6f commit 7a419b2

2 files changed

Lines changed: 440 additions & 3 deletions

File tree

src/bin/anyscan-api.rs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,12 +417,12 @@ async fn main() -> Result<()> {
417417
.route("/", get(public_index))
418418
.route("/app", get(operator_app))
419419
.route("/app/overview", get(operator_pages::operator_overview))
420-
.route("/scanning-policy", get(public_page))
421-
.route("/scanner-identity", get(public_page))
420+
.route("/scanning-policy", get(public_policy))
421+
.route("/scanner-identity", get(public_policy))
422422
.route("/opt-out", get(public_page))
423423
.route("/claim", get(public_page))
424424
.route("/abuse", get(public_page))
425-
.route("/data-policy", get(public_page))
425+
.route("/data-policy", get(public_policy))
426426
.route("/.well-known/security.txt", get(security_txt))
427427
.route("/api/public/profile", get(public_profile))
428428
.route("/api/public/findings", get(list_public_findings))
@@ -604,6 +604,10 @@ async fn public_page() -> Html<&'static str> {
604604
Html(include_str!("../../public-site.html"))
605605
}
606606

607+
async fn public_policy() -> Html<&'static str> {
608+
Html(include_str!("../../templates/public/policy.html"))
609+
}
610+
607611
async fn enforce_worker_only_host_routes(
608612
State(state): State<Arc<AppState>>,
609613
request: Request,
@@ -4483,4 +4487,50 @@ mod tests {
44834487
assert!(resolved.request_opt_in_enabled);
44844488
assert!(resolved.is_enabled());
44854489
}
4490+
4491+
#[tokio::test]
4492+
async fn public_policy_routes_serve_policy_content() {
4493+
let app = Router::new()
4494+
.route("/scanning-policy", get(public_policy))
4495+
.route("/scanner-identity", get(public_policy))
4496+
.route("/data-policy", get(public_policy));
4497+
4498+
let listener = TcpListener::bind("127.0.0.1:0")
4499+
.await
4500+
.expect("bind ephemeral port");
4501+
let addr = listener.local_addr().expect("local addr");
4502+
let server = tokio::spawn(async move {
4503+
axum::serve(listener, app).await.expect("serve policy app");
4504+
});
4505+
4506+
let client = reqwest::Client::new();
4507+
for path in ["/scanning-policy", "/scanner-identity", "/data-policy"] {
4508+
let url = format!("http://{}{}", addr, path);
4509+
let response = client.get(&url).send().await.expect("send request");
4510+
assert_eq!(
4511+
response.status(),
4512+
reqwest::StatusCode::OK,
4513+
"{} should return 200",
4514+
path
4515+
);
4516+
let body = response.text().await.expect("read body");
4517+
assert!(
4518+
body.contains(r#"id="scanning-policy""#),
4519+
"{} body missing scanning-policy section",
4520+
path
4521+
);
4522+
assert!(
4523+
body.contains(r#"id="scanner-identity""#),
4524+
"{} body missing scanner-identity section",
4525+
path
4526+
);
4527+
assert!(
4528+
body.contains(r#"id="data-policy""#),
4529+
"{} body missing data-policy section",
4530+
path
4531+
);
4532+
}
4533+
4534+
server.abort();
4535+
}
44864536
}

0 commit comments

Comments
 (0)