Metadata-Version: 2.4
Name: threatcluster-cli
Version: 0.1.0
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.

## Install

Once published to PyPI:

```
pipx install threatcluster-cli
```

Until then, install from source:

```
git clone <this-repo>
pipx install ./tc-testing/cli
```

See `PUBLISHING.md` for the PyPI publish flow.

## Authenticate

```
tc auth login
```

This runs an Auth0 device-code flow and mints a scoped `tc_agent_*` refresh
credential, storing it in your OS keyring (Keychain / SecretService /
Credential Manager). On headless systems it falls back to a 0600 file at
`~/.config/tc-cli/credentials`.

## Use

All commands print JSON. Pipe through `jq` for human reading.

```
tc threats list --limit 5 | jq '.threats[].title'
tc entities search "lazarus" --type apt_group
tc darkweb ransomware victims --days 7
```

## Cookbook

Worked examples for common analyst / agent flows.

### Smart search

`tc search` merges entity hits and threat clusters into one shape so you don't
have to know which sub-command applies.

```
tc search "Volt Typhoon" --limit 5
tc search lockbit --only entities
tc search cisco --only threats --limit 20
```

### Stdin chaining

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

```
# IOCs for the top 5 trending threats
tc threats list --limit 5 \
  | jq -r '.threats[].cluster_id' \
  | tc threats iocs - \
  | jq -r '.iocs[]'

# STIX export of every threat tagged "ransomware"
tc threats list --query ransomware --limit 50 \
  | jq -r '.threats[].cluster_id' \
  | tc threats stix -

# Open every CVE in your browser (xdg-open / open)
tc vulns list --severity CRITICAL --limit 5 \
  | jq -r '.cves[].cve_id' \
  | xargs -I{} echo "https://nvd.nist.gov/vuln/detail/{}"
```

### Live feeds (`--watch`)

Poll an endpoint and emit only new items as NDJSON. Ctrl+C to stop.

```
# New ransomware victims as they're posted
tc darkweb ransomware victims --watch --interval 60

# Pipe live victims into a Slack webhook
tc darkweb ransomware victims --watch \
  | while read line; do
      echo "$line" | jq -r '"new victim: \(.group): \(.name)"' \
        | curl -X POST -d @- "$SLACK_WEBHOOK_URL"
    done

# Watch new threats matching a keyword
tc threats list --query lockbit --watch --interval 30
```

### Per-session containment for sub-agents

Hand a child process a narrower bearer than your own. The server enforces
the subset — the child cannot escalate.

```
# Read-only sub-agent with a 50-request budget per session
TC_SCOPES=threats:read \
TC_SESSION_ID="$(uuidgen)" \
TC_MAX_REQUESTS=50 \
  tc threats list --limit 5
```

### Auth diagnostics

```
tc auth status -v        # storage backend, bearer jti, key id
tc auth logout           # hard kill: revokes server-side too
tc auth logout --keep-remote   # local-only clear (you're moving the key)
```

### Shell completion

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

## 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_PROPAGATE_AUTH`   | Set to `1` to propagate auth env to subprocesses.            |
| `TC_DEBUG`            | Set to `1` for verbose stderr (auth headers redacted).       |

## Security notes

- Refresh credential is never sent on argv (`--api-key` flag is rejected).
- Bearer JWTs (15 min ttl) are minted on demand and cached only in memory.
- The CLI refuses to talk to plaintext `http://` URLs except `127.0.0.1`/`localhost`.
- Auth env vars are scrubbed from subprocess environments unless
  `TC_PROPAGATE_AUTH=1` is set.
