santh-orchestrator-cli 0.1.0

CLI for the Santh discovery orchestrator: cold URL to loginflow, appmap, and scanner fan-out
# santhorchestrator

Discovery orchestrator v0.1 (wires **loginflow**, **appmap**, **authjar**, and **scanclient** into a single cold-URL pipeline with scanner fan-out).

## CLI

```bash
cargo install --path crates/orchestrator-cli

santhorchestrator scan https://target.example/ \
  --creds creds.toml \
  --scanners scald,bolascan,gossan

# Optional: captchaforge-backed browser login (compile with --features captchaforge)
santhorchestrator scan https://target.example/ --creds creds.toml --captchaforge
```

### `creds.toml`

```toml
[[role]]
name = "alice"
username = "alice@example.com"
password = "secret"

[[role]]
name = "bob"
username = "bob@example.com"
password = "secret2"
```

## Pipeline (v0.1)

1. **Probe**: `scanclient` GET of cold URL (stealth `ProfileBundle` user-agent)  
2. **Login**: `loginflow` HTTP fast-path with stealth profile → `authjar` (multi-role loop)  
3. **Crawl**: minimal same-origin link harvest → `CrawlArtifacts`  
4. **Model**: `appmap::AppMapBuilder::from_crawl`  
5. **Fan-out**: registered [`ScannerRunner`]crates/orchestrator-core/src/runners/mod.rs implementations:
   - **scald**: `scald scan` subprocess when on PATH; else authenticated GET probe  
   - **bolascan**: `bolascan` CLI when on PATH; else `appmap::replay_across` role probe  
   - **gossan**: `gossan scan` subprocess when on PATH; else origin-header probe  

## Library

```rust
use orchestrator_core::{Orchestrator, ScanRequest, ScannerId, ScanMode};
use url::Url;

let orchestrator = Orchestrator::builder().build()?;
let result = orchestrator.scan(ScanRequest {
    target: Url::parse("https://example.com/")?,
    credentials: None,
    scanners: vec![ScannerId::Scald],
    mode: ScanMode::RealTarget,
    use_captchaforge: false,
}).await?;
```

## Tests

```bash
cd software/santhorchestrator
cargo test -p orchestrator-core
```