Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
160 commits
Select commit Hold shift + click to select a range
786b0f0
feat(openvtc-cli2): add state foundation and DIDComm message dispatch…
stormer78 Apr 14, 2026
677388f
feat(openvtc-cli2): add inbox panel UI with task interactions (Phase 2)
stormer78 Apr 14, 2026
8cbb057
feat(openvtc-cli2): add relationships panel with full management (Pha…
stormer78 Apr 14, 2026
037a273
feat(openvtc-cli2): add credentials panel with VRC management (Phase 4)
stormer78 Apr 14, 2026
6051a5d
feat(openvtc-cli2): add settings panel with config editing and export…
stormer78 Apr 14, 2026
7bbcfa8
feat(openvtc-cli2): UI refactoring and VRC issuance (Phase 6)
stormer78 Apr 14, 2026
d8e5be8
feat(openvtc-cli2): add hardware token management to settings panel
stormer78 Apr 14, 2026
35daed9
feat(openvtc-cli2): improve protection display and add passphrase man…
stormer78 Apr 14, 2026
37e025a
feat(openvtc-cli2): add activity log panel and close feature gaps
stormer78 Apr 14, 2026
bdea00b
feat(openvtc-cli2): add R-DID generation for relationship requests
stormer78 Apr 14, 2026
80289af
feat(openvtc-cli2): add status panel, contacts, import, display fixes
stormer78 Apr 14, 2026
350175d
fix(openvtc-cli2): persist config to disk after all mutations
stormer78 Apr 14, 2026
08567e3
refactor(openvtc-cli2): replace bit flags and control chars with type…
stormer78 Apr 14, 2026
7a3c7db
refactor(openvtc-cli2): extract action handlers from main match block
stormer78 Apr 14, 2026
811f4de
refactor(openvtc-cli2): use VecDeque for activity log
stormer78 Apr 14, 2026
923cdec
chore: release v0.2.0
stormer78 Apr 14, 2026
35b60cf
security(openvtc-cli2): remove passphrases from cloned State
stormer78 Apr 14, 2026
6640c2f
security(openvtc-cli2): message validation, dedup, bounds, sanitization
stormer78 Apr 14, 2026
ede1f1b
security(openvtc-cli2): zeroization, rate limiting, redaction, valida…
stormer78 Apr 14, 2026
3459283
refactor(openvtc-cli2): Rust idioms — error handling, must_use, docs
stormer78 Apr 14, 2026
c4f6b4f
refactor(openvtc-cli2): use Cow<str> in truncate_did to avoid allocation
stormer78 Apr 14, 2026
1c47f1b
feat: add config versioning with migration support
stormer78 Apr 14, 2026
b15ff38
refactor(openvtc-cli2): replace mpsc with watch channel for State upd…
stormer78 Apr 14, 2026
0f47806
feat(openvtc-cli2): auto-reconnect mediator on DID change
stormer78 Apr 14, 2026
c260f36
feat(openvtc-cli2): add outbound message queue for offline resilience
stormer78 Apr 14, 2026
40bc6df
refactor(openvtc-cli2): group Action enum into domain sub-enums
stormer78 Apr 14, 2026
b9f2da3
refactor(openvtc-cli2): introduce Panel trait for content panels
stormer78 Apr 14, 2026
5a5902b
test(openvtc-cli2): add unit test harness with 18 tests
stormer78 Apr 14, 2026
489aa7a
docs: update CHANGELOG for v0.2.0 with security, architecture, and id…
stormer78 Apr 14, 2026
47ac71c
perf(openvtc-cli2): enable bracketed paste for instant credential input
stormer78 Apr 14, 2026
3ee51f5
fix(openvtc-cli2): initialize main page state after setup wizard comp…
stormer78 Apr 14, 2026
54f124a
perf(openvtc-cli2): enable bracketed paste for all input fields
stormer78 Apr 14, 2026
539052a
feat(openvtc-cli2): add clipboard copy hotkeys for DIDs on status panel
stormer78 Apr 14, 2026
bbabcf6
fix(openvtc-cli2): allow backspace to clear relationship form fields
stormer78 Apr 14, 2026
93025af
feat(openvtc-cli2): show clipboard copy confirmation on status panel
stormer78 Apr 14, 2026
1482f6b
fix(openvtc-cli2): fix Tab key in relationship form after backspace fix
stormer78 Apr 14, 2026
dce993b
refactor(openvtc-cli2): replace manual messaging with DIDCommService
stormer78 Apr 14, 2026
9cdf8d7
fix(openvtc-cli2): pass DID secrets to DIDCommService listeners
stormer78 Apr 14, 2026
e917c8d
feat(openvtc-cli2): add Logs panel with scrollable activity log
stormer78 Apr 14, 2026
583dff4
feat: include friendly name in relationship request messages
stormer78 Apr 14, 2026
a73752b
feat(openvtc-cli2): inbox task count badge and arrow key navigation
stormer78 Apr 14, 2026
7b98e57
feat(openvtc-cli2): log trust-ping/pong events in activity log
stormer78 Apr 14, 2026
4515a92
fix(openvtc-cli2): VRC from field, auto-alias, and edit alias
stormer78 Apr 14, 2026
9fde914
feat(openvtc-cli2): trust-ping RTT latency in activity log
stormer78 Apr 14, 2026
b5a402a
feat(openvtc-cli2): show raw VRC JSON in credential detail with copy
stormer78 Apr 14, 2026
4ffca2c
feat(openvtc-cli2): periodic keepalive ping with live latency display
stormer78 Apr 14, 2026
892385b
feat(openvtc-cli2): R-DID listeners, accept with R-DID, VTA panel, lo…
stormer78 Apr 14, 2026
cd292ec
feat(openvtc-cli2): outbound task details, R-DID recommendation to re…
stormer78 Apr 14, 2026
1d32ed5
security(openvtc-cli2): only respond to trust-pings from known relati…
stormer78 Apr 14, 2026
6387033
feat(openvtc-cli2): VTA-based relationship DID creation
stormer78 Apr 14, 2026
6706d92
fix(openvtc-cli2): show progress during R-DID creation, fix alias on …
stormer78 Apr 14, 2026
35fc261
feat(openvtc-cli2): dynamic DID display width
stormer78 Apr 14, 2026
0696246
fix(openvtc-cli2): use relationship DID for all R-DID message flows
stormer78 Apr 14, 2026
c438594
docs: comprehensive CHANGELOG update for v0.2.0
stormer78 Apr 14, 2026
aa4412f
fix(openvtc-cli2): show progress feedback when accepting relationship…
stormer78 Apr 14, 2026
eef680f
fix(openvtc-cli2): use thid for relationship lookup in message dispatch
stormer78 Apr 14, 2026
4cdc842
debug(openvtc-cli2): add tracing for DIDComm message send/receive
stormer78 Apr 14, 2026
3b07904
merge: integrate main into release/v0.1.6
stormer78 Apr 15, 2026
87ebb7d
fix: harden relationship establishment flow with 14 robustness improv…
stormer78 Apr 15, 2026
1f3aefa
fix: load R-DID secrets on startup for pending relationships
stormer78 Apr 15, 2026
8771ae8
feat(openvtc-cli2): add Enter-to-expand detail view for activity log …
stormer78 Apr 15, 2026
802e456
fix: deduplicate R-DID listener configs to prevent WebSocket reconnec…
stormer78 Apr 15, 2026
5281f6c
fix: increase listener restart backoff to prevent WebSocket reconnect…
stormer78 Apr 15, 2026
bb4b4b7
fix: use OnFailure restart policy and add connection cycling detection
stormer78 Apr 15, 2026
83363fa
feat(openvtc-cli2): add OPENVTC_DEBUG_LOG env var for file-based debu…
stormer78 Apr 15, 2026
93f75aa
docs(openvtc-cli2): add troubleshooting section with debug logging guide
stormer78 Apr 15, 2026
8f47b59
fix(openvtc-cli2): wrap debug log file writer in Mutex for thread-saf…
stormer78 Apr 15, 2026
bcaed9f
fix: stop ATM profile from opening duplicate WebSocket to mediator
stormer78 Apr 15, 2026
7f098ac
fix: send accept message via R-DID listener to match encryption keys
stormer78 Apr 15, 2026
2cbab55
feat(openvtc-cli2): structured activity log with detailed DIDComm dia…
stormer78 Apr 15, 2026
fd43ce9
fix: remove overly strict sender validation on accept messages
stormer78 Apr 15, 2026
4886f68
refactor: use persona DIDs for all relationship handshake messages
stormer78 Apr 15, 2026
a3d55ab
fix: resolve trust-pong sender to contact alias instead of 'unknown'
stormer78 Apr 15, 2026
7153656
feat(openvtc-cli2): detailed activity log for trust-ping/pong operations
stormer78 Apr 15, 2026
a50dd80
fix: resolve pong sender when from field is missing, improve ping detail
stormer78 Apr 15, 2026
b0fa750
fix: set from field on trust-pong response messages
stormer78 Apr 15, 2026
8ce74f6
fix: resolve clippy warnings for CI (collapsible_if, too_many_argumen…
stormer78 Apr 15, 2026
34d829e
fix: clean up trust-ping task when pong has no from field
stormer78 Apr 15, 2026
f110c51
refactor: simplify and deduplicate relationship flow code
stormer78 Apr 15, 2026
c43a186
chore: switch affinidi-messaging-didcomm-service back to crates.io v0…
stormer78 Apr 15, 2026
ceb72b0
feat(openvtc-cli2): request VRC from relationship detail view
stormer78 Apr 15, 2026
cd4126b
fix: show actual connection latency instead of 0ms
stormer78 Apr 15, 2026
db466cc
fix: VRC issued message rejected as duplicate task ID
stormer78 Apr 15, 2026
9f1227e
fix: don't show connection setup time as ping latency
stormer78 Apr 15, 2026
de1bcd8
refactor: restructure generate_profiles for faster startup
stormer78 Apr 15, 2026
29d2470
feat: concurrent VTA key fetches and dependency upgrade
stormer78 Apr 15, 2026
82116eb
fix: keepalive ping uses self-ping via mediator instead of pinging me…
stormer78 Apr 15, 2026
776d3b4
refactor: remove mediator keepalive ping and latency display
stormer78 Apr 15, 2026
25f4d9a
feat(openvtc-cli2): show VRCs in relationship detail view
stormer78 Apr 15, 2026
da6bbcb
feat: enable Linux kernel keyring fallback for headless environments
stormer78 Apr 15, 2026
86b0091
feat(openvtc-cli2): browse and expand VRCs in relationship detail view
stormer78 Apr 15, 2026
e7e53e4
fix: use kernel keyring (keyutils) on Linux instead of Secret Service
stormer78 Apr 15, 2026
986e273
fix: load persona secrets after setup wizard before connecting
stormer78 Apr 15, 2026
7f9a372
feat(openvtc-cli2): show active context and DIDs in VTA panel
stormer78 Apr 15, 2026
4b4f29d
feat(openvtc-cli2): show VTA context name in context panel
stormer78 Apr 15, 2026
a976fe3
fix: eliminate TOCTOU race in lock file creation (#45)
stormer78 Apr 16, 2026
cddf217
fix(cli): delete inbound messages by mediator-native id only
stormer78 Apr 17, 2026
6007909
chore(release): note mediator delete-id fix in 0.2.0 changelog
stormer78 Apr 17, 2026
1ef6fb8
chore(release): correct 0.2.0 changelog date to 2026-04-17
stormer78 Apr 17, 2026
a4b345e
fix: init setup + commit signing e2e test (#46)
affrncsp Apr 18, 2026
8679bab
fix(cli2): wrap long errors in status panes and log full cause chain
stormer78 Apr 21, 2026
9f46994
fix(cli2): surface VTA credential bundle errors on the paste page
stormer78 Apr 21, 2026
a8d860b
fix(openvtc): build placeholder did:webvh via didwebvh-rs, validate U…
stormer78 Apr 21, 2026
e4d9c5f
docs: add CLAUDE.md with project overview and did:webvh guidance
stormer78 Apr 21, 2026
53317b6
fix(post-pr41): address SecretString hardening follow-ups
stormer78 Apr 21, 2026
6a376b8
fix(cli2): lock setup wizard inputs while async action is in flight
stormer78 Apr 22, 2026
04c4331
feat(cli2): wrap and scroll right-hand content panel
stormer78 Apr 22, 2026
703af9a
feat(cli2): confirm unlock code in setup wizard
stormer78 Apr 22, 2026
0c84c50
chore(workspace): pin local vta-sdk 0.5 + adjust to new SDK surface
stormer78 Apr 30, 2026
45f4e36
feat(cli2): replace paste-bundle setup with online VTA provisioning
stormer78 Apr 30, 2026
3d9129b
chore(workspace): migrate from keyring 3.6 to keyring-core 1.0
stormer78 Apr 30, 2026
d058a46
feat(did-git-sign): replace --credential paste with online VTA provis…
stormer78 Apr 30, 2026
61b3bfe
refactor(did-git-sign): expose init::install via a library crate
stormer78 Apr 30, 2026
b91883d
feat(cli2): auto-configure did-git-sign as part of setup wizard
stormer78 Apr 30, 2026
b8c2781
feat(did-git-sign): add uninstall (lib + CLI subcommand)
stormer78 Apr 30, 2026
1e1b71a
feat(cli2): show did-git-sign principal + SSH key on the help screen
stormer78 Apr 30, 2026
707c065
feat(cli2): wipe profile from Settings menu
stormer78 Apr 30, 2026
e78f857
feat(cli2): SSH-aware clipboard with OSC 52 + arboard fallback
stormer78 Apr 30, 2026
c2bfce7
feat(cli2,did-git-sign): switch provisioning to AdminRotated intent
stormer78 Apr 30, 2026
1b631e8
feat(cli2): visualize admin DID rotation on bootstrap page
stormer78 Apr 30, 2026
5c58763
feat(cli2): prompt before configuring did-git-sign during setup
stormer78 Apr 30, 2026
091dd31
fix(cli2): use DIDComm transport end-to-end on DIDComm-only VTAs
stormer78 Apr 30, 2026
4f47496
fix: persist + reuse chosen VTA transport at runtime
stormer78 Apr 30, 2026
f0c7f90
fix(did-git-sign): support DIDComm-only VTAs
stormer78 Apr 30, 2026
6622072
fix(cli2): remove contact + alias when relationship is deleted
stormer78 Apr 30, 2026
965b63e
chore(workspace): switch vta-sdk to published 0.5 from local path pin
stormer78 May 5, 2026
953d6b1
refactor(cli2): drop dead VtaAuthenticate setup page
stormer78 May 5, 2026
9bfdce1
refactor(workspace): rename to single openvtc binary + openvtc-core lib
stormer78 May 5, 2026
0006581
docs: align v0.2.0 release notes and supporting docs with rename
stormer78 May 5, 2026
ed0124f
chore(deps): refresh transitive deps to clear dependabot alerts
stormer78 May 5, 2026
037c131
fix: surface previously-swallowed errors and remove startup panics
stormer78 May 5, 2026
9b6e9a7
feat(did-git-sign): gate signing on parent process + audit every attempt
stormer78 May 5, 2026
fbbdbec
refactor(openvtc-core): drop ratatui and dialoguer dependencies
stormer78 May 5, 2026
b3b8d01
chore(crypto): bump Argon2id parameters for KEK derivation
stormer78 May 5, 2026
0482a2e
refactor: lift DID truncation helpers into openvtc-core::display
stormer78 May 5, 2026
1fd44c2
refactor(openvtc-core): tighten pub surface — drop dead re-exports + …
stormer78 May 5, 2026
468b3d4
fix(didcomm): drop replays + stale messages before state-mutating dis…
stormer78 May 5, 2026
ae756c1
fix: tighten untrusted-input handling at three boundaries
stormer78 May 5, 2026
a507fc5
chore(ci): add cargo-deny + cargo-llvm-cov coverage; bump MSRV check
stormer78 May 5, 2026
3684edd
fix(didcomm): bound the inbound-event channel so a noisy mediator can…
stormer78 May 5, 2026
33ef6cb
test(setup-flow): table-driven coverage for navigation::navigate
stormer78 May 5, 2026
73d5a26
test(openvtc-core): BIP32 KAT + AES-GCM tampering coverage
stormer78 May 5, 2026
0507aef
refactor(state-handler): move Inbox dispatch into inbox_actions
stormer78 May 5, 2026
0a52e64
refactor(state-handler): move Relationship dispatch into relationship…
stormer78 May 5, 2026
7389505
refactor(state-handler): move Credential dispatch into credential_act…
stormer78 May 5, 2026
0a59985
refactor(state-handler): move Settings + Contact dispatch into settin…
stormer78 May 5, 2026
b9fbd83
feat(crypto): per-entry random Argon2 salt with transparent v1->v2 mi…
stormer78 May 5, 2026
5a6252c
test(openvtc-core): in-process mediator harness for integration tests
stormer78 May 5, 2026
09c7bdf
test: scaffold relationship E2E integration test (WIP, ignored)
stormer78 May 5, 2026
0edf8e0
test(openvtc-core): real DIDComm round-trip over the in-process mediator
stormer78 May 5, 2026
bebff03
test + docs: relationship-protocol round-trip + CHANGELOG post-review…
stormer78 May 5, 2026
7e513d5
test(openvtc-core): VRC request + reject round-trip over the mediator
stormer78 May 5, 2026
8245a3c
test(openvtc-core): migrate harness to affinidi-messaging-test-mediat…
stormer78 May 5, 2026
4f5aa6b
deps: bump affinidi-tdk to 0.7, test-mediator to 0.2 + simplify harness
stormer78 May 5, 2026
7b020f8
docs: refresh CHANGELOG for harness migration + dep refresh; fix MSRV…
stormer78 May 5, 2026
98b1e90
fix(validation): trim profile names, reorder empty check first (#57)
stormer78 May 5, 2026
275507c
fix(paths): cross-platform config path with PathBuf + Windows AppData…
stormer78 May 5, 2026
b8f344a
security(secured_config): tagged-variant downgrade defence + intent g…
stormer78 May 5, 2026
7aad915
docs: changelog entries for the three community-PR folds
stormer78 May 5, 2026
4d8d72a
fix(did-git-sign): address #46 review follow-ups (#52)
stormer78 May 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion .cargo/audit.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# Advisories to ignore (transitive dependencies we cannot easily update)
# Advisories to ignore (transitive dependencies we cannot directly update).
#
# All entries below are in crates pulled transitively through affinidi-tdk,
# vta-sdk, didwebvh-rs, and other third-party workspace dependencies — not
# in anything openvtc depends on directly. Each entry is reviewed when a
# fix becomes available upstream.
[advisories]
ignore = [
# rsa: Marvin Attack timing sidechannel — no patch available yet.
Expand All @@ -9,4 +14,14 @@ ignore = [
# Pinned to 0.8 because aes-gcm 0.10 requires rand_core 0.6.
# We do not use a custom logger that calls rand::rng().
"RUSTSEC-2026-0097",

# proc-macro-error: unmaintained.
# Pulled via static-regular-grammar → xsd-types → ssi-caips → affinidi
# crates. No security impact; awaiting upstream migration to
# proc-macro-error2.
"RUSTSEC-2024-0370",

# rustls-pemfile: unmaintained (both 1.x via reqwest 0.11 and 2.x via
# tonic). No security impact identified; purely a maintenance advisory.
"RUSTSEC-2025-0134",
]
37 changes: 35 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ jobs:
- uses: Swatinem/rust-cache@v2
- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y libpcsclite-dev libdbus-1-dev
- run: cargo doc --workspace --no-deps --exclude openvtc-cli
- run: cargo doc --workspace --no-deps
env:
RUSTDOCFLAGS: -D warnings

Expand All @@ -94,7 +94,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.91.0
- uses: dtolnay/rust-toolchain@1.94.0
- uses: Swatinem/rust-cache@v2
- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y libpcsclite-dev libdbus-1-dev
Expand All @@ -108,3 +108,36 @@ jobs:
- uses: rustsec/audit-check@v2.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}

deny:
name: Cargo Deny (licenses + advisories + bans)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: EmbarkStudios/cargo-deny-action@v2
with:
command: check advisories licenses bans sources

coverage:
name: Coverage (llvm-cov)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview
- uses: Swatinem/rust-cache@v2
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y libpcsclite-dev libdbus-1-dev
- name: Generate coverage (lcov)
# Includes ignored tests so any future #[ignore]-gated integration
# tests still contribute to the report.
run: cargo llvm-cov --workspace --lcov --output-path lcov.info -- --include-ignored
- name: Upload lcov artifact
uses: actions/upload-artifact@v4
with:
name: lcov.info
path: lcov.info
retention-days: 30
126 changes: 126 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,132 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

## [0.2.0] - 2026-05-05

### Added

- **Full TUI main menu panels** in `openvtc` — 8 panels: Inbox, Relationships, Credentials, Settings, VTA Service, Logs, Help/Status, Quit
- **Inbox panel** with real-time task processing: auto-handles trust-pongs, relationship finalization, and rejections; queues interactive tasks; detail views for all task types (inbound/outbound requests, VRCs, pings, informational)
- **Relationships panel** with list/detail/new-request views, inline alias editing ('e' key), R-DID privacy toggle, trust-ping with RTT latency
- **Credentials panel** with Received/Issued tabs, raw VRC JSON in detail view, clipboard copy ('c' key), VRC request and removal
- **Settings panel** with inline editing, config export/import, passphrase protection management, hardware token detection and factory reset
- **VTA Service panel** showing VTA URL, DID, credential DID, key count, and backend type
- **Logs panel** with scrollable timestamped activity log, selected entry copy ('c'), copy all ('a')
- **Activity log panel** at bottom of screen showing real-time timestamped events (`[HH:MM:SS] message`)
- **Status/Help panel** with DID clipboard copy hotkeys ([1] persona, [2] mediator), visual feedback on copy
- **R-DID generation** for both BIP32 and VTA backends — VTA path authenticates and creates keys via API; both sender and receiver can use R-DIDs
- **Dynamic R-DID listeners** — automatically added when creating R-DIDs (sender or receiver), enabling message delivery to relationship-specific DIDs
- **VRC issuance** from inbox with DataIntegrityProof signing; **VRC rejection** with message back to requester
- **Friendly name in relationship requests** — sender's name included in request body, auto-set as contact alias on accept, R-DID recommendation shown when sender uses one
- **DIDComm service integration** (`affinidi-messaging-didcomm-service` 0.2) — replaces manual messaging with Router-based dispatch, automatic reconnection, message pickup, and multi-DID listener support
- **Periodic keepalive ping** (60s) with live RTT latency in connection status header
- **Inbox task count badge** on menu item ("Inbox (3)" in red when tasks pending)
- **Bracketed paste** for all 21 text input fields — paste is instant regardless of string length
- **Up/Down arrow navigation** in all multi-field forms alongside Tab
- **Config versioning** with stepwise migration framework
- **Panel trait** for content panels — unified render interface
- **Outbound message retry** via `DIDCommService::send_message_with_retry`
- **Auto-reconnect mediator** on DID change in settings
- 15 unit tests covering core functions
- **Contact management** actions (add/remove)

### Security

- Trust-pings only responded to from mediator DID or established relationships — prevents presence leakage
- Passphrases removed from cloned State — length-only fields in UI, consumed via `mem::take`
- Token admin PIN wrapped in `Arc<SecretString>` for shared allocation
- Inbound message body size validation (1MB limit), task ID deduplication, sender verification
- Collection bounds (10K tasks, 5K relationships), untrusted display text sanitization
- Unlock rate limiting (5 attempts, exponential backoff), path redaction, file path validation
- Key material explicit drop with documented zeroization limitation
- Structured audit log entries for security-relevant operations

### Fixed

- **R-DID message routing** — acceptance, finalize, VRC, and ping messages now use relationship DID instead of persona DID when R-DID exists
- **Config persistence** — all mutating actions save to disk
- **Setup → main transition** — `sync_from_config()` now called after setup wizard completes
- **VRC "From:" blank** — extract remote DID from relationship for VRC tasks
- **Alias on accept** — sender's name set as contact alias, existing alias-less contacts updated
- **Backspace to empty** in relationship form fields
- **Tab after backspace fix** — dedicated `FocusField` action for field switching
- **DIDComm listener secrets** — pass DID secrets to listeners for mediator authentication
- All `.unwrap()`/`.expect()` replaced with proper error propagation
- Clipboard graceful degradation, `sanitize_display` ANSI stripping order

### Changed

- **Workspace consolidation** — renamed the active CLI package and binary `openvtc-cli2` → `openvtc`, and renamed the supporting library `openvtc-lib` → `openvtc-core`. The unsuffixed name now belongs to the user-facing binary, matching the convention used by uv, ruff, deno, and cargo. The library is `publish = false`, so no external consumers are affected.
- **`vta-sdk` 0.5** consumed from crates.io — dropped the temporary `../verifiable-trust-infrastructure/vta-sdk` path pin so the workspace no longer requires a sibling checkout to build.
- **Replaced manual messaging layer** with `affinidi-messaging-didcomm-service` — deleted messaging/mod.rs (~280 lines) and outbound_queue.rs (~90 lines), added didcomm.rs (~260 lines) with Router, listeners, and send_message_with_retry
- Grouped ~65-variant Action enum into 5 domain sub-enums
- `tokio::sync::watch` replaces mpsc for State updates
- Panel trait with per-panel structs implementing unified render interface
- Dynamic DID display width (`shorten_did(did, max_width)` — 60 chars default, full if fits)
- `Cow<str>` for zero-alloc DID truncation
- Explicit `Arc::clone()`, `#[must_use]` on pure functions, doc comments on State types
- `VecDeque<String>` for O(1) bounded activity log
- `RelationshipRequestBody.name` protocol field for friendly names

### Removed

- **Legacy `openvtc-cli` crate** — the original prompt-driven CLI was phased out in favour of the TUI. All ongoing work lives in `openvtc`.
- **Dead `VtaAuthenticate` setup page** — online provisioning emits `VtaAuthCompleted` directly from `VtaProvisioning`, so the legacy authenticate screen was unreachable.

### Post-release deep-review pass

After cutting the v0.2.0 branch a multi-axis review (code quality, security, tests, docs) flagged a set of findings that landed on the same release branch before merge. They're listed separately so the diff between v0.1.x and v0.2.0 stays readable.

#### Security

- **Per-entry random Argon2 salt with transparent v1→v2 migration.** `derive_passphrase_key` previously used a deterministic salt = SHA-256(info), so two operators with the same passphrase produced the same KEK and exported backups were byte-comparable. The new `passphrase_encrypt_v2` / `passphrase_decrypt` API in `openvtc-core::config::secured_config` writes a magic-prefixed `[OPV2 | salt(16) | nonce(12) | ct+tag]` blob with a fresh random salt; the decrypt path auto-detects v1/v2 so existing exports keep opening. Argon2id parameters bumped to OWASP "high-value KEK" floor (m=128 MiB, t=4, p=1).
- **`did-git-sign` signing policy.** The proxy now refuses to sign unless the parent process name starts with `git` or `ssh-keygen`, and writes every signing attempt — accepted or denied — to `~/.config/did-git-sign/audit.log` (mode 0600) with parent PID/name, namespace, buffer path and SHA-256. Blocks the "malicious build script obtains a signature with namespace=git over attacker-chosen content" pivot.
- **DIDComm replay window + seen-message LRU** in `process_inbound_message`: drop messages with `created_time` outside ±48h / +5m skew, drop messages whose `expires_time` already passed, dedupe on a 1024-entry process-lifetime ID LRU.
- **DID validation** uses a real W3C DID Core 1.0 syntax parser instead of a `did:` prefix check; rejects bidi-override / zero-width chars in DID fields.
- **Inbox display-name sanitisation** strips bidi-override / isolate / zero-width / BOM unicode (Cf class) plus ANSI escapes / control chars, and clamps inbound contact aliases to 64 chars before persistence.
- **Bounded DIDComm event channel** (256-entry capacity) so a noisy mediator can't grow memory without limit; overflow logs and drops, mediator pickup redelivers when we drain.
- **`did.jsonl` write path** is now the resolved profile dir, not the current working directory.
- **Dependabot:** transitive openssl/rustls-webpki/rand bumped via `cargo update` to clear nine open advisories. `pgp` was already at the patched 0.19.
- **Tagged-variant downgrade defence on `SecuredConfigFormat`.** Switched the on-disk variant tag from `#[serde(untagged)]` to `#[serde(tag = "format")]` so every blob carries an explicit `"format"` discriminator. Without it, an attacker with write access to the OS keychain could substitute a `PasswordEncrypted` blob with `{"text": "<plaintext>"}` and serde would silently match it as `PlainText`, bypassing AES-256-GCM. New `assert_format_matches_intent` cross-validation gate adds a second defence layer — a tagged-but-weaker blob is rejected before any decrypt or re-save. Old (untagged) blobs migrate transparently on first load. Folded from @ojasshelke's PR #34; the PR's HKDF v2 fixed-salt variant is superseded by our random-per-entry-salt v2 (`OPV2` magic prefix) above.

#### Community contributions

Three community PRs against `main` were assessed and folded into the release. Each PR's substantive value is preserved with `Co-authored-by:` trailers; the corresponding PRs are closed with a comment pointing here.

- **#57 — profile-name validation hardening (@sameerchore).** `validate_profile_name` now trims leading/trailing whitespace before validating, and the empty/whitespace check runs before the character check (so `" "` gets a clear "cannot be empty or contain only whitespace" error instead of the confusing "Invalid profile name ' '"). Three new integration tests pin the behaviour.
- **#51 — cross-platform config paths (@krsatyamthakur-droid, closes #47).** `profile_dir` and `get_lock_file` now use `dirs::config_dir()` on Windows (typically `%APPDATA%\openvtc`); Unix/macOS continues to use `~/.config/openvtc/` so existing installs don't move. `get_config_path` and `get_lock_file` return `PathBuf` instead of `String` end-to-end.
- **#34 — `SecuredConfig` serde-format hardening (@ojasshelke).** Tagged-variant downgrade defence + intent-gate cross-validation, described under Security above. The PR's HKDF v2 fixed-salt scheme was superseded by our random-salt OPV2 v2 and intentionally not folded.

#### Architecture & code quality

- **State-handler split.** `state_handler/mod.rs` was 2,255 lines with a 500-line `tokio::select!` arm; it's now 813 lines (-64%). Each per-domain match (Inbox, Relationship, Credential, Settings, Contact) was extracted to a `dispatch(action, ctx).await` entry point in the corresponding sub-module.
- **Layering:** moved `colors.rs` and the `dialoguer` passphrase prompt out of `openvtc-core` so the daemon (`openvtc-service`) and automation (`robotic-maintainers`) crates no longer pull in `ratatui` + `dialoguer` transitively.
- **Lifted four DID-truncation helpers** into a single `openvtc-core::display` module (`truncate_did`, `truncate_did_centered`).
- **Tightened `openvtc-core` public surface** — dropped a dead `pub use` re-export and scoped two helpers to `pub(crate)`.
- **Fixed silent failures** in the state handler: surfaced previously-swallowed `save_config` / `remove_listener` / inbox-task errors via `log_error`. Replaced four `.expect("valid route")` panics in DIDComm router init with `?`. Replaced `panic!("Cannot create log file …")` with stderr + continue.
- **Fixed DIDComm-only VTA fallback** in `relationships.rs` (used `build_runtime_vta_client` instead of REST-only `challenge_response`).

#### Tests & CI

- **In-process mediator harness** (`openvtc-core/tests/common/mod.rs`): wraps the upstream `affinidi-messaging-test-mediator` 0.2 fixture via `TestMediator::with_users(["alice", "bob"])`, which boots a real `affinidi-messaging-mediator` on an ephemeral loopback port (memory-backed store, generated `did:peer` identity advertising `dm`/`#auth`/`#ws`, Ed25519 JWT signing keypair) and returns Alice + Bob as ALLOW_ALL accounts whose DIDComm service URI is the mediator's DID — the routing/2.0 shape required for forwards to short-circuit to local delivery instead of being enqueued for external forwarding. The previous in-tree harness predated the test-mediator crate; the migration drops ~400 lines of fixture code and four dev-deps (`affinidi-messaging-mediator`, `-mediator-common`, `-sdk`, `sha256`).
- **End-to-end integration tests** (`relationship_e2e.rs`): drive a real Alice→Mediator→Bob DIDComm round-trip, a production `RelationshipRequestBody` round-trip, and a two-leg VRC request/reject round-trip — all in ~350ms once the mediator is up. Plus a smoke test (`mediator_smoke.rs`) that asserts the well-known endpoint serves a DID Document. Marked `#[ignore]` (each spawns the mediator, ~1s); CI's coverage job runs them with `--include-ignored`.
- **38 new unit tests** across `setup_flow/navigation` (25 table-driven), BIP32 derivation (7 known-answer vectors), AES-GCM tampering (6) — locking the wizard flow, derivation contract, and AEAD failure modes before the v0.3.0 work begins.
- **CI** adds a `cargo-deny` job (advisories + licenses + bans + sources, with documented `RUSTSEC-2023-0071` rsa Marvin-Attack and `RUSTSEC-2024-0370` proc-macro-error ignores) and a `cargo-llvm-cov` coverage job (uploads `lcov.info` artifact, runs ignored tests). MSRV check bumped 1.91 → 1.94 to match `Cargo.toml`.

#### Dependency refresh

Picks up the May 2026 Affinidi-stack releases. All bumps cleared on crates.io; build, full test suite, and integration tests pass.

- **`affinidi-tdk` 0.6 → 0.7** — accessor-method API on `TDKSharedState`/`TDKEnvironment`/`TDKProfile`. Field accesses (`.secrets_resolver`, `.environment`, `.profiles`, `.default_mediator`, `.ssl_certificate_paths`) are now method calls. `TDKSharedState::default().await` (removed in tdk 0.6) replaced with `TDKSharedState::new(TDKConfig::headless()?).await?` in `openvtc-service`.
- **`affinidi-messaging-didcomm-service` 0.2 → 0.3** — version bump driven by the upstream `MediatorACLSet` error-type relocation; downstream impact is `?`-transparent thanks to `From<ACLError> for ATMError`.
- **`affinidi-messaging-test-mediator` 0.1 → 0.2** (dev-deps only) — `TestMediator::with_users(["alice", "bob"])` replaces our hand-rolled `MemoryStore` + ALLOW_ALL registration dance. Drops `affinidi-messaging-mediator`, `-mediator-common`, `-sdk` and `sha256` from dev-deps.
- Working with the upstream maintainers, this branch's review of the May 2026 test-mediator changes also surfaced two follow-ups landing post-publication: an IPv6 routing-classification fix and `mediator-common` feature-gating to keep the SDK light. Neither is on the path used by openvtc tests (loopback over `127.0.0.1`).

#### Docs

- README, CONTRIBUTING, SECURITY, CLAUDE.md aligned to the post-rename workspace shape (`openvtc` binary + `openvtc-core` lib).
- CHANGELOG `[0.2.0]` entry above describes the release as it actually shipped.

## [0.1.5] - 2026-04-14

### Security
Expand Down
Loading
Loading