Metadata-Version: 2.4
Name: threatcluster-cli
Version: 0.1.1
Summary: Command-line client for ThreatCluster (`tc`)
Author: ThreatCluster
License-Expression: MIT
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.10
Requires-Dist: httpx<1.0,>=0.27
Requires-Dist: keyring<26.0,>=24.0
Requires-Dist: pydantic<3.0,>=2.6
Requires-Dist: typer<1.0,>=0.12
Provides-Extra: test
Requires-Dist: pytest-asyncio>=0.23; extra == 'test'
Requires-Dist: pytest>=8.0; extra == 'test'
Requires-Dist: respx>=0.21; extra == 'test'
Description-Content-Type: text/markdown

# threatcluster-cli

Command-line client for ThreatCluster. Installs the `tc` command.

```
pipx install threatcluster-cli
```

---

## Getting started (3 steps)

**1. Install**

```
pipx install threatcluster-cli
```

**2. Mint an agent key**

Sign in at https://threatcluster.io → **Settings → CLI → Mint key**.
Tick the scopes you want, click mint, copy the `tc_agent_…` value.
**Shown once** — store it somewhere safe.

**3. Log in**

```
tc auth login
```

Paste the key when prompted. The CLI stores it in your OS keyring
(Keychain on macOS, SecretService on Linux desktop, Credential Manager on
Windows) and you're ready.

```
tc threats list --limit 5 | jq -r '.threats[].ai_title'
```

That's it.

---

## Commands

Every command outputs JSON. Pipe through `jq` for reading. `tc <command> --help`
for full options.

### `tc auth` — credentials

```bash
tc auth login                    # paste a refresh credential
tc auth status                   # show what's loaded
tc auth status -v                # + storage backend, bearer jti, key id
tc auth logout                   # hard kill: revokes server-side AND clears local
tc auth logout --keep-remote     # local clear only (e.g. moving the key)
```

### `tc search` — smart router (entities + threats)

```bash
tc search "Volt Typhoon"
tc search lockbit --only entities       # entity-only
tc search cisco --only threats --limit 20
```

### `tc threats` — clusters and IOCs

```bash
tc threats list                                 # latest trending
tc threats list --query ransomware --limit 20   # filter by keyword
tc threats list --watch --interval 30           # live feed (NDJSON)
tc threats get <cluster-id>                     # one cluster
tc threats iocs <cluster-id>                    # IOCs for one cluster
tc threats iocs <id> --types ip,domain          # filter IOC types
tc threats stix <cluster-id>                    # STIX 2.1 export
```

### `tc iocs` — bulk indicators

```bash
tc iocs feed                                    # plaintext, one per line (last 30d, confirmed)
tc iocs feed --type ip                          # filter by type
tc iocs feed --type hash --hours 24             # last 24h hashes only
tc iocs export --format csv                     # for spreadsheets / SIEM
tc iocs export --format json                    # structured
tc iocs export --type domain --format csv       # domains, CSV
```

### `tc entities` — actors, malware, tools

```bash
tc entities search "lazarus" --type apt_group
tc entities get apt_group "Lazarus Group"
tc entities related apt_group "Lazarus Group"   # co-occurring entities
tc entities trending                            # top by recent mentions
tc entities trending --window 7d
```

### `tc vulns` — CVEs

```bash
tc vulns list                                   # latest CVEs
tc vulns list --severity CRITICAL --limit 10
tc vulns list --watch --interval 120            # live CVE feed
tc vulns get CVE-2026-1234                      # one CVE detail
```

### `tc darkweb` — ransomware, breaches, markets

```bash
tc darkweb ransomware victims                   # last 30 days
tc darkweb ransomware victims --group lockbit
tc darkweb ransomware victims --days 7 --limit 100
tc darkweb ransomware victims --watch           # live feed
tc darkweb breaches
tc darkweb breaches --watch
tc darkweb keyword-hits                         # business+/MSSP only
```

### `tc feeds` — your custom intel feeds

```bash
tc feeds list
tc feeds get <feed-id>
```

### `tc cluster` — analyst pivots

```bash
tc cluster open <cluster-id>                    # opens in browser
tc cluster open <id> --no-browser               # just print the URL
```

### Stdin chaining (`-`)

Any command that takes an `id` accepts `-` to read ids from stdin.
Compose freely:

```bash
# Top 5 trending clusters → IOCs for each
tc threats list --limit 5 \
  | jq -r '.threats[].cluster_id' \
  | tc threats iocs -

# CVE detail for everything new in 24h
tc vulns list --since 24h \
  | jq -r '.cves[].cve_id' \
  | tc vulns get -

# Open every LockBit-related cluster in the browser
tc threats list --query lockbit --limit 3 \
  | jq -r '.threats[].cluster_id' \
  | tc cluster open -

# STIX bundle for every "ransomware" cluster
tc threats list --query ransomware --limit 20 \
  | jq -r '.threats[].cluster_id' \
  | tc threats stix -
```

---

## Use cases

### SOC analyst — "what's worth my attention right now?"

```bash
# Trending ransomware clusters
tc threats list --query ransomware --limit 10 \
  | jq -r '.threats[] | "[\(.threat_score)] \(.ai_title)"'

# CVEs newly added to CISA KEV-style catalogs
tc vulns list --severity CRITICAL --limit 10 \
  | jq -r '.cves[] | "\(.cve_id) — \(.description[:120])"'

# What ransomware groups are most active this week?
tc entities trending --window 7d \
  | jq -r '.trending.ransomware_group[:10][] | "\(.value)  freq=\(.frequency)"'
```

### Threat hunter — "is X in our intel?"

```bash
# Pivot from a malware family to clusters mentioning it
tc entities search "cobalt strike" --type malware \
  | jq -r '.entities[].entity_value'

# All IOCs from clusters mentioning a tool you're hunting
tc threats list --query "cobalt strike" --limit 50 \
  | jq -r '.threats[].cluster_id' \
  | tc threats iocs - \
  | jq -r '.iocs[]'

```

### MSSP — "give me a feed for $CUSTOMER"

```bash
# Live ransomware victims into a Slack webhook
tc darkweb ransomware victims --watch --interval 60 \
  | while read line; do
      msg=$(echo "$line" | jq -r '"🔒 new victim: \(.group): \(.name)"')
      curl -s -X POST -d "{\"text\":\"$msg\"}" "$SLACK_WEBHOOK_URL"
    done

# Daily IOC blocklists (cron)
tc iocs feed --type ip     > /etc/blocklists/tc-ips.txt
tc iocs feed --type domain > /etc/blocklists/tc-domains.txt
```

### Engineer — "feed our SIEM"

```bash
# Bulk IOC export for SIEM ingest
tc iocs export --format csv > tc-iocs.csv

# Filter to only the IOCs from clusters scoring 80+
tc threats list --limit 100 \
  | jq -r '.threats[] | select(.threat_score >= 80) | .cluster_id' \
  | tc threats iocs - > high-confidence-iocs.json
```

### AI agent — "scoped, budgeted access"

Hand a sub-agent a narrower bearer than your own. The server enforces it —
the child cannot escalate scopes or exceed the budget.

```bash
TC_SCOPES=threats:read,iocs:read \
TC_SESSION_ID="$(uuidgen)" \
TC_MAX_REQUESTS=50 \
  tc threats list --limit 5
```

---

## Environment

| Var                   | Purpose                                                      |
|-----------------------|--------------------------------------------------------------|
| `TC_API_URL`          | Override API base (default `https://api.threatcluster.io`)   |
| `TC_REFRESH_TOKEN`    | Refresh credential (overrides keyring + file). For CI only.  |
| `TC_SCOPES`           | Comma-separated subset of refresh scopes for the bearer.     |
| `TC_SESSION_ID`       | Session id for per-session request budgeting.                |
| `TC_MAX_REQUESTS`     | Cap requests per session; subsequent ones get 429.           |
| `TC_PROPAGATE_AUTH`   | Set to `1` to propagate auth env to subprocesses.            |
| `TC_DEBUG`            | Set to `1` for verbose stderr (auth headers redacted).       |

## Shell completion

```bash
tc --install-completion bash    # or zsh, fish
exec $SHELL                     # restart your shell
tc thr<TAB>                     # → tc threats
```

## Security notes

- Refresh credential is never sent on argv (`--api-key` flag is rejected).
- Bearer JWTs (15 min ttl) are minted on demand, cached in memory only.
- The CLI refuses plaintext `http://` URLs unless the host is `127.0.0.1`/`localhost`.
- Auth env vars are scrubbed from subprocess environments unless `TC_PROPAGATE_AUTH=1`.
- Credential file is mode 0600 + uid-checked; loose perms are refused.

See [the docs](https://threatcluster.io/docs/cli) for the full reference, and
[Agent keys & scopes](https://threatcluster.io/docs/agent-keys) for the
security model in detail.

## Release flow

See `PUBLISHING.md`.
