From b80a601316ca2e11e0f10baf00bd1997a260a236 Mon Sep 17 00:00:00 2001 From: Cody Rester Date: Sun, 10 May 2026 22:00:54 -0500 Subject: [PATCH] feat: v1.7.0 release --- .gitignore | 6 + CHANGELOG.md | 109 ++- CLAUDE.md | 24 + GUIDES/HTML/PlatformAtlas.html | 281 +++++- GUIDES/PREREQUISITES-CHECKLIST.md | 115 ++- GUIDES/SSH_PRIMARY_RULES_REFERENCE.md | 112 +++ GUIDES/SSH_SETUP_GUIDE.md | 134 +++ GUIDES/USER-GUIDE-INSTALLATION-AND-USAGE.md | 530 +++++++++- GUIDES/USER-GUIDE-READING-THE-REPORT.md | 73 +- QUICKSTART.md | 46 +- README.md | 322 +++++- pyproject.toml | 9 +- src/platform_atlas/RULES_KNOWLEDGEBASE.md | 22 + src/platform_atlas/USER-GUIDE.md | 251 ++++- src/platform_atlas/capture/capture_engine.py | 452 +++++++-- .../capture/collectors/filesystem.py | 31 +- .../capture/collectors/gateway4.py | 6 + .../capture/collectors/gateway5.py | 5 + .../capture/collectors/kubernetes.py | 49 +- .../capture/collectors/manual.py | 331 ++++++- .../capture/collectors/mongo.py | 11 +- .../capture/collectors/redis.py | 10 +- .../capture/collectors/system.py | 5 + .../capture/guided_collector.py | 2 +- src/platform_atlas/capture/log_parser.py | 12 +- src/platform_atlas/capture/models.py | 15 + .../capture/modules_registry.py | 126 ++- src/platform_atlas/capture/ui.py | 2 +- src/platform_atlas/capture/utils.py | 28 +- src/platform_atlas/continuous/__init__.py | 39 + src/platform_atlas/continuous/alerts.py | 199 ++++ src/platform_atlas/continuous/banner.py | 99 ++ src/platform_atlas/continuous/drift.py | 168 ++++ .../continuous/endpoint_planner.py | 129 +++ src/platform_atlas/continuous/engine.py | 312 ++++++ src/platform_atlas/continuous/models.py | 250 +++++ .../continuous/notifications.py | 827 ++++++++++++++++ src/platform_atlas/continuous/os_scheduler.py | 677 +++++++++++++ src/platform_atlas/continuous/policy.py | 126 +++ src/platform_atlas/continuous/runtime.py | 151 +++ src/platform_atlas/continuous/scope.py | 65 ++ src/platform_atlas/continuous/storage.py | 487 ++++++++++ src/platform_atlas/core/_version.py | 2 +- src/platform_atlas/core/architecture_store.py | 300 ++++++ src/platform_atlas/core/cli.py | 561 +++++++++-- src/platform_atlas/core/config.py | 229 ++++- src/platform_atlas/core/context.py | 99 +- src/platform_atlas/core/credentials.py | 249 ++++- src/platform_atlas/core/dashboard.py | 918 +++++++++++------- src/platform_atlas/core/dispatch.py | 12 - src/platform_atlas/core/environment.py | 132 ++- src/platform_atlas/core/exceptions.py | 20 + src/platform_atlas/core/fleet.py | 301 ++++++ src/platform_atlas/core/handlers/__init__.py | 4 +- src/platform_atlas/core/handlers/config.py | 21 +- .../core/handlers/continuous.py | 689 +++++++++++++ src/platform_atlas/core/handlers/customer.py | 192 ---- src/platform_atlas/core/handlers/env.py | 43 +- src/platform_atlas/core/handlers/fleet.py | 158 +++ src/platform_atlas/core/handlers/preflight.py | 27 +- src/platform_atlas/core/handlers/session.py | 455 ++++++--- src/platform_atlas/core/handlers/tier.py | 285 ++++++ src/platform_atlas/core/html_collector.py | 132 ++- src/platform_atlas/core/init_setup.py | 705 ++++++++++++-- src/platform_atlas/core/paths.py | 12 +- src/platform_atlas/core/preflight.py | 103 +- src/platform_atlas/core/rules.py | 93 +- src/platform_atlas/core/ruleset_manager.py | 2 +- src/platform_atlas/core/session_manager.py | 165 +++- src/platform_atlas/core/theme.py | 8 + src/platform_atlas/core/topology.py | 69 +- src/platform_atlas/core/transport.py | 564 +++++++++-- src/platform_atlas/core/utils.py | 31 +- src/platform_atlas/core/whats_new.py | 11 +- .../guides/architecture-form.html | 180 +++- src/platform_atlas/main.py | 19 +- .../pipelines/collectionsizes.json | 685 +++++++++++++ .../pipelines/topworkflows.json | 104 +- src/platform_atlas/reporting/arch_renderer.py | 34 +- .../assets/schemas/report.schema.json | 47 +- .../reporting/assets/templates/arch.html | 100 +- .../reporting/assets/templates/diff.html | 22 + .../assets/templates/operational.html | 73 +- .../reporting/assets/templates/report.html | 274 +++++- .../assets/templates/whats-new-1.7.html | 569 +++++++++++ src/platform_atlas/reporting/diff_engine.py | 52 + .../reporting/operational_engine.py | 113 ++- .../reporting/operational_renderer.py | 20 +- .../reporting/report_renderer.py | 75 +- .../reporting/reporting_engine.py | 4 + .../reporting/webui_viewmodel.py | 716 ++++++++++++++ .../rules/rulesets/20231-master-ruleset.json | 24 +- .../rules/rulesets/p6-master-ruleset.json | 73 +- .../rulesets/profiles/p6-prod-kubernetes.json | 2 +- .../rules/rulesets/rules.schema.json | 9 + src/platform_atlas/sessions/customer_data.py | 146 --- .../validation/extended_validation.py | 80 +- .../validation/validation_engine.py | 87 +- 98 files changed, 15088 insertions(+), 1660 deletions(-) create mode 100644 GUIDES/SSH_PRIMARY_RULES_REFERENCE.md create mode 100644 src/platform_atlas/continuous/__init__.py create mode 100644 src/platform_atlas/continuous/alerts.py create mode 100644 src/platform_atlas/continuous/banner.py create mode 100644 src/platform_atlas/continuous/drift.py create mode 100644 src/platform_atlas/continuous/endpoint_planner.py create mode 100644 src/platform_atlas/continuous/engine.py create mode 100644 src/platform_atlas/continuous/models.py create mode 100644 src/platform_atlas/continuous/notifications.py create mode 100644 src/platform_atlas/continuous/os_scheduler.py create mode 100644 src/platform_atlas/continuous/policy.py create mode 100644 src/platform_atlas/continuous/runtime.py create mode 100644 src/platform_atlas/continuous/scope.py create mode 100644 src/platform_atlas/continuous/storage.py create mode 100644 src/platform_atlas/core/architecture_store.py create mode 100644 src/platform_atlas/core/fleet.py create mode 100644 src/platform_atlas/core/handlers/continuous.py delete mode 100644 src/platform_atlas/core/handlers/customer.py create mode 100644 src/platform_atlas/core/handlers/fleet.py create mode 100644 src/platform_atlas/core/handlers/tier.py create mode 100644 src/platform_atlas/pipelines/collectionsizes.json create mode 100644 src/platform_atlas/reporting/assets/templates/whats-new-1.7.html create mode 100644 src/platform_atlas/reporting/webui_viewmodel.py delete mode 100644 src/platform_atlas/sessions/customer_data.py diff --git a/.gitignore b/.gitignore index a9cc797..79a421a 100644 --- a/.gitignore +++ b/.gitignore @@ -99,6 +99,12 @@ poetry.toml tests/ BACKUP/ design/ +webui/ +scripts/ + +# Vendored Tailwind v4 standalone CLI binary — platform-specific, large, +# downloaded by scripts/tailwind-install.sh on each dev machine. +bin/ # Claude .claude/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8761aae..515d375 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,117 @@ -# Changelog +# Changelog — Platform Atlas (CLI / core) -All notable changes to this project will be documented in this file. +All notable changes to the `platform-atlas` package are documented here. +WebUI changes ship in a separate wheel (`platform-atlas-webui`) and are +documented in [`webui/CHANGELOG.md`](webui/CHANGELOG.md). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). --- +## [1.7.0] - 2026-05-03 + +> **Note:** WebUI changes (themes, daemon mode, security hardening, route fixes, etc.) ship in [`platform-atlas-webui` 1.0.0](webui/CHANGELOG.md), released alongside this version. + +### Added + +- **Fleet dashboard** — multi-environment compliance overview from local cache (read-only, never triggers captures): `platform-atlas fleet status` (with `--json`) showing per-env tier, last session age, pass rate, continuous-audit state, and unacked alerts (also surfaced at `/fleet` in the WebUI) +- **Outbound drift notifications** — Slack incoming webhooks and generic JSON webhooks (with optional HMAC-SHA256 signing via `X-Atlas-Signature`). Per-environment channels persisted on the env overlay, fired only on alert-state transitions (new alerts and re-opened acked alerts) so persistent unacked drift doesn't spam every cycle. CLI: `continuous-audit notify add|list|remove|test` +- **Continuous-audit robustness pass** — fcntl-locked atomic appends + 10MB rotation on `events.ndjson`; centralized atomic-write helper used across runs, status, and alerts; `prune_runs` now repoints `latest.json` if the pointed-at run was pruned; `make_run_id` gains a microsecond + nonce suffix to prevent collisions; drift comparator handles unhashable list items, cross-type coercion, and treats `True != 1` at every nesting level; `previous_unreadable` flag surfaced in run reports and the heartbeat when prior runs exist on disk but can't be read; endpoint planner warns on malformed/unmapped `platform.*` paths; macOS launchd install confirms plist-on-disk before bootstrapping +- **Standard / Extended tier system** — Atlas now ships with two distinct audit modes: + - **Standard** — Platform OAuth + optional IAG4 API (~54 rules). No SSH, MongoDB, or Redis required. Designed for quick application-layer audits or environments where infrastructure access is restricted. + - **Extended** — Full infrastructure audit via SSH, MongoDB, Redis, Kubernetes, and Gateways (~107 rules). The default for all installs upgraded from 1.6.x. +- **Tier CLI commands** — `tier show`, `tier set [standard|extended]`, `tier upgrade`, `tier downgrade` for managing the active tier interactively or non-interactively +- **`--tier` global flag** — Override the active tier for a single command without changing the persisted setting +- Sessions now bind a tier at creation time (alongside environment, ruleset, and profile) +- Cross-tier session diffs are flagged with a notice banner in the diff report +- Three-layer tier enforcement: module registry pruning, `require_extended()` collector guards, and tier-aware credential store (Extended-only keys silently return `None` in Standard and raise on write) +- **Continuous Audit** — scheduled drift monitor that re-runs a Platform-OAuth-only capture against the active ruleset and surfaces changed observed values as alerts: + - Per-environment enable/disable; requires a successful `run-once` test before enabling + - OS-level scheduling installed on enable so runs survive process restarts: `systemctl --user` timer on Linux, `launchctl` agent on macOS; in-process scheduler defers when an OS scheduler is active + - Endpoint set pruned to only what the active ruleset references; capture is locked to Platform OAuth regardless of tier + - Bare JSON report written to `~/.atlas/continuous//runs/.json` for external alert systems; per-rule `previous → current` drift attached inline + - Append-only `events.ndjson` timeline + `alerts.json` aggregate state with ack / ack-all; acked alerts re-open if drift recurs + - CLI: `continuous-audit run-once|status|alerts|ack|enable|disable`; banner printed at the top of every invocation while enabled +- **Continuous-audit alert policy + watchlist** — `alert_policy` (`any` default, `regression` to alert only on PASS→FAIL) and a rule-number `watchlist` filter applied at alert/notification time; full drift history still goes to `events.ndjson`. CLI: `continuous-audit policy ` and `continuous-audit watch add|remove|list|clear` +- **What's New page** — On first run after upgrading, Atlas shows a version-specific upgrade summary in the terminal and opens a detailed HTML page in the browser +- **Kubernetes kubectl rule fallbacks** — 13 rules in the P6 Master Ruleset now have an `alt_path` that Atlas uses when the primary data source (Platform OAuth API) is unavailable, enabling fuller coverage on Kubernetes-only deployments where SSH, MongoDB, and Redis are not accessible: + - **10 rules via pod `printenv`** (`ITENTIAL_*` env vars → `platform.config_file.*`): Platform Default User, Platform Core Logging Level, Server ID, Mongo Auth Enabled, Mongo TLS Enabled, Log Max Files, Log File Max Size, Webserver HTTPS Enabled, Webserver HTTP Enabled, Webserver Timeout + - **3 rules via kubectl system data** (`system.kubernetes.*`): Platform Version (from `release_metadata.json`), Node Version (from `node --version`), Gateway Manager Version Check (from `app-ag_manager/package.json`) +- **Node.js version collection** — `KubernetesCollector` now runs `kubectl exec -- node --version` during system info enhancement and stores the result at `system.kubernetes.node_version`, making the Node Version rule evaluable on Kubernetes without the Platform OAuth API +- **kubectl debug logging** — every `kubectl` command now logs the full invocation, exit code, elapsed time, and any stderr to `~/.atlas/atlas.log` at DEBUG level; higher-level collection phases (preflight probe, pod search, system enhancement, platform version, service collection, kubectl env) each emit a phase-entry log line +- **ControlMaster SSH transport** — new `control_master` transport mode lets Atlas piggyback on an existing OpenSSH ControlMaster session with zero credentials. Designed for environments where direct SSH key access is not available — most notably CyberArk PSMP (Privileged Session Manager Proxy) deployments where all privileged SSH is routed through a PAM gateway and target credentials are vault-managed. The user opens one master connection per target node before running Atlas (`ssh -M -S -N `); Atlas multiplexes on those sessions with no MFA interaction, no key configuration, and no knowledge of the PAM mechanism. Full parity with SSHTransport: remote path validation, symlink rejection, allowed-prefix enforcement, size cap, and a passwordless-sudo fallback for files owned by root. Selected interactively during topology setup — the existing SSH (recommended) and Local options are unchanged. +- **Local transport for Platform server** (Extended mode) — the topology setup wizard now offers a `Local` option when configuring the Platform (IAP) node. When selected, Atlas reads config files and runs system commands directly via the local filesystem instead of SSH — intended for environments where Atlas is installed on the Platform server itself to bypass restrictive SSH access. All other nodes (MongoDB, Redis, IAG) remain SSH-connected. Never the default; SSH is still recommended. +- **PLAT-048 — Template Builder Execution Timeout** — new rule that checks the `templateExecutionTimeout` setting on the Template Builder application (`@itential/app-template_builder`). Marks Non-Compliant when the value is present and exceeds 10000ms; skipped automatically when Template Builder is not installed or the setting is absent. + +### Changed + +- Fresh installs default to **Standard** tier; upgrades from 1.6.x default to **Extended** (preserving existing behavior) +- Standard mode reports do not show the partial-capture obelisk (†) — a limited module set is the full expected capture in Standard, not a deficiency +- `--customer` CLI flag removed (was deprecated in 1.6.4) + +### Fixed + +- Capture job reporting `SUCCEEDED` when no modules ran — target initialization errors (e.g. missing credentials) were silently swallowed in `_resolve_modules`; errors are now surfaced and the job correctly fails +- Validation `modules_ran` filter never fired — was reading `metadata.modules_ran` instead of `_atlas.metadata.modules_ran`, so rules for non-captured categories were evaluated and produced misleading SKIP messages +- Cross-tier diff banner never showed — `_rehydrate_attrs` did not restore `df.attrs["tier"]` from the capture JSON; both sides defaulted to "extended" +- Capture file could be left half-written on SIGINT / disk-full — capture and parquet writes now use `tempfile + os.replace` for atomicity +- Validation crashed on list items with non-string `name` (e.g. `None`, integers) — values are now coerced to `str` before path matching +- `SSHRetryConfig` was defined but unused — `SSHTransport` now accepts a `retry=` argument and retries `OSError`s only (auth and protocol errors still fail fast) +- Concurrent `engine.run_once` invocations from the in-process scheduler, OS timer (systemd / launchd), and CLI no longer race — per-env `flock` serializes the OAuth fetch, drift detection, alert state update, and `latest.json` swap +- `alerts.json` read-modify-write is now flock'd — concurrent ack / ack-all across CLI and WebUI no longer lose transitions +- systemd unit files now double-quote env names — environments with spaces (e.g. `Acme Prod`) no longer produce a broken `ExecStart` or `Environment=` line +- Notification dispatch caps events per payload (25 webhook / 10 Slack) and honors HTTP 429 `Retry-After` (capped at 30 s) — large drift bursts no longer stall the engine on a slow receiver +- `runtime._write_raw` switched to `tempfile.mkstemp` — concurrent env-overlay writes can no longer clobber each other's tempfile +- `events.ndjson` rotation rewritten with `collections.deque(maxlen=N)` — O(1) eviction in place of the previous O(n²) `list.pop(0)` loop +- `latest.json` symlink target now verified to resolve under `runs/` before being followed +- Notification dispatch error logs scrub URL and bare-IP substrings before logging — Slack webhook URLs and internal hostnames in receiver responses no longer reach the audit log +- systemd timer no longer uses `Persistent=true` and adds `RandomizedDelaySec=120` — long-downtime reboots no longer fire a burst of catch-up runs +- Corrupt `alerts.json` is renamed to `alerts.json.corrupt-` before the empty state takes over — historical alert data is recoverable instead of silently overwritten +- Environment edit crashed with `'tuple' object has no attribute 'get'` — `ask_deployment()` returns a `(mode, k8s_meta)` tuple; both callers in `env.py` / `config.py` now destructure it and persist the k8s metadata +- Standard / Extended init wizard double-prompted for `organization_name` on existing installs — now silently inherits from caller or `~/.atlas/config.json` +- Architecture HTML form did not pre-fill `organization_name` — `html_collector` now passes `?org=…` and the form reapplies it (and the saved `org-`/`legacy-` payload) on load +- MTU "Other" had no free-text path — added `mtu_size_other` to the form, schema, and CLI prompt; reports render the custom value +- `platform_logs` collection failed silently when logs lived outside the default path — new `log_path_override` config field; capture engine retries the collector with the override after a failed first pass +- Report filter pills showed mismatched counts when the active rule filter excluded rows — `allStats` now counts all rows and pill recount uses a shared `countBuckets()` helper + +### Vault credential backend improvements + +- **Token TTL introspection** — after any Vault auth method succeeds, Atlas calls `lookup_self()` to capture the token's remaining TTL and renewability; surfaced in the CLI wizard and `config credentials` +- **Automatic token refresh** — `VaultBackend` transparently re-authenticates when the token has less than 5 minutes remaining, with no user action required: + - `APPROLE` — calls `login()` again with the stored `role_id` and `secret_id`; supports dynamic short-lived tokens (1h, 24h TTL) set on the Vault role by the admin + - `TOKEN_FILE` — re-reads the Vault Agent sink file for a fresh token + - `TOKEN_ENV` — re-reads `VAULT_TOKEN` from the environment + - `TOKEN` (renewable) — calls `renew_self()` + - `APPROLE_WRAPPED` / non-renewable `TOKEN` — raises a clear error; these cannot be automatically refreshed +- Thread-safe refresh via double-checked locking — concurrent callers cannot stampede Vault during a refresh +- `revoke_token()` method on `VaultBackend` for explicit cleanup at session end +- `TOKEN` auth now raises immediately at connect time if the token has fewer than 60 seconds remaining + +### Security + +- Continuous-audit notifications now ship rule identity only (number, name, severity, alert ID); previous/current drift values stay local so a misconfigured Slack/webhook channel cannot exfiltrate captured Platform secrets +- Webhook URLs blocked from pointing at private, loopback, link-local, or cloud-metadata addresses (`127.0.0.0/8`, RFC1918, `169.254.0.0/16`, etc.); DNS-resolved at validation time so domains that resolve to private space are also rejected; opt-out via `ATLAS_ALLOW_PRIVATE_WEBHOOKS=1` +- Slack webhook URLs, HMAC signing secrets, and custom headers now persist in the OS keyring under `platform-atlas/` instead of plaintext env JSON; legacy channels migrate transparently on first read +- Path-traversal defense in the continuous-audit storage and runtime layers — env names containing `..`, `/`, or `\\` are rejected before constructing any path under `~/.atlas/continuous/` or `~/.atlas/environments/` +- `~/.atlas/continuous/**` files (run reports, `alerts.json`, `events.ndjson`, `status.json`) and env overlay JSON files are now written with mode `0o600` + +### Performance + +- Capture collectors now run in parallel across targets (capped at 8 worker threads) — multi-node topologies where each target was previously waited on serially see roughly N× wall-clock improvement +- SSH file reads use the SFTP `lstat` size directly instead of running a separate `stat -c %s` exec channel — saves ~1 round trip per file (~50–150 ms on high-RTT links) + +### Dependencies + +- `paramiko` updated to 5.0.0 +- `rich-argparse` updated to 1.8.0 +- `rich` updated to 15.0.0 +- `pyarrow` updated to 24.0.0 +- `packaging` updated to 26.2 +- `urllib3` updated to 2.7.0 + +--- + ## [1.6.4] - 2026-05-01 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index 9ac272b..2069a1e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -77,6 +77,30 @@ bandit -r src/platform_atlas/ --skip B105,B106 ### Core Concepts +**Tiers** (1.7+) split Atlas into two productized modes: + +- **Standard** — application-only audit via Platform OAuth + optional IAG4 API token. + ~54 rules across the `platform` and `gateway4` categories. No SSH, no MongoDB, no Redis. + Default for fresh 1.7 installs. +- **Extended** — full infrastructure audit. Adds the SSH/Mongo/Redis/IAG/system/filesystem/ + Kubernetes collectors. ~107 rules. Default for installs upgraded from 1.6.x (migration + shim preserves the existing experience). + +Three independent defenses enforce the Standard boundary: + +1. **Registry pruning** — `capture/modules_registry.py::_build_modules_standard` returns + only `platform` + `gateway4_api` modules. +2. **`require_extended()` guards** — every Extended-only collector and `transport.py`'s SSH + branch call this in `__init__` / `from_config` so any accidental Standard invocation + raises `TierViolationError` before any network connection is attempted. +3. **Tier-aware credential store** — `EXTENDED_ONLY_KEYS` in `credentials.py` are silently + `None` on read in Standard and raise on write. + +Rule filtering happens in `rules.py` before evaluation. Tier resolution order: +`--tier` flag → `ATLAS_TIER` env var → environment overlay → config → default. +Sessions bind tier at create time alongside ruleset/environment — switching sessions +atomically restores the full context. + **Sessions** are the primary unit of work. Each session binds an environment, ruleset, and profile at creation time. Switching sessions atomically restores all three, ensuring audit consistency. Session files live at `~/.atlas/sessions//`: diff --git a/GUIDES/HTML/PlatformAtlas.html b/GUIDES/HTML/PlatformAtlas.html index 69816cf..82f3c16 100644 --- a/GUIDES/HTML/PlatformAtlas.html +++ b/GUIDES/HTML/PlatformAtlas.html @@ -3545,8 +3545,23 @@

