Skip to content

Add trace-commons-operator-client foundation crate - #124

Closed
zmanian wants to merge 1 commit into
mainfrom
trace-commons-operator-client-foundation
Closed

zmanian wants to merge 1 commit into
mainfrom
trace-commons-operator-client-foundation

Conversation

@zmanian

@zmanian zmanian commented May 19, 2026

Copy link
Copy Markdown
Collaborator

Context

This is PR #1 of a three-PR stack that brings operator-side CLI workflows to this repo. The 39 operator commands previously living in Ironclaw's ironclaw traces ... surface were just pruned out of Ironclaw in nearai/ironclaw#3738 — they will re-emerge here as four standalone binaries (one per audience). This PR lays the foundation those binaries will share.

What lands

New workspace member trace-commons-operator-client:

  • Client — wraps reqwest::Client with:
    • Bearer-token resolution from an env var (never logged).
    • Host allowlist enforcement (defense-in-depth against a poisoned --endpoint flag).
    • Typed error mapping for the server's {\"error\": \"<Label>\"} refusal envelope.
  • Error taxonomy — BearerMissing, InvalidEndpoint, HostNotAllowed, Transport, HttpFailure, ServerLabel, MalformedResponse. Each carries a .user_diagnostic() that strips query strings + fragments for safe stderr output.
  • HostAllowlist — exact-match, case-insensitive, sourced from --allowed-hosts <CSV> or TRACE_COMMONS_ALLOWED_HOSTS. Subdomains are not implicit matches.
  • Output helpers — JsonEnvelope wrapper for --json mode ({ \"request\": {...}, \"data\": <server-response> }), ASCII table renderer with column auto-sizing, key-value block renderer for single-record commands.

What doesn't land

Per-endpoint typed request/response structs are deferred to:

If a request/response struct turns out to be shared across binaries when those PRs land, it migrates back here.

Verification

RUSTFLAGS=\"-D warnings\" cargo check --workspace --all-targets   # clean
cargo test -p trace-commons-operator-client                       # 30 passed
cargo clippy -p trace-commons-operator-client --all-targets -- -D warnings  # clean

Test plan

  • CI green.
  • Manual verification by maintainer: review the error taxonomy against the server's refusal-label set in trace_upload_claim_allowlist.rs and similar reviewer/admin gate sites — flag any label naming we should reflect at the client-error level.
  • Confirm TRACE_COMMONS_ALLOWED_HOSTS semantics match operator expectations (currently: comma-separated, exact-match, case-insensitive, no wildcards).

Out of scope

🤖 Generated with Claude Code

New workspace member that holds the shared HTTP transport + foundational
types for the upcoming operator binaries (trace-commons-review,
trace-commons-worker, trace-commons-admin, trace-commons-tenant). These
binaries take over the operator-side CLI surface that was pruned from
Ironclaw's reborn trace client in nearai/ironclaw#3738.

Surface in this PR:
- Client with bearer-token resolution from an env var (never logged),
  host-allowlist enforcement, and typed error mapping for the server's
  {"error": "<Label>"} refusal envelope.
- Error taxonomy: BearerMissing, InvalidEndpoint, HostNotAllowed,
  Transport, HttpFailure, ServerLabel, MalformedResponse. Each carries
  a user_diagnostic() that strips query strings + fragments.
- HostAllowlist with exact-match semantics, case-insensitive, sourced
  from --allowed-hosts or TRACE_COMMONS_ALLOWED_HOSTS.
- Output helpers: JsonEnvelope wrapper for --json mode, ASCII table
  renderer, key-value renderer for single-record commands.

Per-endpoint typed request/response structs land in PR #2 (reviewer +
admin) and PR #3 (worker + tenant). When a struct turns out to be
shared across binaries it migrates back here.

Verification:
- cargo check --workspace --all-targets under -D warnings: clean
- cargo test -p trace-commons-operator-client: 30 passed
- cargo clippy -p trace-commons-operator-client --all-targets -- -D warnings: clean
zmanian added a commit that referenced this pull request May 20, 2026
CI on PR #124 surfaced fmt diffs across the operator-client foundation
and the review/admin/worker binaries. Applied cargo fmt --all to bring
the stack into compliance. Pure formatting; zero behavior change.
zmanian added a commit that referenced this pull request May 20, 2026
Lands the four-PR stack (#124, #125, #126, #127) as a single squash commit on main.

## What's in this squash

**1. `trace-commons-operator-client` foundation crate** (was #124)
- `Client` wrapper around `reqwest::Client` with bearer-token resolution from env, host allowlist enforcement, typed error mapping for `{"error": "<Label>"}` refusals.
- Error taxonomy: `BearerMissing`, `InvalidEndpoint`, `HostNotAllowed`, `Transport`, `HttpFailure`, `ServerLabel`, `MalformedResponse`. `Error::user_diagnostic()` strips query strings + fragments.
- `HostAllowlist` (CSV, exact-match, case-insensitive) sourced from `--allowed-hosts` or `TRACE_COMMONS_ALLOWED_HOSTS`.
- Output helpers: `JsonEnvelope` wrapper for `--json` mode, ASCII table renderer, key-value block renderer.

**2. `trace-commons-review` (8 cmds) + `trace-commons-admin` (12 cmds)** (was #125)
- Single shared bearer per binary (`TRACE_COMMONS_REVIEWER_BEARER`, `TRACE_COMMONS_ADMIN_BEARER`).
- 37 binary tests across both (parse-through, body validation, wiremock round-trips).

**3. `trace-commons-worker` (8 cmds) + `trace-commons-tenant` (11 cmds)** (was #126)
- Worker uses per-subcommand bearer envs (8 distinct env vars, one per route gate). Verified by `worker_per_route_bearer_resolution_uses_distinct_envs`.
- Tenant uses single shared `TRACE_COMMONS_TENANT_BEARER`.
- Operator runbook at `docs/operator/operator-binaries.md`.
- CI smoke job `operator-binaries-smoke` in `.github/workflows/ci.yml`, sibling to `pilot-bootstrap-smoke`.

**4. Privacy-filter-canary port** (was #127)
- New `trace_commons_operator_client::privacy_filter` module: `PrivacyFilterAdapter` trait, `CommandPrivacyFilterAdapter`, `SafePrivacyFilterRedaction`, `adapter_from_env`, `canary_leaked_tokens`. Wire shapes byte-identical to Ironclaw's sidecar protocol.
- Dual-name env-var compat: `TRACE_COMMONS_PRIVACY_FILTER_*` canonical, `IRONCLAW_TRACE_*` legacy fallback with warn-on-use.
- `trace-commons-tenant privacy-filter-canary` stub replaced with the real handler.

## Operator surface added

| Binary | Cmds | Bearer model |
|---|---:|---|
| `trace-commons-review` | 8 | Single `TRACE_COMMONS_REVIEWER_BEARER` |
| `trace-commons-admin` | 12 | Single `TRACE_COMMONS_ADMIN_BEARER` |
| `trace-commons-worker` | 8 | Per-subcommand defaults |
| `trace-commons-tenant` | 11 | Single `TRACE_COMMONS_TENANT_BEARER` |
| **Total** | **39** | |

These mirror the 39 operator commands removed from Ironclaw in nearai/ironclaw#3738.

## Verification

```
cargo check --workspace --all-targets   (-D warnings)   # clean
cargo test --workspace --no-run         (-D warnings)   # clean
cargo clippy --workspace --all-targets  (-D warnings)   # clean
cargo test -p trace-commons-operator-client            # 39 passed
cargo test -p trace-commons-server --bins              # all green
bash scripts/operator/operator-smoke.sh                # SmokeOperatorBinariesOK
```

Superseded PRs (closed): #124, #125, #126.
@zmanian

zmanian commented May 20, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #127. The trace-commons-server stack (#124 → #125 → #126 → #127) was squash-merged top-down per the project's stacked-PR merge convention; #127's squash captures this PR's full diff (the trace-commons-operator-client foundation crate). No code is lost.

Closing as superseded.

@zmanian zmanian closed this May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant