Commit Graph

3 Commits

Author SHA1 Message Date
Joseph Doherty d59ce3571c [M3] mxaccess-nmx: high-level write/advise/un_advise wrappers (resolves F13)
Seven new high-level methods on NmxClient (port of cs:303-466). Each
takes a GalaxyTagMetadata + typed WriteValue (re-exported from
mxaccess-codec), builds the inner NMX body, wraps in NmxTransferEnvelope,
and dispatches via the existing transfer_data opnum.

Methods landed
- write (cs:303-324)
- write2 (cs:326-349, with explicit FILETIME timestamp)
- write_secured2 (cs:351-380, dual user tokens via
  secured_write::resolve_observed_user_token; single-user secured = same id)
- advise_supervisory (cs:382-399, ItemControl envelope)
- send_observed_pre_advise_metadata (cs:401-420, hardcoded target
  platform/engine = (1, 1) per the .NET reference)
- register_reference (cs:422-441, accepts caller-built
  NmxReferenceRegistrationMessage)
- un_advise (cs:443-466, deliberately uses
  NmxTransferMessageKind::Write per cs:457 — the .NET reference's
  divergence from AdviseSupervisory's ItemControl envelope, preserved
  verbatim per CLAUDE.md unknown-bytes rule)

Internal encode_*_transfer_body helpers extracted as pub(crate) fn for
testability — mirrors the .NET reference's `internal static` shape.

NmxClientError gained two new variants: Codec(CodecError) for
metadata->reference-handle and value-encode failures, and
UnsupportedDataType for the kind-resolution path.

Cargo.toml: added mxaccess-galaxy as a dep on mxaccess-nmx.

design/followups.md: F13 moved to Resolved.

Test count delta: 459 -> 468 (+9 in mxaccess-nmx; 8 -> 17). Tests cover
each encode helper standalone (envelope-kind + length checks) plus
real-socket round-trip tests for write / advise_supervisory /
send_observed_pre_advise_metadata.

All four DoD gates green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 08:45:03 -04:00
Joseph Doherty 0c772d273d [M3] mxaccess-nmx: NmxClient — 9 raw INmxService2 opnums (stream B)
Lands M3 stream B raw opnum surface: an async NmxClient over the
mxaccess-rpc transport that dispatches all 9 INmxService2 procedures
(GetPartnerVersion, RegisterEngine2 + WithoutCallback, UnregisterEngine,
Connect, AddSubscriberEngine, RemoveSubscriberEngine,
SetHeartbeatSendInterval, TransferData) plus a NonZeroHresult error
variant that mirrors ThrowIfFailed (cs:563-574).

New
- crates/mxaccess-nmx/src/client.rs (~580 LoC, 8 tests including 5
  real-socket tokio tests against a hand-rolled DCE/RPC server) — port
  of the raw opnum surface from ManagedNmxService2Client.cs.
- NmxClient::connect builds the NTLM-packet-integrity bind path; for
  tests, NmxClient::from_bound_transport accepts a transport bound any
  way the caller likes (the test server doesn't validate signatures).
- fresh_orpc_this generates a per-call Cid via rand::random(), mirroring
  the .NET reference's Guid.NewGuid() at every call site.
- NmxClientError::NonZeroHresult unifies the .NET reference's
  Marshal.ThrowExceptionForHR + InvalidOperationException branches so
  callers see one typed surface for "transport-OK + LMX rejected".

Cargo.toml: added tokio, tracing, thiserror, rand to mxaccess-nmx.

Two layers of the .NET reference are deliberately out of scope this
iteration; both logged as new followups in design/followups.md:

- F12 (P1): the auto-resolving Create() factory, which needs windows-rs
  COM activation (gated by F6) + ComObjRefProvider port.
- F13 (P1): the high-level Write*/Advise*/UnAdvise/RegisterReference
  helpers, which depend on GalaxyTagMetadata from M3 stream A (the
  Galaxy SQL resolver crate, not yet started).

Test count delta: 389 -> 397 (+8). All four DoD gates green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 08:06:15 -04:00
Joseph Doherty fe2a6db786 Initial project state: .NET reference, design, Rust port (M0+M1), evidence
rust / build / test / clippy / fmt (push) Has been cancelled
Layout:
- src/                    .NET 10 x64 reference: MxNativeCodec, MxNativeClient,
                          MxAsbClient, probes, tests, harnesses. Executable spec.
- design/                 Architectural plan for the Rust port (M0–M6), error
                          model, protocol invariants, risks (R1–R16), adversarial
                          review log (review.md).
- rust/                   Rust workspace. M0 skeleton + M1 codec parity.
                          mxaccess-codec: 215 unit tests + 2 cross-implementation
                          parity tests (byte-identical against .NET reference).
                          Other crates are M0 stubs awaiting M2+.
- captures/               Frida + netsh + pcap evidence per CLAUDE.md
                          ("captures are evidence, not throwaway logs").
- analysis/               Decompiled C# (frida/proxy/decompiled-*),
                          Ghidra exports for native DLLs (`exports/` only —
                          working state at `projects/` and AVEVA's input
                          binaries at `input/` are gitignored).
- docs/                   Reverse-engineering reference docs.
- tools/                  Setup-LiveProbeEnv.ps1 (Infisical credential fetcher),
                          Compute-Crc.ps1 (.NET parity helper).
- .github/workflows/      Rust CI: fmt + build + test + clippy on Windows.
- LICENSE                 MIT (Joseph Doherty, 2026).

Verified:
- cargo test --workspace → 217 passed (215 unit + 2 .NET parity), 0 failed
- cargo clippy --workspace -- -D warnings → clean
- cargo fmt --all -- --check → clean
- cargo publish --dry-run -p mxaccess-codec → packages cleanly

Excluded from history (see .gitignore):
- **/bin, **/obj, **/target — build artifacts
- analysis/ghidra/projects/ — Ghidra working state (regenerable)
- analysis/ghidra/input/ — AVEVA proprietary DLLs (vendor IP)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 06:21:00 -04:00