Common commands

platform-atlas initFirst-time setup wizard
platform-atlas env createAdd a new environment
platform-atlas env switch <name>Switch active environment
+
platform-atlas tier set extendedChoose Standard or Extended tier
platform-atlas preflightVerify connectivity
+
+
Continuous Audit
+
platform-atlas continuous-audit run-onceRun a single drift-check capture
+
platform-atlas continuous-audit enableSchedule recurring runs (systemd / launchd)
+
platform-atlas continuous-audit alertsList unacked drift alerts
+
platform-atlas fleet statusAll environments at a glance
+
+
+
WebUI
+
platform-atlas-webuiStart the browser interface (local only)
+
platform-atlas-webui --daemonDetach and run in the background
+
platform-atlas-webui status|restart|stopDaemon control
+
platform-atlas-webui login-urlMint a fresh login URL
+
Audit Workflow
platform-atlas session createCreate a new audit session
@@ -3575,7 +3590,7 @@

Common commands

-

Atlas is designed for both Itential Customer Success teams running quarterly health checks and customers who want to perform self-service validation at any time. Once you're set up, a full audit is just two commands: create a session, then run it.

+

Atlas is designed for both Itential Customer Success teams running quarterly health checks and customers who want to perform self-service validation at any time. Once you're set up, a full audit is just two commands: create a session, then run it. v1.7 also ships an optional WebUI companion package that exposes the same workflow in a local-only browser interface — see the section below.

+ + + +
+

Standard & Extended Tiers (new in v1.7)

+

Atlas now ships with two distinct audit modes. You pick the tier once and it applies until you change it — sessions remember the tier they were created under, so cross-tier comparisons stay honest.

+ +
+
+

Standard

+

~55 rules. Platform OAuth + Gateway 4 API only. No SSH, no MongoDB, no Redis. Set up in five minutes if you have a Platform URI and OAuth credentials.

+

Use it for quick application-layer audits, environments where infrastructure access is restricted, or as a pre-flight before requesting full Extended access.

+
+
+

Extended

+

~108 rules. Full infrastructure: SSH into every server, MongoDB and Redis configuration, Kubernetes via kubectl, Gateway 4 / 5. Default for upgrades from 1.6.x.

+

Use it for formal quarterly health assessments and any environment where you have the credentials and access needed.

+
+
+ +
# Inspect or change the active tier
+platform-atlas tier show
+platform-atlas tier set standard
+platform-atlas tier set extended
+
+# Override per-command without touching the persisted setting
+platform-atlas --tier standard preflight
+ +
+ +
DefaultsFresh installs start in Standard. Upgrades from 1.6.x stay on Extended automatically — nothing changes in your existing workflow unless you opt in.
+

Requirements

-

Atlas is a Python CLI tool that runs on the machine you use to connect to your IAP environment — typically your workstation or a jump host with network access to your servers.

