Skip to content

configuration

Purplemet CI edited this page May 27, 2026 · 4 revisions

Configuration

Priority Order

Configuration is resolved in this order (first wins):

  1. CLI flags (--token, --json, etc.)
  2. Environment variables (PURPLEMET_API_TOKEN, etc.)
  3. .env file (auto-loaded from current directory)
  4. Project config (.purplemet.yml — auto-discovered from CWD up to the project root)
  5. User config (~/.purplemet/config.yml)
  6. Defaults

Environment Variables

Authentication & Connection

Variable Description Default
PURPLEMET_API_TOKEN API authentication token
PURPLEMET_BASE_URL API base URL https://api.purplemet.com
PURPLEMET_TIMEOUT Per-request HTTP timeout (ms) 30000
PURPLEMET_WAIT_TIMEOUT Global polling timeout (ms) 0 (unlimited)
PURPLEMET_POLL_INTERVAL Polling interval (ms) 10000
PURPLEMET_INSECURE Skip TLS verification (dev only) false
PURPLEMET_CONFIG Path to a project config file (default: auto-discover .purplemet.yml)

Output

Variable Description Default
PURPLEMET_JSON JSON output mode false
PURPLEMET_VERBOSE Verbose logging to stderr false
PURPLEMET_NO_ADMIN_WARNING Suppress the warning shown when invoking admin-only commands (users, sessions, tokens) false
PURPLEMET_NO_PAGER Disable the interactive paginator on list commands (TTY only) false

Security Gates

Variable Description Default
PURPLEMET_FAIL_SEVERITY Severity gate: critical, high, medium, low, info — (disabled)
PURPLEMET_FAIL_RATING Rating gate: A, B, C, D, E, F — (disabled)
PURPLEMET_FAIL_CVSS Max CVSS score threshold (e.g. 9.0) 0 (disabled)
PURPLEMET_FAIL_ON_EOL Block on end-of-life components false
PURPLEMET_FAIL_ON_SSL Block on SSL/TLS protocol issues false
PURPLEMET_FAIL_ON_CERT Block on certificate issues false
PURPLEMET_FAIL_ON_HEADERS Block on HTTP security header issues (CSP, HSTS, X-Frame-Options) false
PURPLEMET_FAIL_ON_COOKIES Block on insecure cookies (HttpOnly, Secure, SameSite) false
PURPLEMET_FAIL_ON_UNSAFE Block on unsafe components false
PURPLEMET_FAIL_ON_KEV Block on CISA Known Exploited Vulnerabilities false
PURPLEMET_FAIL_ON_EPSS Max EPSS score threshold (e.g. 0.75, 0 = disabled) 0 (disabled)
PURPLEMET_FAIL_ON_ACTIVE_EXPLOITS Block on actively exploited vulnerabilities false
PURPLEMET_FAIL_ON_OSSF_SCORE Min OpenSSF Scorecard score (e.g. 5.0, 0 = disabled) 0 (disabled)
PURPLEMET_FAIL_ON_CERT_EXPIRY Block if certificate expires within N days 0 (disabled)
PURPLEMET_FAIL_ON_ISSUE_COUNT Block if total issues >= threshold 0 (disabled)
PURPLEMET_REQUIRE_WAF Block if no WAF detected false
PURPLEMET_FAIL_ON_SENSITIVE_SERVICES Block if sensitive services are exposed false
PURPLEMET_EXCLUDE_TECH Block if specified technologies detected (comma-separated)

Dev-only Variables

Variable Description
PPM_CLOUD_UI_BASIC_USER Basic auth username (.dev. URLs only)
PPM_CLOUD_UI_BASIC_PASS Basic auth password (.dev. URLs only)

Pagination

All list commands share the same set of pagination flags:

Flag Description Default
--limit Page size (1–1000) 100
--offset Skip the first N items (mutually exclusive with --page) 0
--page Page number, 1-indexed (mutually exclusive with --offset) 0 (uses --offset)
--all Fetch every page automatically (capped by --max) false
--max Hard cap on the number of items fetched when --all is set 10000

Default behavior depends on where the output goes:

  • Interactive terminal (TTY) with the pager enabledlist commands automatically fetch every page (capped by --max) so you can scroll through the entire result set with the pager's arrow keys. No need to pass --all manually.
  • Pipe / redirect / --no-pager / --json / CI — only the first page is fetched, exactly as you'd expect from a scriptable CLI. Use --all, --page N, or --offset N to access more.

This split keeps both modes ergonomic: humans get effortless scrolling, scripts get predictable single-page output.

