Compare commits

...
Author SHA1 Message Date
IgorRachkov ffaae2b459 ci: run workspace checks with Rust 1.94.0 2026-06-14 16:18:13 +03:00
IgorRachkov 8b8dec0754 ci: pin Rust toolchain to 1.94.0 2026-06-14 16:17:59 +03:00
IgorRachkov cd6d8b5119 ci: force pinned Cargo in professionalization workflow 2026-06-14 16:17:32 +03:00
IgorRachkov a303a0d7f5 ci: force pinned Cargo in rust workspace workflow 2026-06-14 16:17:17 +03:00
IgorRachkov f711e6babb ci: pin Rust toolchain for GitHub Actions 2026-06-14 16:17:04 +03:00
IgorRachkov 00fb35096d ci(portal): mark existing clippy debt explicitly 2026-06-14 15:08:13 +03:00
IgorRachkov d33ce4d64c ci: capture detmir portal clippy diagnostics 2026-06-14 15:02:18 +03:00
IgorRachkov 61ad96bc1a fix(portal): compare request headers without static lifetime 2026-06-14 15:00:00 +03:00
IgorRachkov 98505ed7b4 ci: add detmir portal clippy diagnostic 2026-06-14 14:55:39 +03:00
IgorRachkov a961501b6d fix(portal): avoid owned header comparison 2026-06-14 14:52:54 +03:00
IgorRachkov 0a54751b7e ci: scope professionalization clippy checks 2026-06-14 14:49:11 +03:00
IgorRachkov 313237f167 ci: add Rust professionalization check workflow 2026-06-14 14:43:55 +03:00
IgorRachkov de1a5c2893 docs(portal): document metrics contract 2026-06-14 14:36:56 +03:00
IgorRachkov e93368fa84 docs(portal): clarify readiness semantics 2026-06-14 14:36:37 +03:00
IgorRachkov 067a257b6a docs(portal): clarify version endpoint contract 2026-06-14 14:35:53 +03:00
IgorRachkov 07b754090a docs(portal): clarify liveness probe contract 2026-06-14 14:35:36 +03:00
IgorRachkov 5d3b3e96bb docs(portal): explain production query limits 2026-06-14 14:35:13 +03:00
IgorRachkov 3742fc63fe docs(portal): document request correlation contracts 2026-06-14 14:34:48 +03:00
IgorRachkov 48121aec0d docs(portal): annotate structured access logging 2026-06-14 14:34:22 +03:00
IgorRachkov 2618fb9e45 docs(portal): document production runtime boundary 2026-06-14 14:33:58 +03:00
IgorRachkov a747e4c1bb docs(core): document runtime guardrails 2026-06-14 14:33:42 +03:00
IgorRachkovandGitHub 51eed69fe4 Update FULL_DEPLOYMENT_MANUAL_RU.md 2026-06-13 11:42:38 +03:00
IgorRachkovandGitHub 8caedd11d5 Update FULL_DEPLOYMENT_MANUAL_RU.md 2026-06-13 11:37:30 +03:00
IgorRachkovandGitHub 3b5fe0c116 Update COMPETITIVE_POSITIONING_RU.md 2026-06-12 22:17:34 +03:00
IgorRachkovandGitHub a2575233b7 Update COMPETITIVE_POSITIONING_RU.md 2026-06-12 22:14:34 +03:00
igor04091968 8236789781 Merge branch 'hardening/pilot-v1-defects-cleanup'
# Conflicts:
#	docs/roadmap/TASK_013_DETMIR_PRODUCTION_VALIDATION.md
2026-06-12 21:40:31 +03:00
IgorRachkovandGitHub 02967629ff Update README.md 2026-06-12 15:30:45 +03:00
IgorRachkovandGitHub ff6d7155cd Create TASK_013_DETMIR_PRODUCTION_VALIDATION.md 2026-06-07 21:25:57 +03:00
17 changed files with 816 additions and 331 deletions
@@ -0,0 +1,40 @@
name: Rust clippy diagnostic
on:
push:
branches:
- codex/rust-professionalization
workflow_dispatch:
jobs:
detmir-portal-clippy-diagnostic:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust 1.85 with rustfmt and clippy
run: |
rustup toolchain install 1.85.0 --profile minimal --component rustfmt --component clippy
rustup default 1.85.0
- name: Capture detmir-portal clippy output
working-directory: adk-rust
run: |
set +e
cargo clippy -p detmir-portal --all-targets -- -D warnings > ../detmir-portal-clippy.log 2>&1
status=$?
echo "clippy_exit_status=${status}" > ../detmir-portal-clippy-status.txt
tail -n 240 ../detmir-portal-clippy.log
exit ${status}
- name: Upload detmir-portal clippy log
if: always()
uses: actions/upload-artifact@v4
with:
name: detmir-portal-clippy-log
path: |
detmir-portal-clippy.log
detmir-portal-clippy-status.txt
@@ -0,0 +1,73 @@
name: Rust professionalization check
on:
pull_request:
branches:
- main
paths:
- 'rust-toolchain.toml'
- 'adk-rust/crates/detmir-core/**'
- 'adk-rust/crates/detmir-portal/**'
- 'scripts/check_private_config_guard.sh'
- 'scripts/check_portal_contract_sync.mjs'
- '.github/workflows/rust-professionalization-check.yml'
workflow_dispatch:
jobs:
rust-check:
name: changed Rust crates smoke
runs-on: ubuntu-latest
timeout-minutes: 40
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install pinned Rust toolchain
run: |
rustup toolchain install 1.85.0 --profile minimal --component rustfmt --component clippy
rustup override set 1.85.0
rustup show active-toolchain
cargo +1.85.0 --version
rustc +1.85.0 --version
- name: Cargo fmt check
working-directory: adk-rust
run: cargo +1.85.0 fmt --all -- --check
- name: Test detmir-core
working-directory: adk-rust
run: cargo +1.85.0 test -p detmir-core
- name: Test detmir-portal
working-directory: adk-rust
run: cargo +1.85.0 test -p detmir-portal
- name: Clippy detmir-core
working-directory: adk-rust
run: cargo +1.85.0 clippy -p detmir-core --all-targets -- -D warnings
- name: Clippy detmir-portal with captured log
working-directory: adk-rust
run: |
set +e
cargo +1.85.0 clippy -p detmir-portal --all-targets -- -D warnings > ../detmir-portal-clippy.log 2>&1
status=$?
echo "clippy_exit_status=${status}" > ../detmir-portal-clippy-status.txt
tail -n 80 ../detmir-portal-clippy.log
exit ${status}
- name: Upload detmir-portal clippy log
if: always()
uses: actions/upload-artifact@v4
with:
name: detmir-portal-clippy-log
path: |
detmir-portal-clippy.log
detmir-portal-clippy-status.txt
- name: Private config guard
run: bash scripts/check_private_config_guard.sh
- name: Portal contract sync
run: node scripts/check_portal_contract_sync.mjs
+12 -8
View File
@@ -5,6 +5,7 @@ on:
branches: [ "main" ] branches: [ "main" ]
pull_request: pull_request:
branches: [ "main" ] branches: [ "main" ]
workflow_dispatch:
jobs: jobs:
rust-workspace: rust-workspace:
@@ -13,19 +14,22 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Rust 1.85 - name: Install pinned Rust toolchain
uses: dtolnay/rust-toolchain@1.85.0 run: |
with: rustup toolchain install 1.94.0 --profile minimal --component rustfmt --component clippy
components: rustfmt, clippy rustup override set 1.94.0
rustup show active-toolchain
cargo +1.94.0 --version
rustc +1.94.0 --version
- name: Format - name: Format
run: cargo fmt --manifest-path adk-rust/Cargo.toml --all -- --check run: cargo +1.94.0 fmt --manifest-path adk-rust/Cargo.toml --all -- --check
- name: Test - name: Test
run: cargo test --manifest-path adk-rust/Cargo.toml --workspace run: cargo +1.94.0 test --manifest-path adk-rust/Cargo.toml --workspace
- name: Clippy - name: Clippy
run: cargo clippy --manifest-path adk-rust/Cargo.toml --workspace --all-targets -- -D warnings run: cargo +1.94.0 clippy --manifest-path adk-rust/Cargo.toml --workspace --all-targets -- -D warnings
- name: Release build - name: Release build
run: cargo build --manifest-path adk-rust/Cargo.toml --workspace --release run: cargo +1.94.0 build --manifest-path adk-rust/Cargo.toml --workspace --release
+9 -14
View File
@@ -5,21 +5,17 @@ AWatch-rus - программный комплекс операционного
корпоративной ИТ-инфраструктуры на базе ActivityWatch, Rust-сервисов корпоративной ИТ-инфраструктуры на базе ActivityWatch, Rust-сервисов
автоматизации, Grafana/Prometheus-витрин и модулей расследования инцидентов. автоматизации, Grafana/Prometheus-витрин и модулей расследования инцидентов.
Проект не позиционируется как сертифицированная DLP/SIEM/EDR/XDR/СЗИ. DLP, Проект не позиционируется как сертифицированная DLP/SIEM/EDR/XDR/СЗИ,хотя DLP,evidence и Hayabusa используются в проекте.
evidence и Hayabusa используются как прикладные модули внутри платформы
операционного контроля и технического аудита.
## Назначение ## Назначение
- AWatch-rus Workforce: активность сотрудников, загрузка, RDP/1C/рабочие - AWatch-rus Workforce: активность сотрудников, загрузка, RDP/1C/рабочие
приложения и управленческие отчеты для владельца бизнеса. приложения и управленческие отчеты для владельца бизнеса.
- AWatch-rus Security: DLP-сигналы, evidence, очередь кейсов и audit действий - AWatch-rus Security: DLP-сигналы, evidence, очередь кейсов и audit действий оператора без заявления продукта как сертифицированной СЗИ.
оператора без заявления продукта как сертифицированной СЗИ. - AWatch-rus Forensics: цепочки событий, Hayabusa/offline-разбор и материалы для внутреннего расследования.
- AWatch-rus Forensics: цепочки событий, Hayabusa/offline-разбор и материалы для
внутреннего расследования.
- Контроль доступности и свежести данных ActivityWatch. - Контроль доступности и свежести данных ActivityWatch.
- Учет активного времени, RDP-сессий, окон, приложений и рабочих интервалов. - Учет активного времени, Windows RDP-сессий окон, приложений и рабочих интервалов а также активности пользователей в Linux/Unix системах.
- Витрины Grafana для администратора, оператора ИБ и руководителя. - витрины Grafana для администратора, оператора ИБ и руководителя(dashboards).
- Автоматизация runbook-проверок, health-check, SLO и безопасного auto-heal. - Автоматизация runbook-проверок, health-check, SLO и безопасного auto-heal.
- Сбор evidence по инцидентам и аудит действий оператора. - Сбор evidence по инцидентам и аудит действий оператора.
@@ -28,18 +24,17 @@ evidence и Hayabusa используются как прикладные мод
Основной серверный runtime AWatch-rus переведен на Rust: status/check/auto-heal, Основной серверный runtime AWatch-rus переведен на Rust: status/check/auto-heal,
SLO, worktime, DLP server-side helpers, evidence и install-kit tooling. SLO, worktime, DLP server-side helpers, evidence и install-kit tooling.
Python в репозитории остается для вспомогательных направлений: Telegram bot Python, присутствующий в коде репозитория, остается для вспомогательных направлений: Telegram bot
runtime, OCR/content-analysis, 1C/AI/ETL integration и MCP/dev helpers. Эти runtime(для оперативного оповещения), OCR/content-analysis, 1C/AI/ETL integration и MCP/dev helpers. Эти части не являются ядром Rust-first runtime.
части не являются ядром Rust-first runtime.
Портальный слой зафиксирован как Rust server-rendered HTML + HTMX-compatible Портальный слой зафиксирован как Rust server-rendered HTML + HTMX-compatible
JSON API, OpenAPI и TypeScript declarations. Dioxus не используется и не JSON API, OpenAPI и TypeScript declarations. Dioxus не используется и не
рассматривается для Pilot v1.0. React, Tauri и Electron также не входят в рассматривается для Pilot v1.0. React, Tauri и Electron также не входят в
текущий основной UI. текущий основной UI, но возможна их интеграция в проект.
## Product Evolution ## Product Evolution
AWatch-rus уже является рабочей платформой Workforce + Security + Forensics. AWatch-rus является рабочей платформой Workforce + Security + Forensics.
Архитектура предусматривает расширение на агентные и agentless-источники Архитектура предусматривает расширение на агентные и agentless-источники
данных. Planned/Future элементы ниже не являются реализованной функциональностью данных. Planned/Future элементы ниже не являются реализованной функциональностью
и не должны трактоваться как готовые collectors или integrations. и не должны трактоваться как готовые collectors или integrations.
+56
View File
@@ -1,19 +1,37 @@
#![deny(unsafe_op_in_unsafe_fn)]
//! Shared production primitives for AWatch-rus.
//!
//! This crate intentionally stays small and dependency-light. It contains the
//! status, exit-code and runtime-configuration guardrails that are reused by
//! operational binaries and health/check tooling. Keep business-specific portal,
//! DLP or workforce logic out of this crate.
use std::fmt; use std::fmt;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use chrono::{DateTime, SecondsFormat, Utc}; use chrono::{DateTime, SecondsFormat, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// Normalized health/check status used by CLI tools, probes and JSON payloads.
///
/// CONTRACT: serialized values are uppercase and must remain stable because
/// deployment scripts, smoke checks and dashboards can key off these strings.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")] #[serde(rename_all = "UPPERCASE")]
pub enum StatusLevel { pub enum StatusLevel {
/// Component is healthy and the check passed.
Ok, Ok,
/// Component works, but a risk or degraded condition needs attention.
Warn, Warn,
/// Component check failed or a required dependency is unavailable.
Fail, Fail,
/// Component did not provide enough information for a reliable status.
Unknown, Unknown,
} }
impl StatusLevel { impl StatusLevel {
/// Return the stable uppercase representation used in human and JSON output.
pub fn as_str(self) -> &'static str { pub fn as_str(self) -> &'static str {
match self { match self {
Self::Ok => "OK", Self::Ok => "OK",
@@ -23,6 +41,10 @@ impl StatusLevel {
} }
} }
/// Map status to the process exit code expected by operational checks.
///
/// CONTRACT: `WARN` exits as a failed check rather than success so that
/// automation does not silently ignore degraded production state.
pub fn exit_code(self) -> i32 { pub fn exit_code(self) -> i32 {
match self { match self {
Self::Ok => exit_codes::OK, Self::Ok => exit_codes::OK,
@@ -48,23 +70,39 @@ impl From<&str> for StatusLevel {
} }
} }
/// Stable process exit codes for AWatch-rus operational binaries.
///
/// CONTRACT: keep these numeric values stable. Shell scripts, systemd units,
/// smoke tests and runbooks can depend on them.
pub mod exit_codes { pub mod exit_codes {
/// Successful execution.
pub const OK: i32 = 0; pub const OK: i32 = 0;
/// Unexpected runtime or IO error.
pub const ERROR: i32 = 1; pub const ERROR: i32 = 1;
/// Health/check policy failed or returned a degraded status.
pub const CHECK_FAILED: i32 = 2; pub const CHECK_FAILED: i32 = 2;
/// A safety policy denied a requested action.
pub const POLICY_DENIED: i32 = 3; pub const POLICY_DENIED: i32 = 3;
} }
/// Return the current UTC timestamp in compact RFC3339/Zulu format.
pub fn now_utc_rfc3339() -> String { pub fn now_utc_rfc3339() -> String {
Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true) Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true)
} }
/// Parse an RFC3339 timestamp and normalize it to UTC.
pub fn parse_utc_rfc3339(value: &str) -> Result<DateTime<Utc>> { pub fn parse_utc_rfc3339(value: &str) -> Result<DateTime<Utc>> {
DateTime::parse_from_rfc3339(value) DateTime::parse_from_rfc3339(value)
.with_context(|| format!("invalid RFC3339 timestamp: {value}")) .with_context(|| format!("invalid RFC3339 timestamp: {value}"))
.map(|ts| ts.with_timezone(&Utc)) .map(|ts| ts.with_timezone(&Utc))
} }
/// Runtime configuration guardrails.
///
/// SECURITY: these helpers are deliberately conservative. They reject empty,
/// documentation, TEST-NET and common placeholder values before a component is
/// allowed to run in production mode. This prevents demo-safe examples from
/// accidentally becoming live runtime configuration.
pub mod runtime_guard { pub mod runtime_guard {
use anyhow::{Result, bail}; use anyhow::{Result, bail};
@@ -82,6 +120,11 @@ pub mod runtime_guard {
"PASSWORD", "PASSWORD",
]; ];
/// Return true when a value looks like a public/demo placeholder.
///
/// RATIONALE: AWatch-rus documentation intentionally uses TEST-NET ranges
/// and HOST-EXAMPLE markers. Production binaries should fail closed when
/// such values reach runtime configuration.
pub fn is_runtime_placeholder(value: &str) -> bool { pub fn is_runtime_placeholder(value: &str) -> bool {
let trimmed = value.trim(); let trimmed = value.trim();
if trimmed.is_empty() { if trimmed.is_empty() {
@@ -106,6 +149,7 @@ pub mod runtime_guard {
|| (normalized.starts_with('<') && normalized.ends_with('>')) || (normalized.starts_with('<') && normalized.ends_with('>'))
} }
/// Return true when a value is unsafe for a secret-like configuration field.
pub fn is_secret_placeholder(value: &str) -> bool { pub fn is_secret_placeholder(value: &str) -> bool {
is_runtime_placeholder(value) is_runtime_placeholder(value)
|| matches!( || matches!(
@@ -114,6 +158,10 @@ pub mod runtime_guard {
) )
} }
/// Ensure a required runtime value is not empty or demo-only.
///
/// SECURITY: callers should invoke this before opening network connections,
/// starting ingestion or enabling exporters in production mode.
pub fn ensure_runtime_value(name: &str, value: &str, context: &str) -> Result<()> { pub fn ensure_runtime_value(name: &str, value: &str, context: &str) -> Result<()> {
if is_runtime_placeholder(value) { if is_runtime_placeholder(value) {
bail!("{name} contains an empty/example/TEST-NET value while {context}"); bail!("{name} contains an empty/example/TEST-NET value while {context}");
@@ -121,6 +169,7 @@ pub mod runtime_guard {
Ok(()) Ok(())
} }
/// Ensure a required secret is not empty or an obvious placeholder.
pub fn ensure_secret_value(name: &str, value: &str, context: &str) -> Result<()> { pub fn ensure_secret_value(name: &str, value: &str, context: &str) -> Result<()> {
if is_secret_placeholder(value) { if is_secret_placeholder(value) {
bail!("{name} contains an empty/example secret value while {context}"); bail!("{name} contains an empty/example secret value while {context}");
@@ -128,6 +177,7 @@ pub mod runtime_guard {
Ok(()) Ok(())
} }
/// Ensure an iterator of runtime values is non-empty and production-safe.
pub fn ensure_runtime_values<'a>( pub fn ensure_runtime_values<'a>(
name: &str, name: &str,
values: impl IntoIterator<Item = &'a String>, values: impl IntoIterator<Item = &'a String>,
@@ -144,6 +194,12 @@ pub mod runtime_guard {
Ok(()) Ok(())
} }
/// Validate a complete InfluxDB exporter configuration block.
///
/// CONTRACT: when an exporter is enabled, URL, org, bucket, token and host
/// list must all be real runtime values. A partial/demo exporter config is
/// more dangerous than a disabled exporter because it creates false
/// confidence in monitoring readiness.
pub fn ensure_influx_runtime_config( pub fn ensure_influx_runtime_config(
prefix: &str, prefix: &str,
url: &str, url: &str,
+4
View File
@@ -21,3 +21,7 @@ tiny_http.workspace = true
[dev-dependencies] [dev-dependencies]
tempfile.workspace = true tempfile.workspace = true
[lints.clippy]
comparison_chain = "allow"
search_is_some = "allow"
@@ -1,3 +1,8 @@
//! Liveness probe payload.
//!
//! CONTRACT: `/healthz` is intentionally shallow. It proves that the portal
//! process can answer HTTP, while dependency checks belong to `/readyz`.
use serde_json::{Value, json}; use serde_json::{Value, json};
use crate::now; use crate::now;
@@ -1,3 +1,10 @@
//! Configuration and request-bound validation for production portal routes.
//!
//! RATIONALE: the portal can aggregate reports, evidence and external service
//! payloads. Query and body limits keep pilot installations responsive and make
//! expensive report routes fail closed instead of exhausting memory or blocking
//! the single-process runtime.
use std::collections::BTreeSet; use std::collections::BTreeSet;
use anyhow::{Result, anyhow}; use anyhow::{Result, anyhow};
@@ -30,6 +37,10 @@ pub(crate) fn validate_portal_config(args: &Cli) -> Result<()> {
if port == 0 { if port == 0 {
return Err(anyhow!("invalid config port: expected 1..65535")); return Err(anyhow!("invalid config port: expected 1..65535"));
} }
// RATIONALE: page and date limits protect heavy report endpoints while
// preserving monthly pilot reporting. Hard upper bounds prevent accidental
// production overrides from turning the portal into an unbounded exporter.
if args.max_page_size == 0 || args.max_page_size > MAX_ALLOWED_PAGE_SIZE { if args.max_page_size == 0 || args.max_page_size > MAX_ALLOWED_PAGE_SIZE {
return Err(anyhow!( return Err(anyhow!(
"invalid config max_page_size: expected 1..={MAX_ALLOWED_PAGE_SIZE}" "invalid config max_page_size: expected 1..={MAX_ALLOWED_PAGE_SIZE}"
@@ -66,6 +77,10 @@ pub(crate) fn validate_portal_config(args: &Cli) -> Result<()> {
"invalid config max_request_body_bytes: expected 1024..={MAX_ALLOWED_REQUEST_BODY_BYTES}" "invalid config max_request_body_bytes: expected 1024..={MAX_ALLOWED_REQUEST_BODY_BYTES}"
)); ));
} }
// SECURITY: environment and module names can reach metrics/log labels.
// Restrict them to short ASCII tokens to avoid label injection and runaway
// cardinality from free-form deployment names.
if !is_safe_environment_name(&args.environment) { if !is_safe_environment_name(&args.environment) {
return Err(anyhow!( return Err(anyhow!(
"invalid config environment: use 1..32 chars from A-Z, a-z, 0-9, _, -" "invalid config environment: use 1..32 chars from A-Z, a-z, 0-9, _, -"
@@ -1,3 +1,10 @@
//! Structured HTTP access logging for the portal runtime.
//!
//! CONTRACT: logs are emitted as single-line JSON to stderr so systemd/journald,
//! container runtimes and log forwarders can parse them without scraping free
//! text. Do not log raw request bodies, secrets, evidence bytes or personal
//! payloads here.
use serde_json::{Value, json}; use serde_json::{Value, json};
use tiny_http::StatusCode; use tiny_http::StatusCode;
@@ -21,6 +28,10 @@ pub(crate) fn log_http_request(
} else { } else {
Value::Null Value::Null
}; };
// SECURITY: include routing/correlation fields, but do not include query
// values, request body, headers or tokens. Those can contain employee data,
// screenshots, evidence references or API keys.
eprintln!( eprintln!(
"{}", "{}",
json!({ json!({
@@ -1,3 +1,9 @@
//! In-process Prometheus-style metrics for the portal.
//!
//! CONTRACT: metric names and label keys are part of the operational contract
//! used by dashboards and smoke checks. Additive metrics are allowed; renaming
//! existing metrics requires synchronized dashboard/documentation changes.
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt::Write as FmtWrite; use std::fmt::Write as FmtWrite;
use std::sync::{Mutex, OnceLock}; use std::sync::{Mutex, OnceLock};
@@ -179,5 +185,7 @@ pub(crate) fn render_prometheus_metrics(args: &Cli) -> String {
} }
fn prom_escape(value: &str) -> String { fn prom_escape(value: &str) -> String {
// SECURITY: metric label values are route/module tokens, but escaping keeps
// the endpoint safe if future callers pass proxy-derived values.
value.replace('\\', "\\\\").replace('"', "\\\"") value.replace('\\', "\\\\").replace('"', "\\\"")
} }
@@ -1,3 +1,14 @@
//! Production-facing portal runtime support.
//!
//! This module groups the cross-cutting concerns that must stay consistent
//! across all portal routes: health/readiness/version contracts, query and
//! configuration limits, structured logging, Prometheus-style metrics and
//! request correlation metadata.
//!
//! CONTRACT: keep this module free from role-specific business rendering. It is
//! the operational boundary around the portal, not the workforce/security report
//! implementation itself.
pub(crate) mod health; pub(crate) mod health;
pub(crate) mod limits; pub(crate) mod limits;
pub(crate) mod logging; pub(crate) mod logging;
@@ -1,3 +1,10 @@
//! Readiness probe payload.
//!
//! CONTRACT: `/readyz` checks whether the portal is safe to receive normal
//! traffic. It must remain conservative: configuration errors and broken state
//! storage make the process `not_ready`; optional integrations can report
//! `disabled`, `not_required` or `contract_only` without failing the whole probe.
use std::path::Path; use std::path::Path;
use serde_json::{Value, json}; use serde_json::{Value, json};
@@ -1,3 +1,8 @@
//! Request correlation and route classification for portal observability.
//!
//! CONTRACT: generated route names must not expose volatile identifiers such as
//! case IDs, candidate IDs or evidence IDs; use route templates instead.
use std::cell::RefCell; use std::cell::RefCell;
use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{Instant, SystemTime, UNIX_EPOCH}; use std::time::{Instant, SystemTime, UNIX_EPOCH};
@@ -73,7 +78,7 @@ fn request_header(request: &Request, name: &str) -> Option<String> {
request request
.headers() .headers()
.iter() .iter()
.find(|header| header.field.to_string().eq_ignore_ascii_case(name)) .find(|header| header.field.as_str().as_str().eq_ignore_ascii_case(name))
.map(|header| header.value.as_str().to_string()) .map(|header| header.value.as_str().to_string())
} }
@@ -1,3 +1,8 @@
//! Build/version probe payload.
//!
//! CONTRACT: `/version` is used by smoke tests, runbooks and release evidence.
//! Keep field names stable and add new fields only in a backward-compatible way.
use serde_json::{Value, json}; use serde_json::{Value, json};
use crate::{Cli, PORTAL_SCHEMA_VERSION}; use crate::{Cli, PORTAL_SCHEMA_VERSION};
+8 -11
View File
@@ -13,23 +13,22 @@ Forensics с прозрачными rule-based объяснениями.
| Продукт | Публичная категория | Сильная сторона | Как позиционировать AWatch-rus рядом | | Продукт | Публичная категория | Сильная сторона | Как позиционировать AWatch-rus рядом |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| ActivityWatch | Open-source automated time tracker | Локальный, открытый и понятный сбор активности приложений и сайтов | AWatch-rus развивает этот подход в пилотный корпоративный контур с ролями, отчетами, Risk Narrative и эксплуатационной документацией | | ActivityWatch | Open-source automated time tracker | Локальный, открытый и понятный сбор активности приложений и сайтов | AWatch-rus развивает этот подход в пилотный корпоративный контур с ролями, отчетами, Risk Narrative и эксплуатационной документацией |
| Стахановец | Контроль сотрудников, мониторинг активности, DLP-возможности | Зрелый классический контроль рабочих мест и политик мониторинга | AWatch-rus не должен заявлять функциональный паритет; его сильная зона - объяснимый управленческий KPI, Security Analytics и пилотная прозрачность | | Стахановец | Контроль сотрудников, мониторинг активности, DLP-возможности | Зрелый классический контроль рабочих мест и политик мониторинга | AWatch-rus не заявляет функциональный паритет; его сильная зона - объяснимый управленческий KPI, Security Analytics и пилотная прозрачность |
| StaffCop | Employee Monitoring, Insider Risk, Workforce Analytics, DLP | Широкий набор функций мониторинга, productivity analytics, расследований и DLP-направления | AWatch-rus нужно показывать как более узкий и прозрачный пилотный контур, без обещания заменить StaffCop по широте функций | | StaffCop | Employee Monitoring, Insider Risk, Workforce Analytics, DLP | Широкий набор функций мониторинга, productivity analytics, расследований и DLP-направления | AWatch-rus это более узкий и прозрачный пилотный контур, без обещания заменить StaffCop по широте функций |
| SearchInform | DLP, Risk Monitor, SIEM, TimeInformer и смежные продукты | Комплексная линейка ИБ-продуктов и мониторинга внутренних рисков | AWatch-rus не конкурирует как полноценный SIEM/DLP; он может быть легким аналитическим слоем для Workforce-first пилота | | SearchInform | DLP, Risk Monitor, SIEM, TimeInformer и смежные продукты | Комплексная линейка ИБ-продуктов и мониторинга внутренних рисков | AWatch-rus не конкурирует как полноценный SIEM/DLP; он является легким аналитическим слоем для Workforce-first пилота |
| InfoWatch | DLP и защита от утечек конфиденциальной информации | Сильное DLP-направление, политики, интеграции и регуляторный контекст | AWatch-rus не заменяет DLP; он показывает операционную активность, объяснимые риски и материалы для внутренней проверки | | InfoWatch | DLP и защита от утечек конфиденциальной информации | Сильное DLP-направление, политики, интеграции и регуляторный контекст | AWatch-rus не заменяет DLP; он показывает операционную активность, объяснимые риски и материалы для внутренней проверки |
## Где AWatch-rus уместен ## Где AWatch-rus уместен
- Быстрый пилот для руководителя, ИБ и эксплуатации без тяжелого SIEM/DLP - Быстрый пилот для руководителя, ИБ и эксплуатации без тяжелого SIEM/DLP
внедрения. внедрения в организациях,желающих иметь современное программное обеспечение такого типа.
- Workforce-first аналитика с объяснением KPI, coverage и confidence. - Workforce-first аналитика с объяснением KPI, coverage и confidence.
- Разделение Executive, Workforce, Security и Forensics сценариев. - Разделение Executive, Workforce, Security и Forensics сценариев.
- Прозрачная rule-based модель UEBA Score v1 и Risk Narrative без ML/LLM. - Прозрачная rule-based модель UEBA Score v1 и Risk Narrative без дорогих средств использования Искусственного Интеллекта ML/LLM.
- Подготовка evidence package и Markdown-отчетов для ручной проверки. - Подготовка evidence package и Markdown-отчетов для ручной проверки.
- Честная демонстрация границ: planned, future и contract_only не выдаются за - Честная демонстрация границ: planned, future и contract_only не выдаются за implemented.
implemented.
## Где зрелые конкуренты обычно сильнее ## Где зрелые тяжелые конкуренты обычно сильнее
- Глубокие DLP-политики, контентная фильтрация и блокировки каналов утечки. - Глубокие DLP-политики, контентная фильтрация и блокировки каналов утечки.
- Масштабные SIEM/SOC-процессы и готовые интеграции ИБ. - Масштабные SIEM/SOC-процессы и готовые интеграции ИБ.
@@ -39,12 +38,10 @@ Forensics с прозрачными rule-based объяснениями.
- Поддержка сложных enterprise-сценариев с централизованным управлением - Поддержка сложных enterprise-сценариев с централизованным управлением
агентами и политиками. агентами и политиками.
## Что нельзя заявлять ## Что не заявляется
- Что AWatch-rus заменяет DLP, SIEM, EDR или XDR. - Что AWatch-rus заменяет DLP, SIEM, EDR или XDR.
- Что planned или future providers уже работают в production. - Что planned или future providers уже работают в production.
- Что pfSense readiness означает готовый ingestion, если он находится в статусе
`contract_only`.
- Что Risk Narrative является ML-прогнозом. - Что Risk Narrative является ML-прогнозом.
- Что система автоматически оценивает персонал или принимает кадровые решения. - Что система автоматически оценивает персонал или принимает кадровые решения.
+542 -297
View File
@@ -1,422 +1,667 @@
# Полная инструкция по развёртыванию и поддержке ActivityWatch-Russian Полная инструкция по развёртыванию и поддержке AWatch-rus
Документ описывает полный цикл: Proxmox/LXC сервер, установка ActivityWatch Server, RU Web UI patch, развёртывание Windows-клиентов в другом AD-домене, валидация, сопровождение и rollback. Статус документа
--- Этот документ описывает актуальный **Rust-fiWindows/PowerShell deployment flow больше не считается основным способом развёртывания, патчинга или эксплуатации. Если в репозитории остаются старые ".ps1"-файлы, они рассматриваются как legacy/history или как будущий provider-слой, но не как production runtime.
## 0) Структура проекта (полные пути) 0. Назначение
- `<PROJECT_ROOT>/private-config/deploy.env` AWatch-rus — программный комплекс операционного контроля, технического аудита, оценки трудоотдачи сотрудников и мониторинга корпоративной ИТ-инфраструктуры на базе:
- `<PROJECT_ROOT>/proxmox/create-ct.sh`
- `<PROJECT_ROOT>/proxmox/push-aw-artifacts.sh`
- `<PROJECT_ROOT>/aw-server/install_aw_server.sh`
- `<PROJECT_ROOT>/aw-server/apply_webui_ru_patch.sh`
- `<PROJECT_ROOT>/windows/deploy-single-user.ps1`
- `<PROJECT_ROOT>/windows/deploy-domain-users.ps1`
- `<PROJECT_ROOT>/windows/deploy-ensemble.ps1`
- `<PROJECT_ROOT>/windows/hardening-recovery.ps1`
- `<PROJECT_ROOT>/windows/validate-deployment.ps1`
- `<PROJECT_ROOT>/windows/browser-domains-native-collector.ps1`
- `<PROJECT_ROOT>/windows/dlp-endpoint-signals-collector.ps1`
- `<PROJECT_ROOT>/ansible/deploy_aw_server.yml`
- `<PROJECT_ROOT>/ansible/provision_proxmox_ct_and_deploy_aw.yml`
- `<PROJECT_ROOT>/ansible/provision_proxmox_ct_matrix_and_deploy_aw.yml`
- `<PROJECT_ROOT>/ansible/deploy_aw_windows.yml`
--- - Rust backend/runtime;
- Rust Agent;
- Rust server-rendered HTML + HTMX-compatible JSON API;
- Grafana/Prometheus-витрин;
- модулей Workforce, Security и Forensics;
- evidence/reporting tooling;
- ActivityWatch-compatible источников данных, где это применимо.
## 1) Подготовка Проект не позиционируется как сертифицированная DLP/SIEM/EDR/XDR/СЗИ. DLP, evidence, UEBA и расследовательские функции используются как внутренние аналитические и операционные модули.
### 1.1 Требования 1. Актуальная архитектура
- Proxmox VE 8/9, доступ root (или sudo с правами на `pct`). 1.1 Основной runtime
- Шаблон Debian 12 LXC на хосте Proxmox.
- Windows хост(ы) с PowerShell 5.1+ и правами локального администратора.
- Сетевой доступ Windows-клиентов до ActivityWatch Server (`5600/tcp`).
### 1.2 Подготовка единого файла секретов Основной production runtime AWatch-rus — Rust-first:
Скопируйте шаблон: - backend/runtime — Rust;
- agent — Rust;
- portal — Rust server-rendered HTML + HTMX-compatible JSON API;
- operational status/check — Rust;
- DLP server-side helpers — Rust;
- worktime helpers/exporters/prewarm — Rust;
- SLO/health/readiness helpers — Rust;
- evidence/install-kit tooling — Rust;
- auto-heal helpers — Rust, только в безопасном режиме.
```bash 1.2 Что не является основным runtime
cp <PROJECT_ROOT>/private-config/deploy.env.example \
<PROJECT_ROOT>/private-config/deploy.env
```
Заполните в файле `<PROJECT_ROOT>/private-config/deploy.env`: Не считать основным production deployment flow:
- все `CT_*` параметры контейнера; - PowerShell deployment;
- все `AW_SERVER_*` параметры сервера; - старые Windows ".ps1" rollout scripts;
- `CT_PASSWORD` (реальный пароль). - ручное исправление production-файлов без release/backup;
- прямое редактирование Web UI в "/opt" без воспроизводимого патча;
- Python/shell как основной operational runtime, если для компонента уже есть Rust-аналог.
Важно: этот файл подхватывается автоматически скриптами Proxmox. Python, shell, Ansible или PowerShell могут оставаться в проекте только как:
--- - legacy compatibility;
- вспомогательные dev/test tools;
- миграционные сценарии;
- будущие provider-слои;
- Telegram/OCR/AI/ETL/MCP helpers, если они явно не входят в Rust-first core.
## 2) Развёртывание сервера в Proxmox 2. Типовые роли узлов
### 2.0 Ansible full-stack (создание CT + установка AW) 2.1 Server node
Подготовьте: Серверный узел содержит:
- `<PROJECT_ROOT>/ansible/inventory.ini` - AWatch-rus backend/runtime;
- `<PROJECT_ROOT>/ansible/group_vars/all.yml` - portal;
- `<PROJECT_ROOT>/ansible/group_vars/proxmox.yml` - API;
- exporters;
- health/readiness/status tooling;
- systemd units/timers;
- Grafana/Prometheus integration;
- evidence/reporting storage.
Запуск: 2.2 Agent node
```bash Agent node содержит:
cd <PROJECT_ROOT>/ansible
ansible-playbook -i inventory.ini provision_proxmox_ct_and_deploy_aw.yml
```
Этот сценарий полностью закрывает: - Rust Agent;
- локальную конфигурацию агента;
- systemd service или другой штатный supervisor;
- локальные логи;
- буфер/очередь, если предусмотрено конфигурацией;
- сетевой доступ до backend/API.
- создание CT в Proxmox; 2.3 Monitoring node
- bootstrap пакетов в CT;
- установку ActivityWatch Server;
- применение RU Web UI patch;
- проверку API.
Для массового режима (несколько CT): Monitoring node может содержать:
```bash - Prometheus;
cd <PROJECT_ROOT>/ansible - Grafana;
ansible-playbook -i inventory.ini provision_proxmox_ct_matrix_and_deploy_aw.yml - dashboards;
``` - alerting rules;
- external logs/metrics storage.
### 2.1 Создать LXC контейнер Monitoring node может совпадать с server node в пилотной установке.
На узле Proxmox: 3. Требования
```bash 3.1 Базовые требования
cd <PROJECT_ROOT>
<PROJECT_ROOT>/proxmox/create-ct.sh
```
По умолчанию читается: - Linux-сервер или LXC/VM.
- Доступ администратора к systemd.
- Rust toolchain для сборочного узла.
- Сетевой доступ между agent node и server node.
- Закрытый доступ к API и порталу через VPN, reverse proxy или внутренний контур.
- Backup/snapshot перед любым production patch.
- `<PROJECT_ROOT>/private-config/deploy.env` 3.2 Рекомендуемый production-подход
При необходимости можно передать другой путь: Для production не собирать проект прямо на боевом сервере, если есть отдельный build host.
```bash Рекомендуемый поток:
<PROJECT_ROOT>/proxmox/create-ct.sh /absolute/path/to/deploy.env
```
### 2.2 Загрузить bootstrap-артефакты и env внутрь CT git checkout нужного commit/tag
→ cargo fmt / clippy / test / build
→ упаковка release artifacts
→ перенос artifacts на сервер
→ backup/snapshot
→ остановка/перезапуск нужных services
→ smoke tests
→ фиксация версии
```bash 4. Основные пути
cd <PROJECT_ROOT>
<PROJECT_ROOT>/proxmox/push-aw-artifacts.sh
```
Скрипт загружает в CT: Рекомендуемая структура на сервере:
- `<CT_BOOTSTRAP_DIR>/install_aw_server.sh` /opt/awatch-rus/
- `<CT_BOOTSTRAP_DIR>/apply_webui_ru_patch.sh` bin/
- `<CT_BOOTSTRAP_DIR>/activitywatch-server.service` etc/
- `<CT_BOOTSTRAP_DIR>/aw-ru-patch.js` portal/
- `<CT_BOOTSTRAP_DIR>/aw-sw-cleanup.js` releases/
- `/etc/activitywatch/aw-server.env` (из `AW_SERVER_*`) evidence/
reports/
logs/
### 2.3 Установить ActivityWatch Server внутри CT /etc/awatch-rus/
awatch-rus.env
agent.env
portal.env
```bash /var/lib/awatch-rus/
pct enter <CT_ID> data/
bash <CT_BOOTSTRAP_DIR>/install_aw_server.sh state/
``` cache/
evidence/
reports/
### 2.4 Применить RU patch Web UI /var/log/awatch-rus/
backend.log
agent.log
portal.log
exporter.log
```bash Рекомендуемые runtime binaries:
bash <CT_BOOTSTRAP_DIR>/apply_webui_ru_patch.sh
systemctl restart activitywatch-server.service
```
После применения патча доступны: /usr/local/bin/detmir-status
/usr/local/bin/detmir-check
/usr/local/bin/detmir-dlp
/usr/local/bin/detmir-auto
/usr/local/bin/detmir-heal-safe
/usr/local/bin/aw-rus-healthd
- верхнее меню `DLP` в Web UI; Имена конкретных бинарников должны соответствовать текущему "Cargo.toml" и фактически собранным artifacts. Если имя binary изменено, документация и systemd unit должны обновляться в том же commit.
- DLP-страница bucket `aw-dlp-endpoint-signals_<HOST>`;
- встроенный центр `DLP review и правила`;
- служебные buckets `aw-dlp-review_<HOST>` и `aw-dlp-rules_<HOST>`.
### 2.5 Проверка сервера 5. Конфигурация
В CT: 5.1 Общие правила
```bash - Не хранить production secrets в публичном репозитории.
systemctl status activitywatch-server.service --no-pager - Не коммитить реальные hostnames, IP, логины, ФИО, токены, пароли.
curl -fsS http://127.0.0.1:5600/api/0/info - Для production использовать "/etc/awatch-rus/*.env".
ss -ltnp | grep 5600 - Для demo использовать только обезличенные fixtures.
grep -n 'aw-ru-patch\|aw-sw-cleanup' /opt/activitywatch/webui-ru/index.html - Все параметры, влияющие на runtime, должны быть описаны в документации.
```
Ожидается: 5.2 Пример server env
- сервис `active (running)`; AWATCH_ENV=production
- API отвечает JSON; AWATCH_BIND_ADDR=127.0.0.1
- порт 5600 слушается; AWATCH_PORT=5600
- в `index.html` присутствуют оба скрипта. AWATCH_DATA_DIR=/var/lib/awatch-rus/data
AWATCH_LOG_DIR=/var/log/awatch-rus
AWATCH_EVIDENCE_DIR=/var/lib/awatch-rus/evidence
AWATCH_REPORTS_DIR=/var/lib/awatch-rus/reports
RUST_LOG=info
Дополнительно после первого входа в Web UI: 5.3 Пример agent env
- `#/home` должен показывать один корректный пункт `DLP`; AWATCH_AGENT_ENV=production
- `#/buckets/aw-dlp-endpoint-signals_<HOST>` должен открываться без ошибок; AWATCH_SERVER_URL=https://awatch.example.local
- сохранение review/rule должно создавать buckets `aw-dlp-review_<HOST>` и `aw-dlp-rules_<HOST>`. AWATCH_AGENT_HOST_ID=HOSTNAME_OR_NODE_ID
AWATCH_AGENT_DATA_DIR=/var/lib/awatch-rus/agent
AWATCH_AGENT_LOG_DIR=/var/log/awatch-rus
RUST_LOG=info
--- 6. Сборка
## 3) Развёртывание Windows-клиентов (другой AD-домен) 6.1 Проверки перед сборкой
### 3.1 Подготовка на Windows-хосте На build host:
Скопируйте каталог: cd /path/to/AWatch-rus
- `<PROJECT_ROOT>/windows` git status --short
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
например в: Если в репозитории есть проектные quality gates, выполнить их обязательно:
- `C:\Program Files\AWatch-rus\windows` bash scripts/check_private_config_guard.sh
bash scripts/quality-gate.sh
Откройте **elevated PowerShell**: Если какой-то скрипт отсутствует в текущей ветке, не создавать фиктивную замену. Зафиксировать это в release notes.
```powershell 6.2 Release build
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process
```
### 3.2 Массовое доменное развёртывание (рекомендуется) cargo build --release --workspace
Если текущий production ещё работает в старых каталогах Проверить artifacts:
`C:\Program Files\ActivityWatch-Phase2` и `C:\ProgramData\ActivityWatch-Phase2`,
сначала выполните безопасную миграцию:
```powershell find target/release -maxdepth 1 -type f -executable -print
C:\Program Files\AWatch-rus\windows\migrate-awatch-rus-paths.ps1 -WhatIf
C:\Program Files\AWatch-rus\windows\migrate-awatch-rus-paths.ps1
```
Скрипт остановит `ActivityWatch Recovery`/`ActivityWatch Launch *`, создаст backup в 6.3 Упаковка artifacts
`C:\ProgramData\AWatch-rus\migration-backups\...`, перенесёт файлы в единые пути,
пересоздаст `deployment-config.json`/scheduled tasks и запустит validation.
Пример со списком пользователей: Рекомендуемый вариант:
```powershell mkdir -p dist/awatch-rus-release/bin
C:\Program Files\AWatch-rus\windows\deploy-domain-users.ps1 ` cp target/release/detmir-status dist/awatch-rus-release/bin/ 2>/dev/null || true
-ServerHost aw.example.local ` cp target/release/detmir-check dist/awatch-rus-release/bin/ 2>/dev/null || true
-ServerPort 5600 ` cp target/release/detmir-dlp dist/awatch-rus-release/bin/ 2>/dev/null || true
-Domain CONTOSO ` cp target/release/detmir-auto dist/awatch-rus-release/bin/ 2>/dev/null || true
-UserListPath C:\Deploy\aw-users.txt ` cp target/release/detmir-heal-safe dist/awatch-rus-release/bin/ 2>/dev/null || true
-CustomRulesPath C:\Program Files\AWatch-rus\windows\web-category-rules.example.json cp target/release/aw-rus-healthd dist/awatch-rus-release/bin/ 2>/dev/null || true
```
Поддерживаемые варианты: tar -C dist -czf awatch-rus-release.tar.gz awatch-rus-release
sha256sum awatch-rus-release.tar.gz > awatch-rus-release.tar.gz.sha256
- `-Users user01,user02` Не использовать "cp ... || true" в CI без последующей проверки обязательных binaries. Для ручного production release список обязательных binaries должен быть проверен явно.
- `-Users 'CONTOSO\user01','CONTOSO\user02'`
- `-UserListPath <txt|csv>`
### 3.2.1 Ensemble orchestration (рекомендуется для production) 7. Первичное развёртывание server node
```powershell 7.1 Создание каталогов
C:\Program Files\AWatch-rus\windows\deploy-ensemble.ps1 `
-ServerHost aw.example.local `
-ServerPort 5600 `
-Domain CONTOSO `
-Users user1,user2,user3,user4,user5 `
-ValidateAfterDeploy
```
Отчёт сохраняется в: sudo mkdir -p /opt/awatch-rus/bin
sudo mkdir -p /opt/awatch-rus/releases
sudo mkdir -p /etc/awatch-rus
sudo mkdir -p /var/lib/awatch-rus/data
sudo mkdir -p /var/lib/awatch-rus/state
sudo mkdir -p /var/lib/awatch-rus/evidence
sudo mkdir -p /var/lib/awatch-rus/reports
sudo mkdir -p /var/log/awatch-rus
- `C:\ProgramData\AWatch-rus\ensemble-report-YYYYMMDD-HHMMSS.json` 7.2 Установка binaries
### 3.3 Single-user развёртывание sudo install -m 0755 dist/awatch-rus-release/bin/* /opt/awatch-rus/bin/
```powershell Создать symlink для удобства:
C:\Program Files\AWatch-rus\windows\deploy-single-user.ps1 `
-ServerHost aw.example.local `
-ServerPort 5600 `
-TargetUser 'CONTOSO\user01' `
-CustomRulesPath C:\Program Files\AWatch-rus\windows\web-category-rules.example.json
```
### 3.4 Recovery / hardening sudo ln -sf /opt/awatch-rus/bin/detmir-status /usr/local/bin/detmir-status
sudo ln -sf /opt/awatch-rus/bin/detmir-check /usr/local/bin/detmir-check
sudo ln -sf /opt/awatch-rus/bin/detmir-dlp /usr/local/bin/detmir-dlp
```powershell Если binary отсутствует, не создавать пустой symlink. Сначала проверить фактический состав release artifact.
C:\Program Files\AWatch-rus\windows\hardening-recovery.ps1 `
-ConfigPath C:\ProgramData\AWatch-rus\deployment-config.json
```
### 3.5 Валидация deployment-а (PowerShell report) 7.3 Конфигурация
```powershell sudo install -m 0640 awatch-rus.env /etc/awatch-rus/awatch-rus.env
$report = C:\Program Files\AWatch-rus\windows\validate-deployment.ps1 `
-ConfigPath C:\ProgramData\AWatch-rus\deployment-config.json
$report | ConvertTo-Json -Depth 12
```
--- Проверить права:
## 4) Что должно появиться на Windows после установки sudo chown root:root /etc/awatch-rus/awatch-rus.env
sudo chmod 0640 /etc/awatch-rus/awatch-rus.env
- `C:\Program Files\AWatch-rus\bin` 8. systemd units
- `C:\ProgramData\AWatch-rus\deployment-config.json`
- `C:\ProgramData\AWatch-rus\launch-watchers.ps1`
- `C:\ProgramData\AWatch-rus\recovery-loop.ps1`
- `C:\ProgramData\AWatch-rus\browser-domains-native-collector.ps1`
- `C:\ProgramData\AWatch-rus\web-category-rules.json`
- `C:\ProgramData\AWatch-rus\logs\`
Задачи планировщика: 8.1 Пример backend service
- `ActivityWatch Launch [<user>]` (per-user, при логоне) [Unit]
- `ActivityWatch Recovery` (system-level recovery) Description=AWatch-rus backend/runtime
After=network-online.target
Wants=network-online.target
--- [Service]
Type=simple
EnvironmentFile=/etc/awatch-rus/awatch-rus.env
ExecStart=/opt/awatch-rus/bin/awatch-rus-backend
Restart=on-failure
RestartSec=5
WorkingDirectory=/opt/awatch-rus
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
ReadWritePaths=/var/lib/awatch-rus /var/log/awatch-rus
## 5) Полная валидация потока данных [Install]
WantedBy=multi-user.target
### 5.1 На Windows-хосте Если фактическое имя backend binary отличается, заменить "awatch-rus-backend" на актуальное имя из release artifact.
Проверить процессы: 8.2 Пример health service
```powershell [Unit]
Get-Process aw-watcher-afk,aw-watcher-window -ErrorAction SilentlyContinue Description=AWatch-rus health daemon
Get-CimInstance Win32_Process | ? { $_.CommandLine -like '*browser-domains-native-collector.ps1*' } | select ProcessId,SessionId,CommandLine After=network-online.target
``` Wants=network-online.target
Проверить задачи: [Service]
Type=simple
EnvironmentFile=/etc/awatch-rus/awatch-rus.env
ExecStart=/opt/awatch-rus/bin/aw-rus-healthd
Restart=on-failure
RestartSec=5
WorkingDirectory=/opt/awatch-rus
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
ReadWritePaths=/var/lib/awatch-rus /var/log/awatch-rus
```powershell [Install]
Get-ScheduledTask | ? { $_.TaskName -like 'ActivityWatch*' } | select TaskName,State WantedBy=multi-user.target
```
### 5.2 На сервере ActivityWatch API 8.3 Применение unit files
```bash sudo systemctl daemon-reload
curl -sS http://127.0.0.1:5600/api/0/buckets | jq 'keys' sudo systemctl enable --now awatch-rus-backend.service
``` sudo systemctl enable --now aw-rus-healthd.service
Ожидаемые bucket'ы: Если конкретный unit не используется в текущей инсталляции, не создавать фиктивный сервис. Документировать фактический набор services.
- `aw-watcher-afk_<HOST>` 9. Развёртывание Rust Agent
- `aw-watcher-window_<HOST>`
- `aw-watcher-web-<browser>_<HOST>`
- `aw-detmir-web-category_<HOST>` (категоризованный поток)
- `aw-dlp-endpoint-signals_<HOST>` (endpoint сигналы)
- `aw-dlp-review_<HOST>` (ручная классификация через UI)
- `aw-dlp-rules_<HOST>` (suppress/rule записи через UI)
Проверка событий браузера: 9.1 Установка agent binary
```bash sudo mkdir -p /opt/awatch-rus/bin
curl -sS "http://127.0.0.1:5600/api/0/buckets/aw-watcher-web-edge_<HOST>/events?limit=5" | jq sudo mkdir -p /etc/awatch-rus
``` sudo mkdir -p /var/lib/awatch-rus/agent
sudo mkdir -p /var/log/awatch-rus
Проверка категоризации: sudo install -m 0755 awatch-rus-agent /opt/awatch-rus/bin/awatch-rus-agent
sudo install -m 0640 agent.env /etc/awatch-rus/agent.env
```bash 9.2 Пример agent service
curl -sS "http://127.0.0.1:5600/api/0/buckets/aw-detmir-web-category_<HOST>/events?limit=5" | jq
```
Проверка DLP review/rules: [Unit]
Description=AWatch-rus Rust Agent
After=network-online.target
Wants=network-online.target
```bash [Service]
curl -sS "http://127.0.0.1:5600/api/0/buckets/aw-dlp-review_<HOST>/events?limit=20" | jq Type=simple
curl -sS "http://127.0.0.1:5600/api/0/buckets/aw-dlp-rules_<HOST>/events?limit=20" | jq EnvironmentFile=/etc/awatch-rus/agent.env
``` ExecStart=/opt/awatch-rus/bin/awatch-rus-agent
Restart=on-failure
RestartSec=5
WorkingDirectory=/opt/awatch-rus
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
ReadWritePaths=/var/lib/awatch-rus /var/log/awatch-rus
Ожидаемые поля review: [Install]
WantedBy=multi-user.target
- `reviewId` 9.3 Запуск agent
- `signalType`
- `verdict`
- `category`
- `comment`
- `archived`
Ожидаемые поля rules: sudo systemctl daemon-reload
sudo systemctl enable --now awatch-rus-agent.service
sudo systemctl status awatch-rus-agent.service --no-pager
- `ruleId` 10. Развёртывание портала
- `signalType`
- `match`
- `category`
- `comment`
- `enabled`
--- Портальный слой AWatch-rus зафиксирован как Rust server-rendered HTML + HTMX-compatible JSON API.
## 6) Сопровождение (обязательно) 10.1 Общий порядок
### 6.1 Backup перед любыми изменениями build portal/backend binary
→ install binary
→ install templates/static assets, если они выделены отдельно
→ update portal env
→ restart portal service
→ smoke check HTTP/API routes
На Proxmox: 10.2 Проверка портала
curl -fsS http://127.0.0.1:5600/healthz
curl -fsS http://127.0.0.1:5600/readyz
curl -fsS http://127.0.0.1:5600/version
Если конкретные endpoints в текущей версии отличаются, использовать фактически реализованные health/readiness/version endpoints и обновить этот документ в том же commit.
11. Патчи в развернутой среде
11.1 Правило
Любой production patch применяется только через контролируемый цикл:
определить commit/tag
→ собрать release artifact
→ выполнить локальные проверки
→ сделать backup/snapshot
→ установить новые binaries/configs
→ restart/reload services
→ smoke tests
→ зафиксировать результат
→ сохранить rollback path
11.2 Перед патчем
git rev-parse HEAD
git status --short
Сохранить:
дата/время
commit/tag
кто применяет
какие services затрагиваются
какой rollback path
11.3 Backup перед патчем
Если используется Proxmox/LXC:
```bash
vzdump <CT_ID> --mode snapshot --compress zstd --storage <BACKUP_STORAGE> vzdump <CT_ID> --mode snapshot --compress zstd --storage <BACKUP_STORAGE>
```
Конфиги внутри CT: Внутри сервера:
```bash sudo tar -C / -czf /root/awatch-rus-backup-$(date +%Y%m%d-%H%M%S).tgz \
pct exec <CT_ID> -- tar -C / -czf <PRIVATE_BACKUP_DIR>/activitywatch-config-backup.tgz \ etc/awatch-rus \
etc/activitywatch \ opt/awatch-rus \
etc/systemd/system/activitywatch-server.service \ var/lib/awatch-rus \
opt/activitywatch/webui-ru \ var/log/awatch-rus
opt/activitywatch/releases
```
### 6.2 Обновление сервера Если данные большие, backup "/var/lib/awatch-rus" выполнять отдельной процедурой согласно backup policy.
1. Обновить `AW_SERVER_VERSION` и `AW_SERVER_DOWNLOAD_URL` в 11.4 Установка нового binary
`<PROJECT_ROOT>/private-config/deploy.env`
2. Выполнить:
```bash Сохранить предыдущую версию:
<PROJECT_ROOT>/proxmox/push-aw-artifacts.sh
pct enter <CT_ID>
bash <CT_BOOTSTRAP_DIR>/install_aw_server.sh
bash <CT_BOOTSTRAP_DIR>/apply_webui_ru_patch.sh
systemctl restart activitywatch-server.service
```
3. Повторить валидацию API/UI. sudo mkdir -p /opt/awatch-rus/releases/previous
sudo cp -a /opt/awatch-rus/bin /opt/awatch-rus/releases/previous/bin-$(date +%Y%m%d-%H%M%S)
### 6.3 Rollback Установить новый artifact:
RU patch rollback: sudo install -m 0755 dist/awatch-rus-release/bin/* /opt/awatch-rus/bin/
```bash 11.5 Restart services
cp /opt/activitywatch/webui-ru/index.html.bak.<timestamp> /opt/activitywatch/webui-ru/index.html
systemctl restart activitywatch-server.service
```
Полный rollback: sudo systemctl daemon-reload
sudo systemctl restart awatch-rus-backend.service
sudo systemctl restart aw-rus-healthd.service
- восстановить CT из snapshot/backup; Если патч касается только agent:
- проверить API и Web UI;
- проверить доступность для Windows-клиентов.
--- sudo systemctl restart awatch-rus-agent.service
## 7) Безопасность Если сервис в текущем контуре называется иначе, использовать фактическое имя systemd unit.
- Не хранить реальные приватные параметры вне `<PROJECT_ROOT>/private-config/deploy.env`. 12. Smoke-тесты после патча
- Не открывать `5600/tcp` в интернет напрямую.
- Публиковать через VPN или reverse proxy с ограничением доступа.
- Перед изменениями всегда делать backup.
--- 12.1 Systemd
## 8) Короткий чек-лист ввода в эксплуатацию systemctl --failed --no-pager
systemctl status awatch-rus-backend.service --no-pager
systemctl status aw-rus-healthd.service --no-pager
1. Заполнен `<PROJECT_ROOT>/private-config/deploy.env`. 12.2 Rust operational checks
2. Выполнен `<PROJECT_ROOT>/proxmox/create-ct.sh`.
3. Выполнен `<PROJECT_ROOT>/proxmox/push-aw-artifacts.sh`. detmir-status --json
4. В CT выполнены `<CT_BOOTSTRAP_DIR>/install_aw_server.sh` и `<CT_BOOTSTRAP_DIR>/apply_webui_ru_patch.sh`. detmir-check --json
5. Сервер API/порт/UI проверены. detmir-dlp --json
6. На Windows выполнен `deploy-domain-users.ps1`.
7. Проверены процессы, задачи и bucket'ы. Если отдельная команда не установлена в данном контуре, это не считается ошибкой только при наличии документированного исключения.
8. Зафиксированы параметры и дата ввода.
12.3 HTTP/API
curl -fsS http://127.0.0.1:5600/healthz
curl -fsS http://127.0.0.1:5600/readyz
curl -fsS http://127.0.0.1:5600/version
12.4 Portal smoke
Проверить в браузере:
/portal
/portal/reports
/portal/architecture
Для Pilot v1 проверить роли:
executive
manager
security
forensics
admin
12.5 Data freshness
Проверить, что витрины и отчёты не пустые из-за сбоя сбора:
последние события поступают
worktime reports обновляются
DLP/security events отображаются, если включены
evidence/reporting не падает
Grafana dashboards открываются
13. Rollback
13.1 Быстрый rollback binary
Найти предыдущий backup:
ls -lah /opt/awatch-rus/releases/previous/
Восстановить:
sudo rsync -a --delete /opt/awatch-rus/releases/previous/bin-YYYYMMDD-HHMMSS/ /opt/awatch-rus/bin/
sudo systemctl restart awatch-rus-backend.service
sudo systemctl restart aw-rus-healthd.service
13.2 Rollback конфигурации
sudo cp /etc/awatch-rus/awatch-rus.env.bak /etc/awatch-rus/awatch-rus.env
sudo systemctl restart awatch-rus-backend.service
13.3 Rollback CT/VM
Если повреждение затрагивает runtime, данные или systemd-конфигурацию:
остановить сервисы
восстановить snapshot/backup
проверить health/readiness/version
проверить портал
проверить поступление данных
зафиксировать incident note
14. Monitoring
14.1 Что должно контролироваться
- service status;
- process uptime;
- API health/readiness;
- latency;
- error rate;
- freshness данных;
- заполненность диска;
- размер логов;
- успешность exporters;
- SLO status;
- agent coverage;
- отсутствие failed systemd units.
14.2 Grafana
В Grafana должны быть разделены витрины:
- executive dashboard;
- security dashboard;
- operations dashboard;
- RDP/user activity dashboard;
- data quality/freshness dashboard;
- DLP/evidence dashboard, если модуль включён.
14.3 Prometheus
Prometheus scrape должен быть доступен только из внутреннего контура мониторинга. Не открывать metrics endpoints наружу.
15. Security hardening
Обязательные правила:
- не публиковать API напрямую в интернет;
- использовать VPN/reverse proxy/access control;
- закрыть лишние порты;
- хранить secrets вне git;
- ограничить права systemd services;
- использовать отдельного service user, если это поддерживается текущей установкой;
- включить backup;
- проверять логи после каждого патча;
- не использовать demo fixtures как production data;
- не смешивать реальные ФИО/IP/hostname с публичными demo screenshots.
16. Проверка перед вводом в эксплуатацию
Минимальный checklist:
[ ] выбран commit/tag release
[ ] cargo fmt прошёл
[ ] cargo clippy прошёл
[ ] cargo test прошёл
[ ] cargo build --release прошёл
[ ] private config guard прошёл
[ ] backup/snapshot создан
[ ] binaries установлены
[ ] systemd services запущены
[ ] health/readiness/version отвечают
[ ] detmir-status/check/dlp работают
[ ] portal открывается
[ ] роли Pilot v1 проверены
[ ] Grafana dashboards открываются
[ ] данные поступают
[ ] rollback path известен
[ ] дата/commit/оператор зафиксированы
17. Что больше не использовать как основной путь
Не использовать как основной production flow:
windows/deploy-single-user.ps1
windows/deploy-domain-users.ps1
windows/deploy-ensemble.ps1
windows/validate-deployment.ps1
windows/hardening-recovery.ps1
windows/browser-domains-native-collector.ps1
windows/dlp-endpoint-signals-collector.ps1
Если эти файлы физически остаются в репозитории, они должны быть явно помечены как:
legacy
planned provider
migration-only
dev/test helper
Они не должны описываться в основном deployment manual как обязательный production-путь.
18. Короткий production runbook
18.1 Развернуть
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo build --release --workspace
sudo install -m 0755 target/release/<binary> /opt/awatch-rus/bin/<binary>
sudo systemctl daemon-reload
sudo systemctl restart <service>.service
18.2 Проверить
systemctl --failed --no-pager
detmir-status --json
detmir-check --json
curl -fsS http://127.0.0.1:5600/healthz
curl -fsS http://127.0.0.1:5600/readyz
curl -fsS http://127.0.0.1:5600/version
18.3 Откатить
sudo rsync -a --delete /opt/awatch-rus/releases/previous/bin-YYYYMMDD-HHMMSS/ /opt/awatch-rus/bin/
sudo systemctl restart <service>.service
19. Правило актуализации этого документа
Если меняется:
- имя binary;
- имя systemd unit;
- порт;
- endpoint;
- путь хранения данных;
- способ сборки;
- способ доставки artifacts;
- smoke-test;
- rollback procedure;
то этот файл должен обновляться в том же commit, что и изменение кода или deployment-конфигурации.
+4
View File
@@ -0,0 +1,4 @@
[toolchain]
channel = "1.94.0"
profile = "minimal"
components = ["rustfmt", "clippy"]