+

Atlas is a Python CLI tool that runs on the machine you use to connect to your IAP environment — typically your workstation or a jump host with network access to your servers. What you need depends on which tier you'll run.

+ +

Always required

  • Python 3.11 or later
  • +
  • A Platform OAuth service account with read-only API access (apiread:Adapters, apiread:Health, etc.)
  • +
  • An OS keyring backend, or HashiCorp Vault with a KV v2 secrets engine
  • +
+ +

Standard tier — only the above

+

If you only intend to run Standard audits, you're done. No SSH or database credentials needed.

+ +

Extended tier — additional

+
  • SSH access to your IAP, MongoDB, and Redis nodes (key-based authentication recommended)
  • A MongoDB user with clusterMonitor on admin and read on the Platform database
  • A Redis user with +config|get, +info, +acl, +ping, +role ACL permissions
  • -
  • A Platform OAuth service account with read-only API access (apiread:Adapters, apiread:Health, etc.)
  • -
  • An OS keyring backend, or HashiCorp Vault with a KV v2 secrets engine
+

If direct SSH to the Platform server is blocked (CyberArk PSMP, etc.), use the new ControlMaster transport — see the SSH_SETUP_GUIDE.md companion guide. If Atlas itself is installed on the Platform server, use the Local transport for the IAP node and SSH for everything else.

+
Install on your workstationAtlas works best installed on a workstation PC that has remote access to your IAP environment. It doesn't need to be on the same machine as IAP itself.
@@ -3716,14 +3774,14 @@

Install from a wheel file

source atlas-venv/bin/activate # Windows: atlas-venv\Scripts\activate # Install the wheel -pip install platform_atlas-1.6-py3-none-any.whl +pip install platform_atlas-1.7.0-py3-none-any.whl # Verify it works platform-atlas --version
-
You're installedYou should see a version string like platform-atlas 1.6. If you get "command not found", make sure the virtual environment is active or that ~/.local/bin is in your PATH.
+
You're installedYou should see a version string like platform-atlas 1.7.0. If you get "command not found", make sure the virtual environment is active or that ~/.local/bin is in your PATH.

Headless Linux Setup

@@ -3740,9 +3798,16 @@

Headless Linux Setup

default-keyring=keyrings.alt.file.EncryptedKeyring EOF

Alternatively, use HashiCorp Vault as your credential backend — it bypasses the keyring entirely.

+ +

Optional: WebUI

+

To use the optional browser-based interface, install the second wheel alongside the core:

+
pip install platform_atlas_webui-1.7.0-py3-none-any.whl
+platform-atlas-webui
+

The WebUI shares ~/.atlas/ with the CLI — no separate setup. See the WebUI section for the security model, daemon mode, and a tour of the pages.

