Files
rust-ectf-tools/README.md
Kieran Klukas 0a3596aab6 feat: add --json flag to all API flow commands
Add --json to submit, ls, and info for test/clone/remote flows.
Document all JSON output formats in README.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:04:30 -05:00

220 lines
5.6 KiB
Markdown

# rust-ectf-tools
![vhs gif](https://vhs.charm.sh/vhs-27M7tCPh4cNTI2EM5Z0yLi.gif)
Drop-in replacement for MITRE's `uvx ectf` CLI, rewritten in Rust with reliable serial I/O. Uses raw termios instead of pyserial to avoid macOS CDC-ACM data corruption bugs.
## Install
```bash
brew install taciturnaxolotl/tap/ectf-tools
```
Or build from source:
```bash
cargo build --release
```
## Usage
### HSM Host Tools
```bash
# List files on the HSM
ectf-tools tools /dev/tty.usbmodemXXX list 1a2b3c
# Write a file
ectf-tools tools /dev/tty.usbmodemXXX write 1a2b3c 0 0x4321 myfile.bin
# Read a file
ectf-tools tools /dev/tty.usbmodemXXX read 1a2b3c 1 ./output/
# Interrogate a connected HSM
ectf-tools tools /dev/tty.usbmodemXXX interrogate 1a2b3c
# Listen for another HSM
ectf-tools tools /dev/tty.usbmodemXXX listen
# Receive a file from another HSM
ectf-tools tools /dev/tty.usbmodemXXX receive 1a2b3c 0 1
# Run the hardware test suite
ectf-tools tools /dev/tty.usbmodemXXX test 1a2b3c 0x4321 /dev/tty.usbmodemYYY
# Run tests without a second HSM
ectf-tools tools /dev/tty.usbmodemXXX test 1a2b3c 0x4321 --no-transfer
# Output test results as JSON (for CI)
ectf-tools tools /dev/tty.usbmodemXXX test 1a2b3c 0x4321 --no-transfer --json
```
### API Commands
```bash
# Configure your API credentials
ectf-tools config --token <TOKEN> --git-url <GIT_URL>
# Submit a design for testing
ectf-tools api test submit <COMMIT_HASH>
# List recent test flows
ectf-tools api test ls
# Get details on a specific flow
ectf-tools api test info <FLOW_ID>
# Download job output
ectf-tools api test get <JOB_ID> output.tar.gz
# Submit to handoff
ectf-tools api submit <COMMIT_HASH>
# List and download attack packages
ectf-tools api list
ectf-tools api get <PACKAGE_NAME>
```
### Environment Variables
For CI environments, you can configure the tool entirely via environment variables instead of the config file:
| Variable | Description | Required |
|---|---|---|
| `ECTF_TOKEN` | API bearer token | Yes (with `ECTF_GIT_URL`) |
| `ECTF_GIT_URL` | Git repository URL | Yes (with `ECTF_TOKEN`) |
| `ECTF_API_URL` | API base URL (default: `https://api.ectf.mitre.org`) | No |
If both `ECTF_TOKEN` and `ECTF_GIT_URL` are set, no config file is needed. If a config file exists, env vars override individual fields.
### JSON Output (`--json`)
Most commands support `--json` for machine-readable output. The process exit code is still non-zero on failure.
#### `tools test --json`
```json
{
"total": 15,
"passed": 14,
"failed": 1,
"tests": [
{
"name": "list_empty",
"passed": true,
"duration_secs": 0.123
},
{
"name": "bad_pin",
"passed": false,
"duration_secs": 1.234,
"error": "Expected bad pin to fail, but it succeeded"
}
]
}
```
#### `api test submit --json` / `api clone submit --json` / `api submit --json`
```json
{
"flow": "test",
"id": "abc12345-1234-1234-1234-123456789abc"
}
```
#### `api test ls --json` / `api clone ls --json` / `api remote ls --json`
```json
{
"flows": [
{
"id": "abc12345-1234-1234-1234-123456789abc",
"submitted": "2026-02-11T22:05:47.000000Z",
"status": "succeeded",
"completed": true
}
]
}
```
#### `api test info --json` / `api clone info --json` / `api remote info --json`
```json
{
"flow": "test",
"id": "abc12345-1234-1234-1234-123456789abc",
"submitted": "2026-02-11T22:05:47.000000Z",
"status": "succeeded",
"completed": true,
"params": {
"git_url": "https://github.com/example/repo.git",
"commit_hash": "abc1234"
},
"jobs": [
{
"name": "build",
"id": "def12345-1234-1234-1234-123456789abc",
"status": "succeeded",
"has_artifacts": true,
"private": false
}
]
}
```
### Hardware Bootloader Tools (MSPM0L2228)
```bash
# Check bootloader version and status
ectf-tools hw /dev/tty.usbmodemXXX status
# Erase the current design
ectf-tools hw /dev/tty.usbmodemXXX erase
# Flash an image (name auto-derived from filename for unprotected images)
ectf-tools hw /dev/tty.usbmodemXXX flash design.bin
ectf-tools hw /dev/tty.usbmodemXXX flash design.bin --name mydesign
# Start the flashed design
ectf-tools hw /dev/tty.usbmodemXXX start
# Erase + flash + start in one step (file or directory with hsm.bin)
ectf-tools hw /dev/tty.usbmodemXXX reflash ./build/
ectf-tools hw /dev/tty.usbmodemXXX reflash engineer.hsm/hsm.bin
# Get a file digest from the secure bootloader
ectf-tools hw /dev/tty.usbmodemXXX digest 0
```
### Hardware Bootloader Tools (MAX78000FTHR)
```bash
# Flash a design
ectf-tools hw /dev/tty.usbmodemXXX flash-fthr /dev/tty.usbmodemYYY image.bin
# Permanently unlock the secure bootloader (irreversible!)
ectf-tools hw /dev/tty.usbmodemXXX unlock-fthr /dev/tty.usbmodemYYY secrets.json --force --force
```
### Verbosity
- `-v` — protocol-level debug (headers, ACKs, chunk sizes)
- `-vv` — raw byte-level trace with xxd-style hexdump
## Why not pyserial?
pyserial has known data corruption issues on macOS with CDC-ACM devices (like the MAX78000). This tool opens the serial port directly with proper termios configuration, flushes the input buffer on open, and uses `O_NONBLOCK` to avoid blocking on carrier detect.
<p align="center">
<img src="https://raw.githubusercontent.com/taciturnaxolotl/carriage/main/.github/images/line-break.svg" />
</p>
<p align="center">
<i><code>&copy; 2026-present <a href="https://dunkirk.sh">Kieran Klukas</a></code></i>
</p>
<p align="center">
<a href="https://github.com/taciturnaxolotl/rust-ectf-tools/blob/main/LICENSE.md"><img src="https://img.shields.io/static/v1.svg?style=for-the-badge&label=License&message=MIT&logoColor=d9e0ee&colorA=363a4f&colorB=b7bdf8"/></a>
</p>