Skip to content

Repository files navigation

TAK Bench

TAK Bench is a Rust tool for explicitly authorized testing of TAK/CoT servers that accept CoT XML over raw TCP, TLS, or mTLS. Its stream framing follows the official TAK Server StreamingCotProtocol: fragmented and concatenated CoT events, as well as authentication preambles, are supported.

Use this tool only against servers you administer or are authorized to test.

Safety

Commands that open connections require --acknowledge-authorization or authorization.acknowledged: true. The destination must be listed in allow_hosts, except for loopback in local. Production additionally requires --environment production --allow-production, accepts only smoke, and remains limited to three clients, 15 minutes, and one position every 30 seconds or less frequently. Controlled staging load profiles may use 100, 500, or 1000 clients; they require --allow-staging-stress, authorization, an allowlisted target, and explicit run.max_clients. See controlled load tiers.

Invalid events are blocked by default. In staging they require --allow-invalid-events; in local and temporary environments they still require max_events and a maximum rate of one event per second.

Usage

Validate a configuration without opening a connection:

cargo run -- validate --config examples/functional.yaml

Run an explicitly authorized local TCP smoke test:

cargo run -- smoke \
  --server 127.0.0.1:8089 \
  --acknowledge-authorization \
  --duration 2m

A YAML configuration can define TLS/mTLS, participant roles, ramp-up, timeouts, reconnect, readiness synchronization, routing observations, fragmentation, thresholds, and stable JSON output. CLI flags override equivalent fields. --lifecycle-jsonl (or output.lifecycle_jsonl: true) reserves stdout for sanitized orchestration events; the JSON report remains the primary artifact. Unsupported scenario and scheduling options are rejected before dialing. Start with functional-routing.yaml.

External orchestrators should consume lifecycle JSON Lines as an ephemeral control stream rather than upload them as an artifact. Persist only output.json, validate routing by the individual sender, receiver, and expectation fields, and configure the read timeout longer than the overall functional run so the global scenario deadline owns silent-receiver completion.

Current capabilities

  • Fixed-position CoT events with a UID and per-event correlation ID.
  • TCP, TLS, and mTLS with hostname verification always enabled, including optional per-participant certificate/key path templates using {participant_id}.
  • Optional TAK enrollment and ATAK data-package credentials. Enrollment uses only /Marti/api/tls/config and /Marti/api/tls/signClient/v2 with Basic Auth; it never provisions users or groups, revokes certificates, or calls administrative APIs.
  • Authenticated ATAK packages are imported in memory. PKCS#12 keychains and truststores use pure Rust parsing; trust-only packages require stdin CSV enrollment. Packages in one run must target the configured target.server.
  • Concurrent reading and writing, received/duplicate message counts, and local delivery latency when the correlation extension is preserved.
  • immediate, linear, step, and randomized ramps; connection, message, latency, and drop thresholds that cooperatively stop a run.
  • Participant roles (send_only, receive_only, and send_receive), bounded reconnect with jitter, per-operation timeouts, CoT batching and fragmentation.
  • Observational routing assertions: each expected or forbidden sender/receiver pair has its own sanitized result and observed count; the harness does not configure server routing.
  • An optional readiness barrier gates sender workloads on named participants. "Ready" means that the participant completed TCP and, when configured, TLS/mTLS setup and can execute its local role. It does not claim server-side authorization, registration, presence, or policy acceptance.
  • Optional sanitized JSON Lines lifecycle events (participant_connected, participant_ready, participant_disconnected, and run_completed) containing aliases and classified reasons only.
  • Terminal and JSON reports with final status, abort reason, sanitized configuration, metrics, per-participant classified failures, and assertion results.
  • Credential reports distinguish preparation from workload time using credential_summary, credential_failures, and workload_elapsed_ms. Preparation failures still emit a sanitized failed report and run_completed lifecycle event.
  • A server-neutral Provisioner interface and FakeProvisioner for tests; no Vanguarda-specific or other server-specific API is embedded.
  • A reusable tak_bench::runner module so external integrations can provision their own fixtures and execute the same guarded workload lifecycle as the CLI from one public crate.

Compatibility contract