+

First-Time Setup

The first time you run platform-atlas with no configuration, it launches an interactive setup wizard. You can also run it at any time with:

@@ -3770,7 +3835,7 @@

First-Time Setup

  • Credential storage — Choose between the OS keyring (default) and HashiCorp Vault. See the Vault section for details if your organization manages secrets in Vault.
  • Connection credentials — Your Platform URI, OAuth client ID, Platform client secret, MongoDB URI, and Redis URI. All stored securely in your chosen backend, never in config files.
  • -
  • Deployment topology — Tell Atlas how your environment is laid out: Standalone (one IAP, one Mongo, one Redis), HA2 (multiple nodes), or Custom. You'll configure SSH access (user, key file, port) for each server.
  • +
  • Deployment topology — Tell Atlas how your environment is laid out: Standalone, HA2 (multiple nodes), Kubernetes (the wizard reads values.yaml directly), or Custom. For each server you pick a transport: SSH (default, key-based), ControlMaster for the IAP node when direct SSH is blocked by CyberArk PSMP / a jump host, or Local when Atlas itself is installed on the IAP server. SSH targets ask for user, key file, and port — see the SSH_SETUP_GUIDE.md companion guide for details on every transport.
@@ -4249,12 +4314,71 @@

Config commands

+

Tier commands (new in v1.7)