# In a terminal: auto-fetches everything, pager handles navigation
$ purplemet-cli sites list
…
Showing 142 of 142 site(s) — all pages fetched

# Piped: only the first page, with a hint to get more
$ purplemet-cli sites list | head
…
Showing 1-100 of 142 site(s) — page 1 of 2 (next: --page 2)

# Force the script behavior in a TTY
$ purplemet-cli sites list --no-pager
…
Showing 1-100 of 142 site(s) — page 1 of 2 (next: --page 2)

# Explicit page works the same in both modes
$ purplemet-cli sites list --page 2 --limit 20
…
Showing 21-40 of 142 site(s) — page 2 of 8 (next: --page 3)

# Cap the auto-fetch when you know the workspace is huge
$ purplemet-cli sites list --max 50
…
Showing 50 of 5000 site(s) — capped by --max, raise it to fetch more

--all cannot be combined with --page or --offset. Raise --max when you legitimately need more than the default cap (every API call is counted by the server, so a full fetch on a large workspace can be slow).

--query is evaluated across the whole result set, not just one page (see Filtering with --query below), so you do not need --all for a filter to find matches on later pages.

Interactive Pagination (TTY)

When stdout is an interactive terminal, list commands open a built-in paginator that fetches one page at a time and lets you navigate between pages with the keyboard. Each arrow-right keystroke triggers a fresh API call for the next page — there is no pre-fetch, so a workspace with thousands of items stays cheap to browse.

Key Action
/ h / p Previous page (refetched)
/ l / n Next page (refetched)
/ k Scroll one line up within the current page
/ j Scroll one line down within the current page
PgUp / b Scroll one screen up within the current page
PgDn / Space / f Scroll one screen down within the current page
g Jump to the top of page 1
G Jump to the bottom of the last page
r Refetch the current page
q / Esc / Ctrl+C Quit

The bottom status bar shows your position: page 3/8 rows 1-30/100 and the available shortcuts. The terminal returns to its previous state on exit (alternate screen buffer, like vim or less).

Auto-disables when:

  • --no-pager is set, or PURPLEMET_NO_PAGER=1
  • --json is set (machine output is never paginated)
  • stdout or stdin is not a TTY (pipe, redirect, CI logs)
  • --all, --page N or --offset N is set (those imply you want one specific result set, not interactive browsing)

Disable per-call or globally:

# One-off
purplemet-cli sites list --no-pager

# Globally (e.g. in CI)
export PURPLEMET_NO_PAGER=1

Filtering with --query

--query is a global flag available on every list command (and any command that returns a collection). It filters items client-side on their JSON fields.

Syntax: key<op>value[,key<op>value,…] — multiple predicates are AND-combined.

Operators:

Op Meaning Example
= Exact match (case-insensitive for strings) severity=high
!= Not equal status!=IGNORED
~= Contains (substring, case-insensitive) url~=staging
!~ Does not contain name!~deprecated

Keys are the JSON field names you see in --json output (e.g. severity, status, url, role). Nested fields use the dotted form exposed by the API (e.g. technology.name on issues).

--query filters across the whole account. Every list command evaluates --query over all items in the workspace, not just the page you land on, and reports the accurate filtered total — e.g. issues list --query "severity=high,status=OPEN" prints Showing 1-34 of 34 issue(s) even when those 34 are scattered across many pages. How it's resolved depends on what the API supports:

  • Server-side push-down when the endpoint can filter on the field: sites list --query "url~=staging" becomes a single /site?url=like(...) request, and domains list --query "name~=corp" a single /domain?name=like(...) request. These are the only two server-side filterable fields (site.url, domain.name).
  • Client-side full scan for every other field/command: the CLI walks the pages and keeps the matches. issues list also folds its dedicated --severity / --status flags into this scan.

The exact total requires reading every page (the API can't count a filtered set it doesn't filter), so:

  • One-shot output (piped, CI, --no-pager) scans to completion and prints the exact total — Showing 1-100 of 1500 issue(s) — page 1 of 15. A sparse filter over a large account therefore costs more API calls; the scan is capped by --max (the footer says so when it hits the cap).
  • The interactive pager stays lazy — it fetches just enough to fill the screen and the total refines as you page, with a hint while it's still unknown. Press to keep going, or use --all / --no-pager to force the exact count up front.

Examples

# Sites whose URL contains "staging"
purplemet-cli sites list --query "url~=staging"

# Open high-severity issues only
purplemet-cli issues list --query "severity=high,status=OPEN"

# All non-low issues mentioning a CVE in their name
purplemet-cli issues list --all --query "severity!=low,name~=CVE-2024"

