28 KiB
Roadmap: замена PowerShell на Rust EXE
Дата: 2026-06-05
Цель: убрать зависимость AWatch-rus от PowerShell-скриптов на рабочих хостах и заменить их на самодостаточные Rust EXE/службы без потери данных, без ухудшения пилотной демонстрации и без изменения функционального объема.
Документ описывает порядок миграции. Он не вводит новые функции: каждая Rust замена сначала должна повторить текущий контракт PowerShell-компонента.
Актуальная статусная матрица оставшихся PowerShell-файлов:
POWERSHELL_SCRIPT_STATUS_MATRIX_RU.md.
Операторский checkpoint от 2026-06-05 сохранен в private .ops-контуре:
Phase 0 live inventory выполнен, Phase 2 validation для уже переведенных
Windows Rust paths выполнен успешно. В tracked документации не публикуются live
hostnames, private IP, токены и runtime evidence paths.
1. Целевое состояние
К концу миграции:
- на Windows/RDP-хостах регулярный сбор данных, evidence-sync, 1C upload, guard/recovery и validation выполняются Rust EXE;
- в Scheduled Tasks и Windows Services нет штатных AWatch-rus задач, которые
запускают
powershell.exeилиpwsh.exe; - install-kit поставляет Rust EXE, конфиги и service/task definitions вместо
runtime
.ps1; - Ansible разворачивает Rust binaries и конфиги, а не копирует PowerShell runtime scripts;
- Telegram/Codex/bot контур вызывает Rust helpers или читает Rust JSON
snapshots, не опираясь на пути к
.ps1; - legacy PowerShell хранится только как временный rollback-слой до прохождения acceptance gates и затем удаляется из install-kit;
- Linux/AW/Proxmox части остаются Rust-first; Ansible может остаться оркестратором, потому что это инфраструктурный deploy layer, а не runtime PowerShell.
2. Текущее состояние
Уже выполнено или частично выполнено:
awatch-agent-rsзаменяет Windowsworktime-session-collector.ps1для worktime/RDP path. Legacy PowerShell оставлен как fallback и управляетсяcollectors.worktimeSessionEnabled,worktimeSessionMode,worktimeLegacyFallbackEnabled.aw-windows-telemetry.exeуже используется для:file1c-upload;dlp-evidence-sync.
aw-1c-ingest-rustпишет 1C/file analytics в ClickHouse на серверной стороне.aw-windows-telemetry.exe validate-deploymentдобавлен как Rust validation gate первого уровня. Он проверяет уже мигрированные Windows Rust paths, свежесть worktime bucket, Rust collector guard service и queue sanity без запуска PowerShell.AWatchRusCollectorGuardпереключен сaw-collector-guard.ps1наaw-windows-telemetry.exe collector-guard. Старый PowerShell guard оставлен как rollback script, но штатный service runtime его не запускает. Rust guard получаетsessionIdиз native process snapshot, дедуплицирует legacy collectors по(kind, sessionId)и не запускает пользовательские launch tasks повторно, если legacy collectors уже активны.aw-windows-telemetry.exeдобавил P0 runtime collector subcommands:browser-domains-collector,dlp-endpoint-collector,file-operations-collector. На live Windows/RDP host они включены черезcollectors.*Mode=rust_primary, работают в трех пользовательских сессиях, а P0 PowerShell collector runtime отсутствует. Это не означает полного удаления legacy.ps1: они оставлены как rollback/reference до расширения глубокой функциональной parity.- Основные серверные AWatch-rus/AW/DLP helpers уже Rust-first:
detmir-status,detmir-check,detmir-auto,detmir-heal-safe,aw-rus-healthd-rust,dlp-*,worktime-*,aw-health-check,check-aw-data,aw-prune-local-stateи другие.
Остаток PowerShell в рабочем дереве:
- 26 product
.ps1вwindows/; - operator/MCP helper
scripts/powershell/detmir-powershell-profile.ps1; - parse-check helper
.pssa_run.ps1; .venv/bin/activate.ps1внутри virtualenv не является продуктовым компонентом и не входит в миграцию.
3. Инвентаризация Windows PowerShell
| Скрипт | Роль | Цель миграции | Приоритет |
|---|---|---|---|
worktime-session-collector.ps1 |
RDP/worktime сбор | закрепить замену через awatch-agent-rs, затем удалить fallback |
P0 done/stabilize |
browser-domains-native-collector.ps1 |
browser/domain и DLP web-сигналы | aw-windows-telemetry.exe browser-domains-collector; live Rust primary, legacy fallback/reference |
P0 live/stabilize |
dlp-endpoint-signals-collector.ps1 |
clipboard/USB/print/DLP incident signals | aw-windows-telemetry.exe dlp-endpoint-collector; live Rust primary, screenshots только для DLP events |
P0 live/stabilize |
file-operations-collector.ps1 |
file create/delete/rename/archive hints | aw-windows-telemetry.exe file-operations-collector; live Rust primary with queue/spool |
P0 live/stabilize |
email-outbound-collector.ps1 |
outbound email metadata/DLP | Rust email metadata collector | P1 |
dlp-policy-client.ps1 |
получение DLP policy | Rust policy client/cache | P1 |
export-upload-file-1c-telemetry.ps1 |
1C telemetry upload | закрепить aw-windows-telemetry.exe file1c-upload, затем удалить legacy |
P0 done/stabilize |
sync-dlp-evidence-artifacts.ps1 |
DLP evidence upload | закрепить aw-windows-telemetry.exe dlp-evidence-sync |
P0 done/stabilize |
export-evtx-for-hayabusa.ps1 |
bounded EVTX export | Rust EVTX export helper | P1 |
export-upload-hayabusa-to-aw-server.ps1 |
EVTX/Hayabusa upload | Rust upload helper или режим в aw-windows-telemetry.exe |
P1 |
aw-standalone-service.ps1 |
supervisor service wrapper | Rust Windows service wrapper | P0 |
aw-collector-guard.ps1 |
guard/restart/recovery | Rust guard with allowlist, lock, cooldown | P0 done/stabilize |
hardening-recovery.ps1 |
recovery/hardening | Rust recovery CLI; destructive actions behind --apply |
P1 |
validate-deployment.ps1 |
post-deploy validation | Rust validation CLI aw-windows-telemetry.exe validate-deployment; расширять до полной parity перед удалением .ps1 |
P0 started |
rebuild-worktime-tasks.ps1 |
rebuild scheduled tasks | Rust task reconciliation CLI | P1 |
fix-session-watchers.ps1 |
repair session watchers | Rust repair subcommand | P2 |
cleanup-disc-sessions.ps1 |
cleanup stale disconnected sessions | Rust maintenance subcommand | P2 |
migrate-awatch-rus-paths.ps1 |
path migration | Rust migration CLI with backup and dry-run | P1 |
deploy-single-user.ps1 |
single-user deploy | Rust/Ansible-backed installer action | P1 |
deploy-domain-users.ps1 |
domain deploy | Rust/Ansible-backed installer action | P1 |
deploy-ensemble.ps1 |
orchestrated deploy | Rust deploy coordinator or Ansible playbook wrapper | P1 |
install-standalone-service.ps1 |
local service install | Rust installer/bootstrap CLI | P0 |
install-collector-guard-service.ps1 |
guard service install | Rust installer/bootstrap CLI | P0 |
install-dlp-client.ps1 |
DLP client install | Rust installer/bootstrap CLI | P1 |
audit-cryptopro.ps1 |
CryptoPro audit | Rust audit CLI | P2 |
run-user1-probe.ps1 |
manual probe | Rust diagnostic probe | P2 |
4. Неприкосновенные ограничения
- Не делать big-bang replacement.
- Не отключать PowerShell fallback до прохождения shadow/parity gates.
- Не переносить функции, которые требуют скрытого сбора, keylogging, screen recording или content interception. Скриншоты допустимы только для DLP incident evidence, если это явно включено политикой.
- Не менять бизнес-логику DLP, 1C, worktime или evidence при переносе.
- Не менять thresholds, bucket names, event schema и ClickHouse schema без отдельного решения.
- Не ломать install-kit и rollback ради удаления
.ps1. - Не хранить live hostnames, private IP, tokens, passwords или runtime evidence paths в публичных tracked docs.
5. Общий контракт каждого Rust EXE
Каждый заменяющий EXE должен иметь:
--config <path>;--jsonдля машинного вывода;--dry-runдля всех действий, меняющих состояние;--timeout-seconds;--log-pathили structured logging в штатный каталог;--version;- стабильные exit codes:
0- OK;1- usage/config/runtime error;2- check выполнен, но состояние WARN/FAIL;3- action запрещен safety policy;
- structured JSON event для audit trail;
- lock/cooldown для guard/recovery/actions;
- spool/queue для сетевых upload path;
- atomic writes для state files;
- no implicit sudo/admin: повышенные права должны быть видны в task/service definition;
- rollback compatibility с текущими config keys.
6. Фазы миграции
Phase 0. Baseline и реестр вызовов
Цель: зафиксировать, где PowerShell реально используется.
Действия:
- Сканировать репозиторий:
windows/*.ps1;windows/installkit/innosetup/*.iss;ansible/*.yml;ansible/group_vars/*.yml;scripts/*;- docs/runbooks.
- Снять runtime baseline на тестовом Windows host:
- Scheduled Tasks;
- Windows Services;
- текущие command lines процессов;
deployment-config.json;- свежесть AW buckets;
- наличие DLP evidence и 1C upload.
- Для каждого скрипта зафиксировать:
- входные параметры;
- env/config keys;
- side effects;
- event schema;
- log/state paths;
- expected exit codes;
- rollback path.
Выход фазы:
docs/POWERSHELL_TO_RUST_ROADMAP_RU.mdкак базовая дорожная карта;- отдельный runtime inventory для live-контура в private/operator notes, без публикации секретов.
Phase 1. Windows Rust foundation
Цель: подготовить общий Windows runtime вместо набора разрозненных EXE.
Действия:
- Расширить существующие
awatch-agent-rsиaw-windows-telemetryтолько в рамках parity, без новых функций. - Вынести общие Windows helpers:
- config loading;
- ActivityWatch HTTP client;
- evidence upload client;
- Windows task/service inspection;
- Event Log/EVTX access;
- filesystem state/spool;
- structured logs/audit.
- Зафиксировать единый Windows config contract:
C:\ProgramData\AWatch-rus\deployment-config.json;C:\Program Files\AWatch-rus\windows\*.exe;C:\ProgramData\AWatch-rus\logs;C:\ProgramData\AWatch-rus\spool;C:\ProgramData\AWatch-rus\switch-backups.
Gate:
cd adk-rust
cargo fmt --all -- --check
cargo test --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo build --release -p awatch-agent-rs -p aw-windows-telemetry
Phase 2. Закрепить уже выполненные замены
Цель: не переписать повторно то, что уже переведено, а довести до production definition of done.
Компоненты:
worktime-session-collector.ps1->awatch-agent-rs;export-upload-file-1c-telemetry.ps1->aw-windows-telemetry.exe file1c-upload;sync-dlp-evidence-artifacts.ps1->aw-windows-telemetry.exe dlp-evidence-sync;aw-collector-guard.ps1->aw-windows-telemetry.exe collector-guardчерезAWatchRusCollectorGuardservice wrapper;- серверный writer ->
aw-1c-ingest-rust.
Действия:
- Проверить, что task/service actions запускают EXE, а не PowerShell.
- Проверить, что PowerShell fallback выключен там, где Rust уже стабилен.
- Проверить свежесть buckets/ClickHouse/evidence after restart.
- Обновить install-kit file list: Rust EXE являются primary artifact.
- Оставить legacy
.ps1только как rollback на ограниченный период.
Gate:
ActivityWatch File1C Uploadзапускаетaw-windows-telemetry.exe;ActivityWatch DLP Evidence Syncзапускаетaw-windows-telemetry.exe;- worktime events имеют
source=awatch-agent-rs; AWatchRusCollectorGuardзапущен и его child process -aw-windows-telemetry.exe collector-guard;- guard не создает duplicate legacy browser/fileops/DLP endpoint collectors при stale bucket: при уже активных collectors launch tasks не запускаются повторно;
- 1C ClickHouse ingest идет по
aw-1c-ingest-rust; - PowerShell worktime process count = 0 в штатном режиме.
- PowerShell
aw-collector-guard.ps1process count = 0 в штатном режиме.
Phase 3. Runtime collectors
Цель: заменить регулярный сбор данных на Windows.
Порядок:
browser-domains-native-collector.ps1- current status: live Rust primary through
aw-windows-telemetry.exe browser-domains-collector; - ActivityWatch window/category health events are written with
source=aw-windows-telemetry-rust; - UIAutomation URL/domain extraction implemented in Rust: browser process
detection, normalized URL, host/rootDomain, default/custom category rules,
aw-watcher-web-*,aw-detmir-web-category_*and web DLP incident schema preserve the legacy bucket/event contract; - live disconnected RDP sessions may legitimately report
browserDetected=falseandurlDetected=falseuntil a browser is foreground in an interactive user session; - screenshots только для DLP incident evidence.
- current status: live Rust primary through
dlp-endpoint-signals-collector.ps1- current status: live Rust primary through
aw-windows-telemetry.exe dlp-endpoint-collector; - endpoint collector health is written with
source=aw-windows-telemetry-rust; - clipboard metadata/hash/length, USB insert, print job metadata and DLP
incident event semantics implemented in Rust with legacy fields:
requestedAction,enforcementMode,nativeChannelAction,enforcementSuppressed, content pack matches andenforced; - destructive endpoint enforcement for USB write-block and print cancel is intentionally not enabled during pilot hardening: Rust emits equivalent audit/incident semantics and suppresses unsafe block actions unless a separate enforcement decision is made;
- incident screenshot policy remains: screenshots only for DLP events.
- current status: live Rust primary through
file-operations-collector.ps1- current status: live Rust primary through
aw-windows-telemetry.exe file-operations-collector; - bounded filesystem watcher, operation schema, queue/spool and create/rename/delete smoke are verified;
- per-session queue/state/log files are used, so RDP sessions do not share one state file;
- legacy PowerShell remains installed only as rollback/reference.
- current status: live Rust primary through
email-outbound-collector.ps1- metadata-only parity;
- Outlook/SMTP mode behavior preserved;
- no content interception beyond current documented behavior.
dlp-policy-client.ps1- Rust policy fetch/cache;
- strict validation;
- safe fallback to last known good policy.
Shadow-mode:
- Rust collector writes
source=<rust-component>andmode=shadow; - PowerShell remains primary during comparison;
- compare event counts, schema, timestamps, severity, policy hits and evidence links for at least several collection cycles.
Gate:
- no duplicate management conclusions in portal;
- event schema compatible with current AW/DLP consumers;
- no stale buckets introduced;
- no uncontrolled screenshot capture;
- Rust collector survives AW API outage by spooling and later flushing.
Phase 4. Guard, service wrapper и recovery
Цель: заменить PowerShell, который управляет процессами и восстановлением.
Компоненты:
aw-standalone-service.ps1;aw-collector-guard.ps1;hardening-recovery.ps1;rebuild-worktime-tasks.ps1;fix-session-watchers.ps1;cleanup-disc-sessions.ps1.
Действия:
- Сделать Rust Windows service wrapper:
- supervises configured collectors;
- records child process state;
- no hidden PowerShell spawn in normal mode.
- Сделать Rust guard/recovery:
- allowlist actions only;
- lock file;
- cooldown;
- dry-run by default for destructive or repair actions;
- audit entry for every change.
- Перевести rebuild/fix/cleanup в subcommands одного maintenance EXE.
Gate:
- controlled restart of one collector works;
- stale collector detection matches old guard;
- recovery cannot restart arbitrary process/service;
- rollback restores PowerShell guard/service within one operator action.
Phase 5. Install/deploy/validate
Цель: install-kit перестает запускать PowerShell как штатный bootstrap.
Компоненты:
install-standalone-service.ps1;install-collector-guard-service.ps1;install-dlp-client.ps1;deploy-single-user.ps1;deploy-domain-users.ps1;deploy-ensemble.ps1;validate-deployment.ps1;migrate-awatch-rus-paths.ps1;- InnoSetup
AWatch-rus-InnoSetup.iss; - Ansible Windows playbooks/group vars.
Действия:
- Создать Rust bootstrap/installer EXE:
- install/update service;
- install/update scheduled tasks;
- write config atomically;
- backup previous config/tasks;
- emit JSON validation report.
- Перевести validation в Rust:
- task actions;
- service status;
- bucket freshness;
- file permissions;
- rust binary version matrix;
- no PowerShell runtime task check.
- Обновить InnoSetup:
- package
*.exe; - run Rust bootstrap;
- keep
.ps1out of normal install payload after stabilization.
- package
- Обновить Ansible:
- deploy EXE;
- configure task/service actions to EXE;
- remove default
.ps1paths from bot/env after migration.
Gate:
- clean install on test Windows host;
- upgrade from PowerShell install to Rust install;
- rollback to previous package;
validate-deploymentJSON is consumed by CI/operator without parsing human text;- install-kit verification confirms no
powershell.exein primary install action.
Phase 6. Ops-only хвост
Цель: убрать одноразовые PowerShell helpers.
Компоненты:
audit-cryptopro.ps1;run-user1-probe.ps1;scripts/powershell/detmir-powershell-profile.ps1;.pssa_run.ps1.
Решение:
audit-cryptopro.ps1-> Rust audit CLI;run-user1-probe.ps1-> Rust diagnostic probe or remove if obsolete;- operator PowerShell profile is not production runtime and can be retired after Rust/SSH operator commands exist;
.pssa_run.ps1removed when no product PowerShell remains.
Gate:
- no production task/service depends on these helpers;
- docs no longer instruct operator to run PowerShell for routine checks;
- one emergency manual path remains documented, but not packaged as runtime.
Phase 7. Decommission
Цель: убрать PowerShell from product surface.
Действия:
- Remove
.ps1from install-kit file list. - Remove
powershell.exeinstaller run action. - Remove default
.ps1paths from Ansible/bot env. - Update architecture/docs:
- Windows collectors are Rust EXE;
- PowerShell no longer prerequisite for runtime;
- rollback history documented separately.
- Run tracked-file hygiene scan for public docs.
Gate:
rg -n "powershell\\.exe|\\.ps1|PowerShell" windows ansible docs scripts README.md
Expected result:
- only historical notes, explicit rollback docs, or non-runtime examples remain;
- no install-kit primary action launches PowerShell;
- no AWatch-rus Scheduled Task action launches PowerShell in live validation.
7. Rollout по хостам
Порядок раскатки:
- Local build host:
- build Windows EXE;
- artifact check;
- installer dry-run.
- Test Windows/RDP host:
- install Rust EXE side-by-side;
- shadow-mode collectors;
- compare with PowerShell.
- Canary production Windows/RDP host:
- one host, one business day;
- monitor bucket freshness, DLP incidents, 1C upload, evidence upload.
- Remaining Windows hosts:
- staged batches;
- no more than one failure domain at a time.
- AW server / Proxmox / gateway:
- update Ansible/bot references;
- verify server Rust services remain active;
- verify ClickHouse ingest and portal health.
- Install-kit:
- publish Rust-first package;
- keep previous package as rollback artifact.
8. Acceptance gates
Local gates:
cd adk-rust
cargo fmt --all -- --check
cargo test --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo build --workspace --release
cargo build --release --target x86_64-pc-windows-gnu -p awatch-agent-rs -p aw-windows-telemetry
Repository gates:
scripts/check_detmir_rust_release_artifacts.sh
scripts/verify_innosetup_installer.sh
git diff --check
Windows gates:
Get-ScheduledTask | Where-Object {
$_.TaskName -like 'ActivityWatch*' -or $_.TaskName -like 'AWatch*'
} | Select-Object TaskName,TaskPath,State
Expected:
- task actions point to Rust EXE for migrated components;
- no migrated component runs
powershell.exe; - logs are fresh;
- spool is empty or draining;
- AW buckets are fresh;
- DLP evidence sync only uploads DLP incident evidence;
- 1C upload does not copy screenshots.
Server gates:
detmir-status --json
detmir-check --json
systemctl --failed --no-pager
systemctl list-timers aw-1c-ingest.timer --no-pager
Expected:
- AWatch-rus severity is OK or explained WARN;
- no failed Rust services;
- ClickHouse writer timer is active;
- portal data freshness is acceptable for pilot.
9. Rollback model
До decommission каждая миграция хранит rollback:
- previous EXE/script backup in
switch-backups; - previous task/service definition;
- previous
deployment-config.json; - one-command switch back for canary host;
- rollback reason written to audit log.
Rollback триггеры:
- AW bucket stale/dead after migration;
- DLP event loss or uncontrolled duplicate events;
- evidence upload fails repeatedly and spool grows;
- 1C upload stops producing landing files;
- service/guard restarts loop;
- Windows host shows sustained CPU/RAM regression from new EXE;
- user-visible pilot portal data quality degrades.
10. Риски
| Риск | Где | Снижение риска |
|---|---|---|
| Windows API differs from PowerShell cmdlets | DLP, tasks, Event Log, print, WMI | parity fixtures, canary, schema comparison |
| UIAutomation/browser URL extraction changes behavior | browser collector | shadow-mode and domain count comparison |
| Outlook/SMTP metadata behavior differs | email collector | metadata-only parity, explicit mode tests |
| Privilege mismatch | services/tasks/recovery | install under same account, explicit elevation, validation |
| AV/EDR blocks unsigned EXE | Windows hosts | code signing plan, allowlist, staged rollout |
| Duplicate events during shadow | all collectors | shadow source tags, portal ignores shadow for KPI |
| Rollback not fast enough | production canary | backup tasks/configs, single switch command |
| Public docs leak live contour details | tracked docs | placeholders and git grep hygiene scan |
11. Минимальный порядок ближайших работ
- Зафиксировать live inventory PowerShell usage на тестовом Windows/RDP host.
- Закрепить уже сделанные Rust paths:
- worktime/RDP;
- 1C file upload;
- DLP evidence sync.
- Расширить
aw-windows-telemetry.exe validate-deploymentдо полной parity сvalidate-deployment.ps1, потому что он станет главным gate для следующих замен. - Перенести
aw-standalone-service.ps1иaw-collector-guard.ps1, потому что они управляют runtime collectors. - Стабилизировать P0 runtime collectors после live Rust-primary switch:
- browser domains;
- DLP endpoint signals;
- file operations.
URL/domain extraction и clipboard/USB/print incident semantics закрыты на
уровне Rust code/schema/runtime self-test. Следующий шаг перед удалением
legacy
.ps1- burn-in, canary rollback test и live foreground-browser proof в интерактивной RDP-сессии.
- Перенести deploy/install scripts и InnoSetup primary action.
- Убрать PowerShell paths из Ansible/bot env.
- Удалить
.ps1из install-kit и оставить только historical rollback docs.
12. Итоговая оценка
Миграция реалистична, потому что серверная часть уже Rust-first, а Windows
контур уже имеет два рабочих Rust основания: awatch-agent-rs и
aw-windows-telemetry.exe.
Критичный участок не сервер, а Windows runtime и install-kit:
dlp-endpoint-signals-collector.ps1;browser-domains-native-collector.ps1;aw-collector-guard.ps1;aw-standalone-service.ps1;validate-deployment.ps1;- InnoSetup action that still launches PowerShell.
До пилота не нужно удалять весь PowerShell хвост. Для пилота достаточно закрепить уже работающие Rust-primary paths, не допустить копирования скриншотов в 1C контуре, оставить скриншоты только для DLP events, иметь понятный rollback и честно формулировать границу parity: code/schema/runtime path закрыт, а полный live URL/domain incident proof требует активного foreground browser в интерактивной RDP-сессии. Полное удаление PowerShell из install-kit лучше делать после canary и shadow parity по DLP/browser/file collectors.