+
+ + + + + + + + + +
CommandDescription
tier showDisplay the active tier
tier set [standard|extended]Switch tiers
tier upgradeGuided Standard → Extended with explanations
tier downgradeGuided Extended → Standard with explanations
--tier <name>One-shot override without changing the persisted setting
+
+ +

Continuous Audit commands (new in v1.7)

+
+ + + + + + + + + + + + + +
CommandDescription
continuous-audit run-onceRun a single drift-check capture on demand
continuous-audit enableInstall systemd-user / launchd timer for the active env
continuous-audit disableRemove the OS scheduler entry
continuous-audit statusLast-run, next-scheduled, alert counts
continuous-audit alertsList unacked alerts
continuous-audit ack <id> / ack --allAcknowledge alerts
continuous-audit policy [any|regression]Choose alerting policy
continuous-audit watch add|remove|list|clearManage the rule-number watchlist
continuous-audit notify add|list|test|removeSlack / webhook channels for alert transitions
+
+ +

Fleet commands (new in v1.7)

+
+ + + + + + +
CommandDescription
fleet statusOverview of every env: tier, last-session age, pass rate, continuous-audit state, unacked alerts
fleet status --jsonSame data as JSON for piping into jq / monitoring
+
+ +

WebUI commands (separate package)

+
+ + + + + + + + + + +
CommandDescription
platform-atlas-webuiStart the WebUI in the foreground; opens browser at the login URL
platform-atlas-webui --daemonDetach and run in the background; PID at ~/.atlas/webui.pid
platform-atlas-webui status|restart|stopDaemon control
platform-atlas-webui login-urlMint a fresh nonce-signed login URL
platform-atlas-webui --reset-tlsRegenerate the self-signed TLS cert
platform-atlas-webui --reset-tokenRotate the OS-user token (invalidates browser sessions)
+
+

Other commands

+ @@ -4265,6 +4389,115 @@

Other commands

+ +
+

Continuous Audit & Fleet (new in v1.7)

+

A formal session run is a point-in-time snapshot. Continuous Audit fills the gap between formal runs by re-executing a Platform-OAuth-only capture against the active ruleset on a schedule and recording any rule whose observed value drifted from the prior run as an alert. Captures are locked to Platform OAuth regardless of tier, so it works in Standard and Extended without any extra access.

+ +

Getting started

+

Before you enable the schedule, run one capture by hand to confirm the OAuth path works and seed the prior-run state:

+
platform-atlas continuous-audit run-once
+platform-atlas continuous-audit enable     # installs systemd-user / launchd timer
+platform-atlas continuous-audit status     # last run, next run, alert counts
+ +

Alerts and ack

+

When a rule's observed value changes between runs, Atlas opens an alert. Alerts persist until you ack them, and re-open if drift recurs after an ack.

+
platform-atlas continuous-audit alerts
+platform-atlas continuous-audit ack <alert-id>
+platform-atlas continuous-audit ack --all
+ +

Policy and watchlist

+

Default policy is any — every state change is an alert. Switch to regression when you only want PASS → FAIL transitions. The watchlist filters notifications and the alert UI down to specific rule numbers; everything still goes to the events.ndjson timeline.

+
platform-atlas continuous-audit policy regression
+platform-atlas continuous-audit watch add 12 47 102
+platform-atlas continuous-audit watch list
+ +

Notifications

+

Per-environment Slack and webhook channels deliver alert-state transitions. Notifications fire only on newly opened alerts and re-opened alerts after ack — persistent unacked drift won't spam.