# Admin tokens only
purplemet-cli tokens list --query "role=ADMIN"

# Active user accounts
purplemet-cli users list --query "status=ENABLED"

# Discoveries that succeeded
purplemet-cli discoveries list --query "status=DONE"

# Internal domains
purplemet-cli domains list --query "name~=internal"

# Sensitive services
purplemet-cli services list --query "sensitive=true"

# Filtering already spans the whole account; --all just disables the
# interactive pager and prints every match in one shot
purplemet-cli issues list --all --query "severity=critical,status=OPEN"

Tip: unsure of the field names? Run the same command with --json once — the keys you see in the output are the keys you can filter on.

The footer reports the filtered count, not the unfiltered total:

Showing 1-34 of 34 issue(s) — page 1 of 1

Admin-only Commands

The users, sessions, and tokens command groups require an ADMIN token. Calling them with an OPERATOR or READER token returns 403 API_METHOD_NOT_ALLOWED.

When invoked, these commands print a one-line warning to stderr. To suppress it (e.g. in CI pipelines that legitimately use an ADMIN token), pass --no-admin-warning or set PURPLEMET_NO_ADMIN_WARNING=1.

.env File

The CLI automatically loads a .env file from the current directory. Format:

PURPLEMET_API_TOKEN=your-token-here
PURPLEMET_BASE_URL=https://api.purplemet.com
PURPLEMET_FAIL_SEVERITY=high
PURPLEMET_FAIL_ON_EOL=true

Rules:

  • Lines starting with # are comments
  • Empty lines are ignored
  • Existing environment variables are not overwritten
  • The .env file should be in .gitignore

Security: The CLI warns if the .env file is readable by group or others. Set chmod 600 .env.

Project Config File (.purplemet.yml)

A project-scoped YAML config lives at the root of your repository. It is auto-discovered by walking up from the current directory until the CLI finds either the file or a .git/ directory (the project boundary). Lookup order:

  1. --config <path> flag (explicit; errors if missing)
  2. $PURPLEMET_CONFIG env var
  3. .purplemet.yml / .purplemet.yaml, searched upward from CWD up to the nearest .git/
# Default target for `analyze` — accepts a siteId (UUID) or URL.
# `purplemet-cli analyze` can then run without any argument.
site: https://example.com

verbose: true

# Per-project security gates
fail_severity: high
fail_rating: C
fail_on_kev: true
fail_on_headers: true
exclude_tech:
  - php
  - java

Security — no secrets in project config. Because this file is meant to be committed alongside the code, secret fields (token, basic_user, basic_pass) are stripped at load time and a warning is emitted. Keep secrets in env vars or in the user-level config below.

User Config File (~/.purplemet/config.yml)

Optional YAML configuration file for persistent user-level settings. Unlike the project config, this file can contain the API token — it is meant to stay on the user's machine, outside version control.

# Authentication
token: ppm_xxx
base_url: https://api.purplemet.com

# Timeouts
poll_interval_ms: 10000
timeout_ms: 30000
wait_timeout_ms: 300000

verbose: true
no_admin_warning: true  # silence admin-only command warnings

# Security gates
fail_severity: high
fail_rating: C
fail_cvss: 9.0
fail_on_eol: true
fail_on_ssl: true
fail_on_cert: true
fail_on_headers: true
fail_on_cookies: true
fail_on_unsafe: true
fail_on_kev: true
fail_on_epss: 0.75
fail_on_active_exploits: true
fail_on_ossf_score: 5.0
fail_on_cert_expiry: 30
fail_on_issue_count: 50
require_waf: true
fail_on_sensitive_services: true
exclude_tech:
  - php
  - java

Issues explicitly ignored via purplemet-cli issues ignore are always excluded from gate evaluation.

Security: The CLI warns if config file permissions are broader than 0600. Set chmod 600 ~/.purplemet/config.yml.

Severity Levels

For --fail-on-severity / PURPLEMET_FAIL_SEVERITY:

Level Weight Blocks on
critical 4 Critical only
high 3 High + Critical
medium 2 Medium + High + Critical
low 1 Low + Medium + High + Critical
info 0 All issues

Default in CI templates: high (blocks on high and critical issues).

Rating Scale

For --fail-on-rating / PURPLEMET_FAIL_RATING, accepted values are A, B, C, D, E, F (ordered from best to worst — A is the safest, F the most critical). The rating is computed by the Purplemet platform; see the official Purplemet documentation for the scoring rules.

The gate triggers if the analysis rating is at or worse than the threshold. Example: --fail-on-rating C fails on C, D, E, and F.

Clone this wiki locally