Files
ruvnet--RuView/v2/crates/wifi-densepose-cli/Cargo.toml
T
Dragan Spiridonov 6d3fb88677 fix(cli): resolve scope from the token on read, and add whoami --refresh
Two gaps that only appear with a credential file written by an earlier build —
i.e. exactly the case a fresh-login test never exercises.

1. `whoami` printed "Scope: (not reported)" for an existing file. The previous
   commit resolved scope from the token claim at WRITE time only, so files
   written before it stayed blank forever. `effective_scope()` now falls back at
   READ time, which fixes existing files and any client that stored only what
   the token response carried. The token is authoritative either way; the stored
   field is a convenience copy.

2. `whoami` said the token "will refresh on next use" — a promise nothing kept,
   because no command called `ensure_fresh`. The refresh path was implemented
   and unit-tested but never actually run. `--refresh` exercises it, and goes
   through `Session::ensure_fresh` rather than reimplementing a second, subtly
   different refresh, so it inherits the single-flight guarantee and the
   persist-before-return ordering.

   It is a flag, not silent behaviour: refreshing rotates the stored refresh
   token — identity spends the old one — so it is a state change, not a read.

VERIFIED AGAINST PRODUCTION, end to end:
  whoami on a pre-existing file        -> Scope: sensing:read (was "not reported")
  whoami --refresh                     -> both tokens rotated
                                          refresh sha256[:12] 50cfa06b -> 2d37617a
                                          access  sha256[:12] 61eebe8d -> 14d8e8de
                                          status: expired -> valid
  refreshed token GET  /api/v1/models      -> 200
  refreshed token POST /api/v1/train/start -> 401 (still read-scoped)

That exercises the rotating-refresh path against identity's real reuse
detection — the one place a bug costs the user their session rather than a
retry — and confirms the scope gate survives a refresh.

Tests: 82 with --features login, 44 default, 501 sensing-server.

Co-Authored-By: Ruflo & AQE
2026-07-22 18:21:49 +02:00

84 lines
2.6 KiB
TOML

[package]
name = "wifi-densepose-cli"
version = "0.3.1"
edition.workspace = true
description = "CLI for WiFi-DensePose"
authors.workspace = true
license.workspace = true
repository.workspace = true
documentation = "https://docs.rs/wifi-densepose-cli"
keywords = ["wifi", "cli", "densepose", "disaster", "detection"]
categories = ["command-line-utilities", "science"]
readme = "README.md"
[[bin]]
name = "wifi-densepose"
path = "src/main.rs"
[features]
# `mat` pulls wifi-densepose-mat → -nn → ort (ONNX) → openssl-sys, which does NOT
# cross-compile to aarch64 and is irrelevant to the calibration path. Build the
# Pi/appliance calibration binary with `--no-default-features` to exclude it.
default = ["mat"]
mat = ["dep:wifi-densepose-mat"]
[dependencies]
# Internal crates
wifi-densepose-mat = { version = "0.3.0", path = "../wifi-densepose-mat", optional = true }
wifi-densepose-signal = { version = "0.3.1", path = "../wifi-densepose-signal", default-features = false }
wifi-densepose-core = { version = "0.3.0", path = "../wifi-densepose-core" }
wifi-densepose-calibration = { version = "0.3.0", path = "../wifi-densepose-calibration" }
# Linear algebra / complex numbers (used by calibrate.rs to build CsiFrame)
ndarray = { workspace = true }
num-complex = { workspace = true }
# CLI framework
clap = { version = "4.4", features = ["derive", "env", "cargo"] }
# Output formatting
colored = "2.1"
tabled = { version = "0.20", features = ["ansi"] }
indicatif = "0.17"
console = "0.16"
# Async runtime
tokio = { version = "1.35", features = ["full"] }
# HTTP API server (calibrate-serve subcommand — drives a future UI)
axum = { workspace = true }
tower-http = { version = "0.6", features = ["cors", "trace"] }
# Serialization
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
csv = "1.3"
# Error handling
anyhow = "1.0"
# ADR-271 phase 2 — `login`/`logout`/`whoami`. The `login` feature carries the
# interactive half (PKCE, loopback, OOB paste, credential store, refresh);
# the sensing server depends on this same crate with default features and
# gets only the verifier.
ruview-auth = { path = "../ruview-auth", features = ["login"] }
# Only for constructing the HTTP client hands to Session.
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
thiserror = "2.0"
# Time
chrono = { version = "0.4", features = ["serde"] }
# UUID
uuid = { version = "1.6", features = ["v4", "serde"] }
# Logging
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
[dev-dependencies]
assert_cmd = "2.0"
predicates = "3.0"
tempfile = "3.9"
tower = { workspace = true }