+
platform-atlas continuous-audit notify add slack
+platform-atlas continuous-audit notify add webhook    # with optional HMAC-SHA256 signing
+platform-atlas continuous-audit notify test <id>
+
+ +
Payloads carry rule identity onlyNotification bodies include the rule number, name, severity, and alert ID — never the previous or current observed values. A misconfigured Slack/webhook channel cannot exfiltrate captured Platform secrets.
+
+ +

Fleet view

+

The fleet command is a read-only overview of every environment Atlas knows about. It reads the local cache only — it never triggers a capture or hits the Platform API.

+
platform-atlas fleet status
+platform-atlas fleet status --json
+

For each environment you'll see the current tier, most recent session and its age, pass rate, continuous-audit state, and unacked alert count. The same data renders at /fleet in the WebUI as a sortable card grid.

+
+ +
+ + +
+

WebUI (new optional package)

+

The optional platform-atlas-webui 1.0.0 wheel is a browser-based interface for the same workflow you use in the CLI. It's a thin presentation layer over the same engines — both interfaces read and write the same ~/.atlas/ directory; what you do in one shows up in the other immediately.

+ +

The WebUI is local-only — it serves on localhost over self-signed TLS and authenticates the OS user that started it. There is no remote / multi-tenant deployment mode.

+ +

Installing and first launch

+
pip install platform_atlas_webui-1.7.0-py3-none-any.whl
+platform-atlas-webui
+

On first launch Atlas writes a self-signed TLS certificate to ~/.atlas/.webui-cert.pem, prints its SHA-256 fingerprint, and opens your default browser at a one-time nonce-signed login URL. The first request consumes the nonce and sets a signed session cookie; subsequent navigation just works.

+

If Atlas has never been set up before, the WebUI redirects to /setup and walks you through the same wizard you'd see in platform-atlas config init.

+ +

Daemon mode

+

For an always-on local install, run detached:

+
platform-atlas-webui --daemon       # double-fork; PID at ~/.atlas/webui.pid
+platform-atlas-webui status
+platform-atlas-webui restart
+platform-atlas-webui stop
+platform-atlas-webui login-url      # mint a fresh URL after restart
+

Daemon mode supports Linux and macOS. On Windows, run the foreground command in a terminal you keep open.

+ +

Security model

+
+
CommandDescription
preflightRun connectivity checks against all configured services
whats-newReopen the post-upgrade summary HTML page
--versionDisplay version, Python path, and OS info
--debugEnable verbose logging
--env <name>Override the active environment for this command
+ + + + + + + + +
LayerWhat it does
TLSSelf-signed cert at ~/.atlas/.webui-cert.pem; regenerate with --reset-tls. Browsers warn the first time — accept for localhost.
OS-user bindingToken file at ~/.atlas/.webui-token (mode 0600). Browser session cookies are signed against that token plus a separate cookie secret. Rotating either invalidates every outstanding cookie (--reset-token).
CSRFStateless HMAC tokens injected into every form, required on AJAX POST / PATCH / DELETE.
CSP & headersStrict response headers. HTML reports themselves render under a sandboxed CSP — captured data cannot reach back into the WebUI's authenticated origin.
Audit logEvery state-changing request appends one JSON line to ~/.atlas/webui-audit.log (rotates at 10 MB).
+
+ +

Page-by-page tour

+
+ + + + + + + + + + + + + + + +
PageWhat you do here
/ DashboardKPI tiles, audit-activity heatmap of the last 48 h, zero-state helpers when tiles are empty.
/sessionsCreate, activate, run capture/validate/report. Live SSE output stream; force-kill button after 60 s.
/environmentsCreate, edit, activate, delete environments. Activation atomically restores tier, ruleset, and profile alongside the env.
/credentialsReconfigure Keyring vs Vault for the active env. All five Vault auth methods supported including AppRole-Wrapped, Token (file), Token (env).
/reportsDirect links to every session's compliance, operational, and architecture HTML reports.
/tierSide-by-side cards for Standard and Extended; switch with a confirmation modal.
/fleetSortable card grid mirroring fleet status — read-only, never triggers a capture.
/continuousStatus, settings, run history. Alerting block with alert_policy selector and watchlist chip editor.
/alertsDrift timeline with ack and ack-all. Bell icon in the topbar shows unacked count.
/notificationsAdd, edit, test, and remove Slack and webhook channels. HMAC signing toggle.
/settingsTheme picker (Aurora / Horizon palettes), light/dark mode segmented control.
+
+ +

Themes

+

Theme palette and light/dark mode are independent axes:

+
    +
  • Aurora — confident, technical (deep navy + electric blue). Default.
  • +
  • Horizon — warm, editorial (charcoal + terracotta).
  • +
+

The moon/sun toggle in the topbar swaps light/dark and preserves your palette choice. Settings persist in config.json under webui_theme, webui_accent, and webui_mode.

+ + +
+

Troubleshooting

@@ -4337,7 +4570,7 @@

I need to run Atlas on a schedule