docs+portal: expose product evolution and architecture
This commit is contained in:
@@ -24,6 +24,7 @@ use sha2::{Digest, Sha256};
|
||||
use tiny_http::{Header, Method, Request, Response, Server, StatusCode};
|
||||
|
||||
const INDEX_HTML: &str = include_str!("static/index.html");
|
||||
const ARCHITECTURE_HTML: &str = include_str!("static/architecture.html");
|
||||
const APP_CSS: &str = include_str!("static/app.css");
|
||||
const APP_JS: &str = include_str!("static/app.js");
|
||||
const API_CONTRACT_OPENAPI: &str = include_str!("contracts/openapi.json");
|
||||
@@ -1372,13 +1373,10 @@ fn handle_request(request: Request, args: &Cli, snapshot_cache: &SnapshotCache)
|
||||
if let Some((evidence_id, download)) = parse_evidence_screenshot_path(&path) {
|
||||
return handle_evidence_screenshot(request, args, &evidence_id, download);
|
||||
}
|
||||
if let Some(html) = portal_html_route(&path) {
|
||||
return respond_text(request, StatusCode(200), html, "text/html; charset=utf-8");
|
||||
}
|
||||
match path.as_str() {
|
||||
"/" | "/operator" | "/manager" | "/owner" | "/incidents" | "/reports" => respond_text(
|
||||
request,
|
||||
StatusCode(200),
|
||||
INDEX_HTML,
|
||||
"text/html; charset=utf-8",
|
||||
),
|
||||
"/app.css" => respond_text(request, StatusCode(200), APP_CSS, "text/css; charset=utf-8"),
|
||||
"/app.js" => respond_text(
|
||||
request,
|
||||
@@ -1506,6 +1504,14 @@ fn handle_request(request: Request, args: &Cli, snapshot_cache: &SnapshotCache)
|
||||
}
|
||||
}
|
||||
|
||||
fn portal_html_route(path: &str) -> Option<&'static str> {
|
||||
match path {
|
||||
"/" | "/operator" | "/manager" | "/owner" | "/incidents" | "/reports" => Some(INDEX_HTML),
|
||||
"/architecture" => Some(ARCHITECTURE_HTML),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_evidence_only_request(request: Request, args: &Cli) -> Result<()> {
|
||||
let method = request.method().clone();
|
||||
let path = normalize_path(request.url());
|
||||
@@ -9961,6 +9967,7 @@ mod tests {
|
||||
fn normalizes_gateway_prefix() {
|
||||
assert_eq!(normalize_path("/portal/api/health?x=1"), "/api/health");
|
||||
assert_eq!(normalize_path("/portal/"), "/");
|
||||
assert_eq!(normalize_path("/portal/architecture"), "/architecture");
|
||||
assert_eq!(normalize_path("/api/health"), "/api/health");
|
||||
assert!(query_flag("/api/reports?anonymize=1", "anonymize"));
|
||||
assert!(query_flag("/api/reports?anonymize=true", "anonymize"));
|
||||
@@ -9976,6 +9983,23 @@ mod tests {
|
||||
assert_eq!(safe_download_stem("risk:candidate/1"), "risk_candidate_1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn portal_architecture_page_is_informational_and_status_labeled() {
|
||||
assert!(portal_html_route("/architecture").is_some());
|
||||
let body = portal_html_route("/architecture").unwrap();
|
||||
for marker in [
|
||||
"Rust Agent",
|
||||
"PowerShell Provider",
|
||||
"implemented",
|
||||
"planned",
|
||||
"future",
|
||||
"contract_only",
|
||||
"Страница является информационной",
|
||||
] {
|
||||
assert!(body.contains(marker), "architecture page missing {marker}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn api_contract_artifacts_are_valid_and_future_ui_ready() {
|
||||
let openapi: Value =
|
||||
|
||||
@@ -243,6 +243,63 @@ h1 {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border: 1px solid transparent;
|
||||
background: transparent;
|
||||
color: #cbd5e1;
|
||||
border-radius: 8px;
|
||||
padding: 11px 12px;
|
||||
font: inherit;
|
||||
font-weight: 700;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-link:hover,
|
||||
.nav-link.is-active {
|
||||
background: rgba(148, 163, 184, 0.14);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.architecture-page .topbar {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.architecture-content {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.architecture-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.architecture-grid article {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
align-content: start;
|
||||
min-height: 150px;
|
||||
padding: 14px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: var(--soft);
|
||||
}
|
||||
|
||||
.architecture-grid strong {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.architecture-grid p {
|
||||
margin: 0;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<!doctype html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AWatch-rus Product Architecture</title>
|
||||
<link rel="stylesheet" href="/portal/app.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar" aria-label="Основная навигация">
|
||||
<div class="sidebar-brand">
|
||||
<strong>AWatch-rus</strong>
|
||||
<span>Архитектура продукта</span>
|
||||
</div>
|
||||
<nav class="tabs">
|
||||
<a class="nav-link" href="/portal/">Портал</a>
|
||||
<a class="nav-link is-active" href="/portal/architecture">Архитектура</a>
|
||||
</nav>
|
||||
</aside>
|
||||
<main class="shell architecture-page">
|
||||
<header class="topbar">
|
||||
<div class="brand">
|
||||
<p class="eyebrow">AWatch-rus</p>
|
||||
<h1>Product Architecture</h1>
|
||||
<p class="lead">Текущие компоненты, предусмотренные расширения и будущие направления без заявления фиктивных collectors.</p>
|
||||
</div>
|
||||
<div class="topbar-side">
|
||||
<a class="small-button" href="/portal/">Вернуться в портал</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="content-panel architecture-content" aria-label="Архитектура продукта">
|
||||
<section class="card">
|
||||
<h2>Current Components</h2>
|
||||
<p>Эти элементы относятся к текущему рабочему контуру AWatch-rus.</p>
|
||||
<div class="architecture-grid">
|
||||
<article><span class="status-pill status-ok">implemented</span><strong>Backend</strong><p>Rust-first серверные helpers, report layer и portal runtime.</p></article>
|
||||
<article><span class="status-pill status-ok">implemented</span><strong>Portal</strong><p>Rust server-rendered HTML + HTMX-compatible JSON API.</p></article>
|
||||
<article><span class="status-pill status-ok">implemented</span><strong>Rust Agent</strong><p>Агентский Rust runtime и Windows telemetry paths в текущей parity-модели.</p></article>
|
||||
<article><span class="status-pill status-ok">implemented</span><strong>Reports</strong><p>Workforce, Security и Forensics отчеты, включая Markdown export.</p></article>
|
||||
<article><span class="status-pill status-ok">implemented</span><strong>UEBA v1</strong><p>Прозрачная rule-based модель без ML, LLM и внешних SaaS.</p></article>
|
||||
<article><span class="status-pill status-ok">implemented</span><strong>Forensics</strong><p>Карточки расследований, timeline и evidence package.</p></article>
|
||||
<article><span class="status-pill status-ok">implemented</span><strong>Role gates</strong><p>Серверные проверки доступа для Pilot v1 ролей.</p></article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>Planned Extensions</h2>
|
||||
<p>Эти направления предусмотрены архитектурой, но не являются готовой функциональностью без отдельной реализации и тестов.</p>
|
||||
<div class="architecture-grid">
|
||||
<article><span class="status-pill status-warn">planned</span><strong>PowerShell Provider</strong><p>Agentless/legacy Windows source после формализации provider contract.</p></article>
|
||||
<article><span class="status-pill status-warn">planned</span><strong>SSH Provider</strong><p>Read-only probes и existing logs для Linux/Unix/network hosts.</p></article>
|
||||
<article><span class="status-pill status-warn">planned</span><strong>Syslog Provider</strong><p>Нормализация событий от внешних log sources.</p></article>
|
||||
<article><span class="status-pill status-warn">planned</span><strong>1C Provider</strong><p>Расширение текущего file-based 1C analytics сценария до формального provider.</p></article>
|
||||
<article><span class="status-pill status-unknown">contract_only</span><strong>pfSense Provider</strong><p>Readiness contracts и demo fixture без заявления production ingestion.</p></article>
|
||||
<article><span class="status-pill status-warn">planned</span><strong>Russian OS validation</strong><p>Astra Linux, РЕД ОС, Альт и РОСА требуют distro-specific smoke и compatibility matrix.</p></article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>Future</h2>
|
||||
<p>Эти элементы являются будущими направлениями, а не частью текущего Pilot v1.</p>
|
||||
<div class="architecture-grid">
|
||||
<article><span class="status-pill status-unknown">future</span><strong>SCUD Provider</strong><p>Сопоставление с физическим доступом после отдельного vendor/source contract.</p></article>
|
||||
<article><span class="status-pill status-unknown">future</span><strong>VPN Provider</strong><p>Сетевой контекст для расследований после отдельной реализации.</p></article>
|
||||
<article><span class="status-pill status-unknown">future</span><strong>React/TypeScript Enterprise UI</strong><p>Будущий enterprise UI, не текущий основной portal UI.</p></article>
|
||||
<article><span class="status-pill status-unknown">future</span><strong>Tauri Desktop Forensics</strong><p>Отдельный desktop-контур для forensic workflows.</p></article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>Граница заявления</h2>
|
||||
<p>Страница является информационной. Она не добавляет backend API, collectors или ingestion. Planned и future элементы не считаются implemented.</p>
|
||||
</section>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -22,6 +22,7 @@
|
||||
<button class="tab" data-tab="perimeter">Сетевой периметр</button>
|
||||
<button class="tab" data-tab="reports">Отчеты</button>
|
||||
<button class="tab" data-tab="settings">Настройки</button>
|
||||
<a class="nav-link" href="/portal/architecture">Архитектура</a>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user