diff --git a/.github/.github/FUNDING.yml b/.github/.github/FUNDING.yml new file mode 100644 index 00000000..123d1906 --- /dev/null +++ b/.github/.github/FUNDING.yml @@ -0,0 +1,2 @@ +# These are supported funding model platforms +ko_fi: bunnylab diff --git a/.vscode/.vscode/tasks.json b/.vscode/.vscode/tasks.json new file mode 100644 index 00000000..7765da75 --- /dev/null +++ b/.vscode/.vscode/tasks.json @@ -0,0 +1,56 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Borealis - Engine (Production)", + "type": "shell", + "command": "powershell.exe", + "args": [ + "-NoLogo", + "-NoProfile", + "-ExecutionPolicy", "Bypass", + "-File", "${workspaceFolder}\\Borealis.ps1", + "-EngineProduction" + ], + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Borealis - Engine (Dev)", + "type": "shell", + "command": "powershell.exe", + "args": [ + "-NoLogo", + "-NoProfile", + "-ExecutionPolicy", "Bypass", + "-File", "${workspaceFolder}\\Borealis.ps1", + "-EngineDev" + ], + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Borealis - Agent", + "type": "shell", + "command": "powershell.exe", + "args": [ + "-NoLogo", + "-NoProfile", + "-ExecutionPolicy", "Bypass", + "-File", "${workspaceFolder}\\Borealis.ps1", + "-Agent" + ], + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + } + ] +} diff --git a/Dependencies/Dependencies/7zip/7z.dll b/Dependencies/Dependencies/7zip/7z.dll new file mode 100644 index 00000000..e81e08b9 Binary files /dev/null and b/Dependencies/Dependencies/7zip/7z.dll differ diff --git a/Dependencies/Dependencies/7zip/7z.exe b/Dependencies/Dependencies/7zip/7z.exe new file mode 100644 index 00000000..19961dbe Binary files /dev/null and b/Dependencies/Dependencies/7zip/7z.exe differ diff --git a/Docs/Docs/Codex/BOREALIS_AGENT.md b/Docs/Docs/Codex/BOREALIS_AGENT.md new file mode 100644 index 00000000..7cb6092e --- /dev/null +++ b/Docs/Docs/Codex/BOREALIS_AGENT.md @@ -0,0 +1,35 @@ +# Codex Guide: Borealis Agent + +Use this doc for agent-only work (Borealis agent runtime under `Data/Agent` → `/Agent`). For shared guidance, see `Docs/Codex/SHARED.md`. + +## Scope & Runtime Paths +- Purpose: outbound-only connectivity, device telemetry, scripting, UI helpers. +- Bootstrap: `Borealis.ps1` preps dependencies, activates the agent venv, and co-launches the Engine. +- Edit in `Data/Agent`, not `/Agent`; runtime copies are ephemeral and wiped regularly. + +## Logging +- Primary log: `Agent/Logs/agent.log` with daily rotation to `agent.log.YYYY-MM-DD` (never auto-delete rotated files). +- Subsystems: log to `Agent/Logs/.log` with the same rotation policy. +- Install/diagnostics: `Agent/Logs/install.log`; keep ad-hoc traces (e.g., `system_last.ps1`, ansible) under `Agent/Logs/` to keep runtime state self-contained. +- Troubleshooting: prefix lines with `--`; ask operators whether verbose logging should stay after resolution. + +## Security +- Generates device-wide Ed25519 keys on first launch (`Certificates/Agent/Identity/`; DPAPI on Windows, `chmod 600` elsewhere). +- Refresh/access tokens are encrypted and pinned to the Engine certificate fingerprint; mismatches force re-enrollment. +- Uses dedicated `ssl.SSLContext` seeded with the Engine TLS bundle for REST + Socket.IO traffic. +- Validates script payloads with backend-issued Ed25519 signatures before execution. +- Outbound-only; API/WebSocket calls flow through `AgentHttpClient.ensure_authenticated` for proactive refresh. Logs bootstrap, enrollment, token refresh, and signature events in `Agent/Logs/`. + +## Execution Contexts & Roles +- Auto-discovers roles from `Data/Agent/Roles/`; no loader changes needed. +- Naming: `role_.py` with `ROLE_NAME`, `ROLE_CONTEXTS`, and optional hooks (`register_events`, `on_config`, `stop_all`). +- Standard roles: `role_DeviceInventory.py`, `role_Screenshot.py`, `role_ScriptExec_CURRENTUSER.py`, `role_ScriptExec_SYSTEM.py`, `role_Macro.py`. +- SYSTEM tasks depend on scheduled-task creation rights; failures should surface through Engine logging. + +## Platform Parity +- Windows is the reference. Linux (`Borealis.sh`) lags in venv setup, supervision, and role loading; align Linux before macOS work continues. + +## Ansible Support (Unfinished) +- Agent + Engine scaffolding exists but is unreliable: expect stalled/silent failures, inconsistent recap, missing collections. +- Windows blockers: `ansible.windows.*` usually needs PSRP/WinRM; SYSTEM context lacks loopback remoting guarantees; interpreter paths vary. +- Treat Ansible features as disabled until packaging/controller story is complete. Future direction: credential mgmt, selectable connections, reliable live output/cancel, packaged collections. diff --git a/Docs/Docs/Codex/BOREALIS_ENGINE.md b/Docs/Docs/Codex/BOREALIS_ENGINE.md new file mode 100644 index 00000000..17f5e0a6 --- /dev/null +++ b/Docs/Docs/Codex/BOREALIS_ENGINE.md @@ -0,0 +1,35 @@ +# Codex Guide: Borealis Engine + +Use this doc for Engine work (successor to the legacy server). For shared guidance, see `Docs/Codex/SHARED.md`. + +## Scope & Runtime Paths +- Bootstrap: `Borealis.ps1` launches the Engine and/or Agent. The equivalant bootstrap script exists for Linux when running `Borealis.sh`. +- Edit in `Data/Engine`; runtime copies live under `/Engine` and are discarded every time the engine is launched. + +## Architecture +- Runtime: `Data/Engine/server.py` with NodeJS + Vite for live dev and Flask for production serving/API endpoints. + +## Development Guidelines +- Every Python module under `Data/Engine` or `Engine/Data/Engine` starts with the standard commentary header (purpose + API endpoints). Add the header to any existing module before further edits. + +## Logging +- Primary log: `Engine/Logs/engine.log` with daily rotation (`engine.log.YYYY-MM-DD`); do not auto-delete rotated files. +- Subsystems: `Engine/Logs/.log`; install output to `Engine/Logs/install.log`. +- Keep Engine-specific artifacts within `Engine/Logs/` to preserve the runtime boundary. + +## Security & API Parity +- Mirrors legacy mutual trust: Ed25519 device identities, EdDSA-signed access tokens, pinned Borealis root CA, TLS 1.3-only serving, Authorization headers + service-context markers on every device API. +- Implements DPoP validation, short-lived access tokens (~15 min), SHA-256–hashed refresh tokens (30-day) with explicit reuse errors. +- Enrollment: operator approvals, conflict detection, auditor recording, pruning of expired codes/refresh tokens. +- Background jobs and service adapters maintain compatibility with legacy DB schemas while enabling gradual API takeover. + +## WebUI & WebSocket Migration +- Static/template handling: `Data/Engine/services/WebUI`; deployment copy paths are wired through `Borealis.ps1` with TLS-aware URL generation. +- Stage 6 tasks: migration switch in the legacy server for WebUI delegation and porting device/admin API endpoints into Engine services. +- Stage 7 (queued): `register_realtime` hooks, Engine-side Socket.IO handlers, integration checks, legacy delegation updates. + +## Platform Parity +- Windows is primary target. Keep Engine tooling aligned with the agent experience; Linux packaging must catch up before macOS work resumes. + +## Ansible Support (Shared State) +- Mirrors the agent’s unfinished story: treat orchestration as experimental until packaging, connection management, and logging mature. diff --git a/Docs/Docs/Codex/SHARED.md b/Docs/Docs/Codex/SHARED.md new file mode 100644 index 00000000..9f365150 --- /dev/null +++ b/Docs/Docs/Codex/SHARED.md @@ -0,0 +1,6 @@ +# Codex Guide: Shared Conventions + +Cross-cutting guidance that applies to both Agent and Engine work. Domain-specific rules live in `Docs/Codex/BOREALIS_AGENT.md` and `Docs/Codex/BOREALIS_ENGINE.md`. + +- UI & AG Grid: see `Docs/Codex/USER_INTERFACE.md` for MagicUI styling language and AG Grid patterns (with references to live templates). +- Add further shared topics here (e.g., triage process, security posture deltas) instead of growing `AGENTS.md`. diff --git a/Docs/Docs/Codex/USER_INTERFACE.md b/Docs/Docs/Codex/USER_INTERFACE.md new file mode 100644 index 00000000..732e9559 --- /dev/null +++ b/Docs/Docs/Codex/USER_INTERFACE.md @@ -0,0 +1,35 @@ +# Codex Guide: Shared UI (MagicUI + AG Grid) + +Applies to all Borealis frontends. Use `Data/Engine/web-interface/src/Admin/Page_Template.jsx` as the canonical visual reference (no API/business logic). Keep this doc as the single source of truth for styling rules and AG Grid behavior. + +## Page Template Reference +- Purpose: visual-only baseline for new pages; copy structure but wire your data in real pages. +- Header: small Material icon left of the title, subtitle beneath, utility buttons on the top-right. +- Shell: full-bleed aurora gradient container; avoid gutters on the Paper. +- Selection column (for bulk actions): pinned left, square checkboxes, header checkbox enabled, ~52px fixed width, no menu/sort/resize; rely on AG Grid built-ins. +- Typography/buttons: IBM Plex Sans, gradient primary buttons, rounded corners (~8px), themed Quartz grid wrapper. + +## MagicUI Styling Language (Visual System) +- Aurora shells: gradient backgrounds blending deep navy (#040711) with soft cyan/violet blooms, subtle borders (`rgba(148,163,184,0.35)`), and low, velvety shadows. +- Full-bleed canvas: hero shells run edge-to-edge; inset padding lives inside cards so gradients feel immersive. +- Glass panels: glassmorphic layers (`rgba(15,23,42,0.7)`), rounded 16–24px corners, blurred backdrops, micro borders, optional radial flares for motion. +- Hero storytelling: start views with stat-forward heroes—gradient StatTiles (min 160px) and uppercase pills (HERO_BADGE_SX) summarizing live signals/filters. +- Summary data grids: use AG Grid inside a glass wrapper (two columns Field/Value), matte navy background, no row striping. +- Tile palettes: online cyan→green; stale orange→red; “needs update” violet→cyan; secondary metrics fade from cyan into desaturated steel for consistent hue families. +- Hardware islands: storage/memory/network blocks reuse Quartz theme in rounded glass shells with flat fills; present numeric columns (Capacity/Used/Free/%) to match Device Inventory. +- Action surfaces: control bars live in translucent glass bands; filled dark inputs with cyan hover borders; primary actions are pill-shaped gradients; secondary controls are soft-outline icon buttons. +- Anchored controls: align selectors/utility buttons with grid edges in a single row; reserve glass backdrops for hero sections so content stays flush. +- Buttons & chips: gradient pills for primary CTAs (`linear-gradient(135deg,#34d399,#22d3ee)` success; `#7dd3fc→#c084fc` creation); neutral actions use rounded outlines with `rgba(148,163,184,0.4)` borders and uppercase microcopy. +- Rainbow accents: for creation CTAs, use dark-fill pills with rainbow border gradients + teal halo (shared with Quick Job). +- AG Grid treatment: Quartz theme with matte navy headers, subtle alternating row opacity, cyan/magenta interaction glows, rounded wrappers, soft borders, inset selection glows. +- Overlays/menus: `rgba(8,12,24,0.96)` canvas, blurred backdrops, thin steel borders; bright typography; deep blue glass inputs; cyan confirm, mauve destructive accents. + +## AG Grid Column Behavior (All Tables) +- Auto-size value columns and let the last column absorb remaining width so views span available space. +- Declare `AUTO_SIZE_COLUMNS` near the grid component (exclude the fill column). +- Helper: store the grid API in a ref and call `api.autoSizeColumns(AUTO_SIZE_COLUMNS, true)` inside `requestAnimationFrame` (or `setTimeout(...,0)` fallback); swallow errors because it can run before rows render. +- Hook the helper into both `onGridReady` and a `useEffect` watching the dataset (e.g., `[filteredRows, loading]`); skip while `loading` or when there are zero rows. +- Column defs: apply shared `cellClass: "auto-col-tight"` (or equivalent) to every auto-sized column for consistent padding. Last column keeps the class for styling consistency. +- CSS override: add `& .ag-cell.auto-col-tight { padding-left: 0; padding-right: 0; }` in the theme scope. +- Fill column: last column `{ flex: 1, minWidth: X }` (no width/maxWidth) to stretch when horizontal space remains. +- Example: follow the scaffolding in `Engine/web-interface/src/Scheduling/Scheduled_Jobs_List.jsx` and the structure in `Data/Engine/web-interface/src/Admin/Page_Template.jsx`. diff --git a/Docs/Docs/assemblies.md b/Docs/Docs/assemblies.md new file mode 100644 index 00000000..fb943209 --- /dev/null +++ b/Docs/Docs/assemblies.md @@ -0,0 +1,20 @@ +# Assemblies Runtime Reference + +## Database Layout +- Three SQLite databases live under `Data/Engine/Assemblies` (`official.db`, `community.db`, `user_created.db`) and mirror to `Engine/Assemblies` at runtime. +- Automatic JSON → SQLite imports for the official domain have been retired; the staged `official.db` now serves as the authoritative store unless you invoke a manual sync. +- Payload binaries/json store under `Payloads/` in both staging and runtime directories; the AssemblyCache references payload GUIDs instead of embedding large blobs. +- WAL mode with shared-cache is enabled on every connection; queue flushes copy the refreshed `.db`, `-wal`, and `-shm` files into the runtime mirror. +- `AssemblyCache.describe()` reveals dirty/clean state per assembly, helping operators spot pending writes before shutdown or sync operations. + +## Dev Mode Controls +- User-created domain mutations remain open to authenticated operators; community/official writes require an administrator with Dev Mode enabled. +- Toggle Dev Mode via `POST /api/assemblies/dev-mode/switch` or the Assemblies admin controls; state expires automatically based on the server-side TTL. +- Privileged actions (create/update/delete, cross-domain clone, queue flush, official sync, import into protected domains) emit audit entries under `Engine/Logs/assemblies.log`. +- When Dev Mode is disabled, API responses return `dev_mode_required` to prompt admins to enable overrides before retrying protected mutations. + +## Backup Guidance +- Regularly snapshot `Data/Engine/Assemblies` and `Data/Engine/Assemblies/Payloads` alongside the mirrored runtime copies to preserve both metadata and payload artifacts. +- Include the queue inspection endpoint (`GET /api/assemblies`) in maintenance scripts to verify no dirty entries remain before capturing backups. +- Maintain the staged databases directly; to publish new official assemblies copy the curated `official.db` into `Data/Engine/Assemblies` before restarting the Engine. +- Future automation will extend to scheduled backups and staged restore helpers; until then, ensure filesystem backups capture both SQLite databases and payload directories atomically. diff --git a/Docs/Docs/images/repo_screenshots/Assembly_Editor.png b/Docs/Docs/images/repo_screenshots/Assembly_Editor.png new file mode 100644 index 00000000..1410b387 Binary files /dev/null and b/Docs/Docs/images/repo_screenshots/Assembly_Editor.png differ diff --git a/Docs/Docs/images/repo_screenshots/Assembly_List.png b/Docs/Docs/images/repo_screenshots/Assembly_List.png new file mode 100644 index 00000000..513beb97 Binary files /dev/null and b/Docs/Docs/images/repo_screenshots/Assembly_List.png differ diff --git a/Docs/Docs/images/repo_screenshots/Device_Approval_Queue.png b/Docs/Docs/images/repo_screenshots/Device_Approval_Queue.png new file mode 100644 index 00000000..f72d47d7 Binary files /dev/null and b/Docs/Docs/images/repo_screenshots/Device_Approval_Queue.png differ diff --git a/Docs/Docs/images/repo_screenshots/Device_Details.png b/Docs/Docs/images/repo_screenshots/Device_Details.png new file mode 100644 index 00000000..f8055e11 Binary files /dev/null and b/Docs/Docs/images/repo_screenshots/Device_Details.png differ diff --git a/Docs/Docs/images/repo_screenshots/Device_Enrollment_Codes.png b/Docs/Docs/images/repo_screenshots/Device_Enrollment_Codes.png new file mode 100644 index 00000000..caf6eedb Binary files /dev/null and b/Docs/Docs/images/repo_screenshots/Device_Enrollment_Codes.png differ diff --git a/Docs/Docs/images/repo_screenshots/Device_List.png b/Docs/Docs/images/repo_screenshots/Device_List.png new file mode 100644 index 00000000..c8db0e65 Binary files /dev/null and b/Docs/Docs/images/repo_screenshots/Device_List.png differ diff --git a/Docs/Docs/images/repo_screenshots/Log_Management.png b/Docs/Docs/images/repo_screenshots/Log_Management.png new file mode 100644 index 00000000..6eb90754 Binary files /dev/null and b/Docs/Docs/images/repo_screenshots/Log_Management.png differ diff --git a/Docs/Docs/images/repo_screenshots/Log_Management_Raw.png b/Docs/Docs/images/repo_screenshots/Log_Management_Raw.png new file mode 100644 index 00000000..64d2a22f Binary files /dev/null and b/Docs/Docs/images/repo_screenshots/Log_Management_Raw.png differ diff --git a/Docs/Docs/images/repo_screenshots/Scheduled_Job_History.png b/Docs/Docs/images/repo_screenshots/Scheduled_Job_History.png new file mode 100644 index 00000000..3961425e Binary files /dev/null and b/Docs/Docs/images/repo_screenshots/Scheduled_Job_History.png differ diff --git a/Docs/Docs/images/repo_screenshots/Scheduled_Job_List.png b/Docs/Docs/images/repo_screenshots/Scheduled_Job_List.png new file mode 100644 index 00000000..f6d3d5f2 Binary files /dev/null and b/Docs/Docs/images/repo_screenshots/Scheduled_Job_List.png differ diff --git a/Docs/Docs/images/repo_screenshots/Site_List.png b/Docs/Docs/images/repo_screenshots/Site_List.png new file mode 100644 index 00000000..4ef463e4 Binary files /dev/null and b/Docs/Docs/images/repo_screenshots/Site_List.png differ diff --git a/Docs/Docs/images/repo_screenshots/Workflow_Editor.png b/Docs/Docs/images/repo_screenshots/Workflow_Editor.png new file mode 100644 index 00000000..b6bcd51e Binary files /dev/null and b/Docs/Docs/images/repo_screenshots/Workflow_Editor.png differ diff --git a/Update.ps1 b/Update.ps1 index 069aa37c..cad29122 100644 --- a/Update.ps1 +++ b/Update.ps1 @@ -189,9 +189,41 @@ function Start-AgentScheduledTasks { function Stop-AgentPythonProcesses { param( - [string[]]$ProcessNames = @('python', 'pythonw') + [string[]]$ProcessNames = @('python', 'pythonw'), + [string]$ProjectRoot, + [switch]$SkipEngine = $true ) + $enginePids = @() + $engineRoot = '' + $dataEngineRoot = '' + if ($ProjectRoot) { + try { $engineRoot = (Join-Path $ProjectRoot 'Engine') } catch {} + try { $dataEngineRoot = (Join-Path $ProjectRoot 'Data\Engine') } catch {} + } + + if ($SkipEngine) { + try { + $cims = Get-CimInstance -ClassName Win32_Process -Filter "Name='python.exe' OR Name='pythonw.exe'" -ErrorAction Stop + foreach ($proc in $cims) { + try { + $pid = [int]$proc.ProcessId + } catch { continue } + $cmd = ($proc.CommandLine -as [string]) + $exePath = ($proc.ExecutablePath -as [string]) + $isEngine = $false + foreach ($marker in @($engineRoot, $dataEngineRoot, '\Engine\', '\Data\Engine\', 'Engine\server.py', 'Data\Engine\server.py')) { + if (-not $marker) { continue } + try { + if ($cmd -and $cmd.ToLowerInvariant().Contains($marker.ToLowerInvariant())) { $isEngine = $true; break } + if ($exePath -and $exePath.ToLowerInvariant().Contains($marker.ToLowerInvariant())) { $isEngine = $true; break } + } catch {} + } + if ($isEngine -and ($enginePids -notcontains $pid)) { $enginePids += $pid } + } + } catch {} + } + foreach ($name in ($ProcessNames | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Unique)) { $name = $name.Trim() if (-not $name) { continue } @@ -206,13 +238,29 @@ function Stop-AgentPythonProcesses { foreach ($proc in $processes) { $procId = $null $procName = $null + $procPath = $null try { $procId = $proc.Id $procName = $proc.ProcessName + $procPath = $proc.Path } catch {} if ($procId -eq $null) { continue } + $isEngineProc = $false + try { + if ($enginePids -and ($enginePids -contains $procId)) { $isEngineProc = $true } + foreach ($marker in @($engineRoot, $dataEngineRoot)) { + if (-not $marker) { continue } + if ($procPath -and $procPath.ToLowerInvariant().StartsWith($marker.ToLowerInvariant())) { $isEngineProc = $true; break } + } + } catch {} + + if ($SkipEngine -and $isEngineProc) { + Write-Host "Skipping Engine python process: PID $procId ($procName)" -ForegroundColor Cyan + continue + } + if (-not $procName) { $procName = $name } $stopped = $false @@ -1732,7 +1780,7 @@ function Invoke-BorealisAgentUpdate { } else { Write-UpdateLog "No managed tasks were running when update started." 'DEBUG' } - Run-Step "Updating: Terminate Running Python Processes" { Stop-AgentPythonProcesses } + Run-Step "Updating: Terminate Running Python Processes" { Stop-AgentPythonProcesses -ProjectRoot $scriptDir -SkipEngine } $updateSucceeded = $false try { @@ -1797,4 +1845,4 @@ function Invoke-BorealisAgentUpdate { } } -Invoke-BorealisAgentUpdate \ No newline at end of file +Invoke-BorealisAgentUpdate