Run Microsoft 365 security scans, track compliance and exposure findings, and pull reports - from your terminal or CI.
Status: v0.x. The CLI and SDK work against the live Aether365 API today; the command surface may still change until the first 1.0 release.
Aether365 continuously scans Microsoft 365 tenants against CIS, EIDSCA, and CISA baselines, maps your external attack surface, and turns the findings into remediation guidance your team can act on. The CLI brings that to the command line: trigger scans, fetch findings, and export reports without opening the dashboard.
Requires Python 3.12+.
curl -fsSL https://raw.githubusercontent.com/aether365-io/cli/main/install.sh | shThe installer picks the best available method: pipx
if present, then uv, otherwise a dedicated
virtual environment in ~/.aether365/venv. Re-running it upgrades to the
latest release. It never uses sudo and never touches system Python packages.
pipx install aether365pip install aether365Or straight from source:
pip install "git+https://github.com/aether365-io/cli.git"The
aether365package lands on PyPI with the first tagged release. Until then, use the install-from-source command above.
pipx install aether365
aether365 login # opens your browser, stores the key
aether365 scan run --type compliance # your first scanThat is the whole setup: login opens the Aether365 dashboard, you approve
the CLI, and the issued API key lands in ~/.aether365/config (mode 600).
Three ways to authenticate, use whichever fits:
aether365 login- browser-based sign-in (recommended). Starts a temporary listener on127.0.0.1, opens the dashboard's CLI authorization page, and saves the key for you. With--no-browserit prints the URL for you to open manually; the callback still lands on localhost, so the browser must run on the same machine.aether365 configure- interactive paste flow (aws-cli style). Create a key in the dashboard under Settings -> API Keys, then paste it at the hidden prompt and pick your region (eu/us). Works over SSH.- Environment / flag -
export AETHER365_API_KEY="ak_live_..."or--api-keyper invocation, ideal for CI.
Check what the CLI is using at any time:
aether365 whoami
# APIKEY ak_live_***f3a9
# REGION eu
# PROFILE default
# SOURCE profile 'default' in /home/you/.aether365/configKeys are scoped to your tenant; nothing else is ever accessible.
aether365 scan run --type compliance --watch # start and stream progress
aether365 scan list --status completed
aether365 scan get <scan-id>
aether365 scan results <scan-id> --severity High --output json
aether365 scan cancel <scan-id>aether365 eas summary
aether365 eas history
aether365 eas targets add example.com
aether365 eas targets verify <target-id>
aether365 eas scanaether365 report generate <scan-id> --audience board
aether365 report status <scan-id>
aether365 report download <scan-id> -o report.pdfaether365 tenant me
aether365 tenant connections
aether365 policies
aether365 threats
aether365 remediation plans
aether365 ai-pilot remediableEvery command supports --output json for scripting, and exit codes are
CI-friendly (scan results --fail-on-findings exits 2 on failures). Run
aether365 <group> --help for the full surface.
The same package is an SDK:
from aether365 import Aether365Client
client = Aether365Client() # reads AETHER365_API_KEY
scans, meta = client.scans.list(limit=10)
for scan in scans:
print(scan["id"], scan["status"], scan["failCount"])Everywhere the CLI or SDK builds auth, the API key is resolved in this order - first match wins:
| Priority | Source |
|---|---|
| 1 | --api-key flag |
| 2 | AETHER365_API_KEY environment variable |
| 3 | Selected profile in ~/.aether365/config |
The active profile is selected by --profile, then AETHER365_PROFILE,
then default.
~/.aether365/config is an INI file (written with mode 600), one section
per profile - handy for separate tenants or staging environments:
[default]
api_key = ak_live_...
region = eu
[staging]
api_key = ak_live_...
region = usaether365 login --profile staging # or: aether365 --profile staging configure
aether365 --profile staging scan list
aether365 configure list # show the effective credentials, key masked| Variable | Purpose | Default |
|---|---|---|
AETHER365_API_KEY |
API key (ak_live_...) |
- |
AETHER365_PROFILE |
Profile name in ~/.aether365/config |
default |
AETHER365_API_URL |
API endpoint override | https://api.aether365.io |
AETHER365_OUTPUT |
Default output format (table/json) |
table |
AETHER365_CONFIG_FILE |
Config file location override | ~/.aether365/config |
AETHER365_APP_URL |
Dashboard URL used by aether365 login |
https://app.aether365.io |
The CLI ships click's native tab completion. Add the line for your shell to its rc file:
eval "$(_AETHER365_COMPLETE=bash_source aether365)" # ~/.bashrc
eval "$(_AETHER365_COMPLETE=zsh_source aether365)" # ~/.zshrc
_AETHER365_COMPLETE=fish_source aether365 | source # ~/.config/fish/config.fishFull product documentation, every security check explained, and remediation guides: docs.aether365.io
Contributions are welcome - see CONTRIBUTING.md for the process and DEVELOPMENT.md for local setup. Bug reports and feature requests go through issues; please use the templates.
Found a vulnerability? Please do not open a public issue - see SECURITY.md for private reporting.