The harness only observes whether a server accepts TCP/TLS/mTLS connections, delivers events to clients, preserves the correlation identifier required by configured assertions, and closes or rejects sockets according to its own policy. It has no administrative view into a TAK Server.

Preservation of the correlation extension and acceptance of a receive-only client that sends no initial announcement are integration properties of the consumer's chosen server. tak_bench does not assume either behavior. Provisioning identities, certificates, groups, policy, revocation, and cleanup remains the external orchestrator's responsibility.

Credential sources

The default remains neutral and uses the existing PEM fields under tls. Credential acquisition is enabled only when credentials.source is present. The CSV is never read from a file or argument: library callers pass a zeroizing buffer and the CLI reads it exclusively from stdin.

credentials:
  assignment: round_robin
  source:
    kind: tak_enrollment
    users: stdin_csv
    endpoint:
      host: tak.example
      port: 8446
      sni: tak.example
      ca: /run/secrets/enrollment-ca.pem
    rsa_bits: 4096
    max_parallel: 4
    timeout: 30s

The CSV header must be exactly participant,username,password. participant may be empty. A supplied alias receives that identity first; remaining participants reuse identities in deterministic round-robin order. Each row is enrolled once.

printf 'participant,username,password\nclient-0,alice,secret\n' \
  | tak-bench run --config staging/enrollment.yaml --acknowledge-authorization

ATAK packages use kind: atak_data_packages and a directory. Authenticated packages provide a client PKCS#12 and truststore directly. Trust-only packages require an enroll_trust_only block with users: stdin_csv and an enrollment endpoint. Packages must contain an unambiguous manifest and PKCS#12 member, have no unsafe ZIP paths or encryption, and all declare the same target.

Keys, certificates, passwords, CSV, manifest contents, and package paths are excluded from stdout, stderr, lifecycle events, and JSON reports.

Reusable GitHub Action

The repository includes a neutral composite action. Pin it to an approved full commit SHA; it installs the supported Rust toolchain and builds that exact source revision with --locked. With a configuration it runs the workload and returns the sanitized report path, but it never uploads artifacts, provisions fixtures, revokes credentials, or calls a server administration API:

- name: Run neutral routing check
  id: tak-bench
  uses: valmojr/tak_bench@<full-commit-sha>
  with:
    config: staging/routing.yaml
    report: artifacts/routing-report.json
    lifecycle-jsonl: "true"
    allow-staging-stress: "true" # only for an authorized, allowlisted staging target

- name: Upload sanitized evidence only
  uses: actions/upload-artifact@v7
  with:
    name: tak-bench-report
    path: ${{ steps.tak-bench.outputs.report-path }}
    if-no-files-found: error

When a consumer-owned wrapper must react to lifecycle events while the process is running, use setup-only mode and pass the binary output to that wrapper. The wrapper remains responsible for fixture lifecycle and any product-specific action:

- name: Build approved TAK Bench revision
  id: tak-bench
  uses: valmojr/tak_bench@<full-commit-sha>

- name: Run consumer staging wrapper
  env:
    TAK_BENCH_BIN: ${{ steps.tak-bench.outputs.binary-path }}
  run: ./scripts/run-staging-routing.sh

For enrollment or trust-only packages, use setup-only mode and have the consumer-owned wrapper provide the CSV through the binary's stdin. The action does not accept credential CSV as a regular input, write it to a temporary file, or place it in process arguments.

Lifecycle JSONL should be consumed live and discarded. Only the sanitized JSON report should be uploaded as evidence.

Development

cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
cargo build --release --locked
cargo package --locked

Slow local readers, bounded abrupt disconnects, bounded slow first writes, and carefully rate-limited invalid inputs are opt-in scenario controls. They are never production-safe. See scenario guidance.

Before a release tag, run an authorized mTLS preflight and smoke workload against the intended TAK Server version using examples/smoke-mtls.yaml. Loopback fixtures validate transport behavior but do not claim compatibility with every server deployment. See the GitHub Actions and release guide for the tag and artifact process.

License

Licensed under either the Apache License 2.0 or MIT license, at your option.

About

Smoke and stress testing TAK Servers/XML routing tool

Topics

Resources

Security policy

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages