# Session Log — 2026-05-30 (work spanning 2026-05-29 evening → 2026-05-30) ## User - **User:** Mike Swanson (mike) - **Machine:** GURU-5070 - **Role:** admin ## Session Summary The session opened as a GuruRMM feature request ("Mobile device support") and ran through the `/feature-request` flow. After clarifying scope (MDM for phones/tablets **plus** a GuruRMM mobile agent app — treated as one coherent feature), produced `SPEC-017-mobile-device-support.md`. The central technical finding documented: the iOS/Android capability asymmetry — an Android Device Admin app delivers real remote lock/wipe with no server certificate, but a sandboxed iOS App Store app cannot lock/wipe without an MDM enrollment profile (which needs the free Apple MDM Push Certificate). Mike then confirmed ACG now holds **both** Apple certificates (Developer Program + signing, and the MDM Push Certificate), so the spec was updated to mark both iOS phases Apple-cert-unblocked, with the annual MDM-push-cert renewal trap flagged. The bulk of the session was a full GuruConnect (GC) modernization effort. Mike asked whether a `gc-audit` equivalent to `/rmm-audit` existed; it did not, so a `gc-audit` skill was authored, adapted to GC's actual architecture (protobuf wire format, runtime sqlx, Gitea Actions CI, static-HTML+component-library dashboard) rather than copying RMM assumptions. The skill was then run as a dry run: seven parallel/ sequential audit passes on Opus surfaced **three CRITICAL relay-plane auth failures** (any-JWT-joins-any-session, viewer-WS blacklist bypass, JWT-accepted-as-agent-key) plus the dashboard's wire-incompatible "protobuf" decoder, a stubbed deploy step leaving production 57 commits stale, and several HIGH/MEDIUM items. The audit report was committed and the skill was refined (use `.claude/standards/` as the compliance baseline; reconcile all `docs/specs/SPEC-*.md` + `specs/*/plan.md` `[DONE]` markers; tag already-planned findings `[TRACKED]` during a rebuild). Mike then directed a ground-up re-spec. Produced `SPEC-002-v2-modernization-architecture.md` from four locked decisions: greenfield-but-salvage-proven-Rust-cores; native-first with full key fidelity (Win+R / Ctrl+Alt+Del / clipboard) and WebRTC only as a fallback; standalone-first with a versioned `/api/integration/v1/` RMM contract; hardened single-tenant now with a tenancy-ready schema. File transfer (clipboard cut/paste + drag-and-drop, bidirectional) was elevated to a headline differentiator after Mike named it as a favorite ScreenConnect feature. `/shape-spec` then produced `specs/v2-secure-session-core/` (Phase 1). The Phase-1 keystone was implemented end to end across four tasks, each via a Coding Agent (Opus) → mandatory Code Review (Opus) → Gitea Agent commit loop: Task 1 (v2 schema + per-agent `cak_` keys + tenancy-ready columns), Task 2 (auth rebuild deleting the JWT-as-agent-key branch, session-scoped viewer tokens, per-agent key issuance, folding in a pre-existing machine-metadata bug fix), Task 3 (secure relay WS — viewer-token verification with blacklist + session-claim match, agent identity binding, frame caps, input throttle), and Task 4 (in-memory rate limiting + single-use widened support codes). A review-driven authorization-strength fix split viewer tokens into VIEW_ONLY vs CONTROL gated on permission, fully closing CRITICAL #1. Because the dev machine has no Rust toolchain, all code was verified on the build host (172.16.3.30) and confirmed compiling + passing tests (32/32), and the Gitea Actions CI was confirmed green. Every audit CRITICAL and HIGH in the auth/session core is now remediated in code. The session closed with a `/sync` (pulled four of Howard's auto-sync commits) and a radio-show task: set the "promised vs got / best invention" episode to today's date (Saturday 2026-05-30), preserved Howard's Segments 1-2, and expanded the reserved Segment 3 into a topical May-2026 tech-news segment (AI glasses, AI-and-jobs, subscription squeeze, orbital data centers, AI security reality check, gadget hits) using live web research, since the assistant's training only runs to ~Jan 2026. ## Key Decisions - **SPEC-017 scope:** treat "mobile device support" as MDM + a GuruRMM mobile agent app together; document the iOS/Android lock-wipe asymmetry rather than over-promising iOS parity. - **gc-audit adapted, not copied:** GC uses runtime sqlx (not RMM's macros — and CLAUDE.md's "compile-time checked queries" line is stale), protobuf wire format, Gitea Actions CI, and a static-HTML+component-library dashboard. The skill's passes were rewritten accordingly; Pass B's initial "macros are the GC norm" rule was later corrected to flag new `query!` macros as a `[LOW]` deviation. - **GC v2 direction (4 locked decisions):** greenfield-salvage-cores; native-first full key fidelity (WebRTC fallback only); standalone-first + versioned RMM contract; hardened single-tenant with a tenancy-ready (nullable `tenant_id`) schema so Phase 4 flips on isolation with no migration rewrite. - **File transfer elevated:** clipboard cut/paste + drag-and-drop (both directions) made a core differentiator with a delayed-render clipboard design, not a deferred panel. - **v2 sqlx + repo:** confirmed runtime `sqlx::query()` for v2 (GC already uses it); clean architectural reset in-place in the existing `guru-connect` repo (not a new repo). - **Auth-strength (CRITICAL #1):** viewer-token minting gated on permission, and — after review found `view` is held by every default role — split into VIEW_ONLY (gated on `view`, relay refuses input) vs CONTROL (gated on `control`/admin) tokens. This is what actually closed CRITICAL #1. - **Codec/transport/cutover:** H.264 default (HEVC opt-in); Phase-2 web viewer on protobuf-over-WSS first (WebRTC later); widened higher-entropy support codes; clean wholesale v1→v2 cutover (no client data to migrate). - **Verification path:** with no local Rust toolchain, all Rust was verified by building + testing on the build host (172.16.3.30) and by confirming Gitea Actions CI, rather than trusting self-review. - **Radio Segment 3:** built as a "present-day" bookend tying each item back to Segments 1-2; pulled live (web search) because training is stale for a same-day show. ## Problems Encountered - **Gitea push failed mid-session** (internal :3000 refused, public 502) — a transient blip; later confirmed reachable and the pending commit had already been swept upstream by auto-sync. No loss. - **Explore agent reported two GC docs at the repo root** (`FEATURE_ROADMAP.md`, `ARCHITECTURE_DECISIONS.md`) that actually live under `docs/`; caught and corrected the gc-audit skill's paths before finalizing. - **CI red on Tasks 2/3/authz** — but only at the `cargo fmt --all --check` gate, which short-circuits before clippy/build/test, so the code had never actually compiled in CI. Verified on the build host that it compiled + passed; applied the fmt patch + two clippy one-liners (`8a01935`) → CI green. - **Task 4 clippy red** — `empty_line_after_doc_comments` (rate_limit.rs) and two dead-code event constants (events.rs); fixed (`2118942`, build-host-verified) → CI green. - **Audit authz finding:** Task 2/3's first authz gate used `has_permission("view")`, which is held by every default role, so it didn't actually narrow access; reviewer caught it, leading to the VIEW_ONLY/CONTROL split. - **Coord todo POSTs failed twice on an em-dash** ("error parsing the body"); resolved by using ASCII-only text. (Same lesson recurred and was applied.) - **No Rust toolchain on GURU-5070** — every Coding Agent could author but not compile; mitigated by build-host verification (172.16.3.30) for each task. ## Configuration Changes **`azcomputerguru/guru-connect` (separate repo):** - New: `docs/specs/SPEC-002-v2-modernization-architecture.md`, `reports/2026-05-29-gc-audit.md`, `specs/v2-secure-session-core/{plan,shape,references,standards}.md`. - New (server): `migrations/004_v2_secure_session_core.sql`, `005_machine_metadata.sql`, `006_widen_support_code.sql`; `src/db/{agent_keys.rs,tenancy.rs}`; `src/auth/agent_keys.rs`; `src/api/machine_keys.rs`. - Rebuilt/modified (server): `src/middleware/rate_limit.rs` (+mod.rs), `src/relay/mod.rs`, `src/api/sessions.rs`, `src/auth/{jwt.rs,mod.rs}`, `src/db/{machines,sessions,support_codes,events,users,mod}.rs`, `src/support_codes.rs`, `src/main.rs`, `Cargo.toml` (removed `tower_governor`). - Episode/radio: n/a (different repo). **`azcomputerguru/gururmm` (submodule):** - New: `docs/specs/SPEC-017-mobile-device-support.md`; `docs/FEATURE_ROADMAP.md` updated (MDM checklist + Asset Location Tracking cross-link to SPEC-017). **`azcomputerguru/claudetools` (this repo):** - New: `.claude/skills/gc-audit/SKILL.md` (then refined twice). - New memory: `.claude/memory/project_apple_mdm_certs.md`, `.claude/memory/project_guruconnect_v2_direction.md`; `MEMORY.md` index updated. - Radio: created `projects/radio-show/episodes/2026-05-30-promised-vs-got-and-inventions/show-prep.md` (expanded, 25KB); `git rm` of `projects/radio-show/episodes/tbd-promised-vs-got-and-inventions/`. - This session log. ## Credentials & Secrets - No new secrets created. - Gitea API token used for CI status checks: SOPS vault `services/gitea.sops.yaml`, field `credentials.api.api-token`. - ACG holds both Apple certs as of 2026-05-29 (Developer Program + signing; MDM Push Certificate). **Still to capture:** the exact owning Apple ID and expiry for the MDM Push Certificate (renews annually on the same Apple ID or all enrolled iOS devices break) — see `.claude/memory/project_apple_mdm_certs.md`. ## Infrastructure & Servers - **Coordination API:** `http://172.16.3.30:8001/api/coord` (locks, todos) — no auth. - **Gitea (internal):** `http://172.16.3.20:3000` (azcomputerguru org). Public: `git.azcomputerguru.com` (NPM/Cloudflare; prefer internal). - **GC build/deploy host:** `172.16.3.30` (Linux, Rust toolchain present; GC server runs on `:3002` behind NPM at `connect.azcomputerguru.com`; GC clone at `/home/guru/guru-connect`). Production GC binary was stale (git `1bfd476`, ~2026-01-18) vs submodule HEAD — deploy step is a stub. - **Gitea Actions runners (online):** `guruconnect-builder` (ubuntu-latest), `pluto-guruconnect` (windows-msvc, on Pluto 172.16.3.36). - GC DB: PostgreSQL on the GC host; v2 migrations 004-006 added (not yet applied to production). ## Commands & Outputs - `cargo fmt --all` / `cargo clippy --all-targets --all-features -- -D warnings` / `cargo build --release --target x86_64-unknown-linux-gnu` / `cargo test --release` — run on `172.16.3.30` to verify GC v2 (no local toolchain). Note: must set `CARGO_BUILD_TARGET=x86_64-unknown-linux-gnu` on Linux because the repo `.cargo/config.toml` defaults to `x86_64-pc-windows-msvc`. - GC v2 keystone test result on build host: `32 passed; 0 failed`. - CI: build-and-test run on `2118942` — build-server, build-agent, security-audit all success. - Coord todo POST: requires ASCII-only body (`text`, `created_by_user`, `created_by_machine` required); em-dashes cause "error parsing the body". - `git rm -r projects/radio-show/episodes/tbd-promised-vs-got-and-inventions/` — old radio folder removed after writing the dated one. ## Pending / Incomplete Tasks - **GC v2 Phase 1 remainder:** Task 5 (attended-mode consent — proto `ConsentRequest`/`ConsentResponse`), Task 6 (native viewer full key fidelity — WH_KEYBOARD_LL hook, scan-code injection, SAS for Ctrl+Alt+Del, clipboard sync), Task 7 (HW H.264 + raw/Zstd fallback). Then Phase 2 (file transfer + dashboard + web viewer), Phase 3 (`/api/integration/v1/` RMM contract), Phase 4 (multi-tenancy switch-on). Source of truth: `specs/v2-secure-session-core/plan.md` + `docs/specs/SPEC-002-*.md`. - **Open coord todos (guruconnect):** `9a462965` (revoke viewer tokens on logout), `3c1f372a` (trusted-proxy client-IP keying — NPM-on-loopback collapses clients to 127.0.0.1), `542137df` (multi-instance fail-closed DB single-use gate). Plus two `TODO(audit-events)` comments in `db/events.rs`. - **GC v2 deploy:** wire the real `deploy.yml` SSH step (currently a stub) and chain `cargo audit` into release/deploy; v1→v2 cutover after the product-capability tasks. - **SPEC-017 mobile:** capture the Apple MDM Push Certificate's owning Apple ID + expiry; provision Google Play/FCM. - **Radio:** Mike's "best invention" pick (Segment 2); refresh Segment 3 items if the show slips past 2026-05-30. ## Reference Information - **Specs:** `guru-connect/docs/specs/SPEC-002-v2-modernization-architecture.md`, `guru-connect/specs/v2-secure-session-core/`, `guru-connect/specs/native-remote-control/`; `gururmm/docs/specs/SPEC-017-mobile-device-support.md`. - **Audit report:** `guru-connect/reports/2026-05-29-gc-audit.md`. - **gc-audit skill:** `.claude/skills/gc-audit/SKILL.md`. - **Memory:** `.claude/memory/project_apple_mdm_certs.md`, `.claude/memory/project_guruconnect_v2_direction.md`. - **Commit SHAs — guru-connect:** `486debf` (audit report), `5c60a10` (SPEC-002), `81e4b99` (shape spec), `fef8111` (T1), `41691bf` (T2), `0f25878` (T3), `a453e79` (authz split), `8a01935` (fmt/clippy), `bfcdbb5` (T4), `2118942` (clippy fix). - **Commit SHAs — gururmm:** `417856e` (SPEC-017). - **Commit SHAs — claudetools:** `e8ac759`, `df6a2dd`, `e5ccb6a`, `c670471`, `c70cd70` (gc-audit skill). - **Coord todos (guruconnect):** done — `faf39fe0`, `c8916c89`; open — `9a462965`, `3c1f372a`, `542137df`. - **Radio episode:** `projects/radio-show/episodes/2026-05-30-promised-vs-got-and-inventions/show-prep.md`. --- ## Update: 11:49 PT — GuruConnect v2 Phase 1 COMPLETED (Tasks 5-7, trusted-proxy fix) + local Rust toolchain ### Session Summary (this update) Continued from the morning save and completed all of GuruConnect v2 Phase 1 (the secure-session-core). After the morning's Tasks 1-4 + authz split, this block delivered, in order: the trusted-proxy client-IP fix, Task 5 (attended consent), a local Rust toolchain on GURU-5070, the agent-crate clippy cleanup, Task 6 (full key fidelity — the headline), and Task 7 (HW H.264 + negotiated raw fallback). Each followed the Coding Agent (Opus) → Code Review (Opus) → commit loop. Phase 1 is now complete; every CRITICAL and HIGH from the 2026-05-29 audit is remediated in code. Trusted-proxy fix (todo 3c1f372a): GC runs behind NPM on loopback, so axum `ConnectInfo` was always 127.0.0.1 — the Task-4 rate limiter/lockout bucketed every external client into one key (one abuser could lock out everyone). Added shared `utils::ip_extract::client_ip` honoring X-Real-IP / rightmost-untrusted X-Forwarded-For ONLY when the TCP peer is a configured trusted proxy (`CONNECT_TRUSTED_PROXIES` env, default loopback, fail-closed); wired into the limiter, relay, and audit logging. Task 5 (consent): proto `ConsentRequest`/`ConsentResponse`; the server gates an attended session at `join_session` (invisible to the tech until granted; `StartStream` only fires from `join_session`, so an unconsented session never streams), 60s timeout → teardown, Windows MessageBox dialog (fail-closed). Mid-session, installed a full local Rust toolchain on GURU-5070 (rustup/cargo 1.96, MSVC C++ Build Tools, protoc 35.0 via winget; `PROTOC` env set), ending the per-task build-host round-trips. This Windows machine builds BOTH the server and the Windows agent locally — better coverage than the Linux build host, which can't compile the agent. The local clippy immediately exposed that CI never clippy-checks the agent crate (build-server clippy is Linux-only; build-agent only runs `cargo build`); 77 pre-existing agent clippy errors had accumulated. Cleaned them up (commit d0de888, behavior-preserving, code-reviewed) and filed a todo to add agent-clippy to CI. Task 6 (full key fidelity — headline): `WH_KEYBOARD_LL` hook on the viewer diverts system combos (Win/Win+R, Alt+Tab, Ctrl+Esc) to the remote as full `KeyEvent`s and suppresses local handling, GATED on viewer focus + a toggle so it never bricks the technician's own keyboard; scan-code `SendInput` with correct extended-key flags; Ctrl+Alt+Del completes through the SAS helper (SYSTEM `SendSAS`, `SoftwareSASGeneration` policy); modifier hygiene re-syncs key-ups on focus loss. Review caught a BLOCKER — the hook wasn't focus-scoped — fixed. Task 7 (codec, last): encoder trait + factory; capability negotiation (`AgentStatus.supports_h264` + server `select_video_codec` + `StartStream.video_codec`); MF H.264 encoder + viewer decoder (FIRST-CUT, compile-verified-only, default-OFF via `DEFAULT_PREFER_H264=false`); raw+Zstd byte-for-byte unchanged as the guaranteed default. Task 6/7 were authored AND verified locally (fmt/clippy/test/build) — the toolchain payoff. ### Key Decisions (this update) - Installed the local Rust+MSVC+protoc toolchain on GURU-5070 to end build-host round-trips; Coding Agents now self-verify locally and hand back CI-green code. Recorded in memory `reference_guru5070_rust_toolchain`. - Cleaned the 77 pre-existing agent clippy errors BEFORE Task 6 (which edits agent code) so the local clippy loop runs on a clean base; filed a CI todo (CI never lints the agent). - Trusted-proxy IP: honor forwarding headers ONLY from a configured trusted-proxy allowlist (default loopback), fail-closed; never trust a header from an untrusted (spoofable) peer. - Task 6 hook focus-gated (`VIEWER_FOCUSED` AtomicBool, set from `WindowEvent::Focused`) so it diverts system keys only when the viewer window is focused. SAS named-pipe DACL tightened from NULL/Everyone to Authenticated Users. - Task 7 ships H.264 dormant (`DEFAULT_PREFER_H264=false`): raw+Zstd is what runs; H.264 is compile-verified-only until live hardware validation (Task 8). `unsafe impl Send for H264Encoder` verified sound (session future is `block_on`-driven, never `spawn`ed). ### Problems Encountered (this update) - Local clippy (cargo 1.96, newer than CI's 1.94) exposed 77 pre-existing agent clippy errors CI never caught → cleaned up + filed the CI-gap todo. (Local rustfmt 1.9 vs CI 1.8: empirically verified NO skew — `cargo fmt --check` clean on the CI-green HEAD.) - Task 6 Code Review BLOCKER: the `WH_KEYBOARD_LL` hook diverted system combos regardless of viewer focus, so an unfocused viewer would swallow the technician's own Win/Alt+Tab/Ctrl+Esc → fixed with the focus gate. - Coord lock-release jq one-liner failed (locks endpoint shape); left to auto-expire (harmless). Em-dash in a todo POST failed again ("error parsing the body") → ASCII-only retry. - Bash-tool CWD persisted into the `guru-connect` submodule from `git apply` calls, so a relative `.claude/scripts/...` path resolved wrong; use absolute paths. ### Configuration Changes (this update) **guru-connect:** new `server/src/utils/ip_extract.rs` (trusted-proxy client-IP); new `agent/src/consent/mod.rs` (Task 5); new `agent/src/encoder/{h264,capability,color}.rs` + `agent/src/viewer/decoder.rs` (Task 7). Modified across server (relay, session, middleware/rate_limit+mod, main, auth, db/{machines,sessions,events,users}, api) and agent (viewer/{input,render,mod}, input/{keyboard,mod}, session, bin/sas_service, ~22 files in the clippy sweep), proto/guruconnect.proto, agent/Cargo.toml, Cargo.lock (pruned), and the plan.md task markers. **claudetools:** new memory `.claude/memory/reference_guru5070_rust_toolchain.md` + MEMORY.md index line. **GURU-5070 machine:** rustup (cargo 1.96 at `~/.cargo/bin`), VS2022 Build Tools (VCTools workload), protoc 35.0 (winget). `PROTOC` set as a User env var. ### Commands & Outputs (this update) - Local GC verify (PowerShell, from the guru-connect dir): `$env:PROTOC="C:\Users\guru\AppData\Local\Microsoft\WinGet\Packages\Google.Protobuf_Microsoft.Winget.Source_8wekyb3d8bbwe\bin\protoc.exe"; cargo fmt --all; cargo clippy --workspace --all-targets --all-features -- -D warnings; cargo test --workspace; cargo build --workspace` — all green (Task 7: 89 tests). Default target is `x86_64-pc-windows-msvc`; builds server + agent. - `winget install Rustlang.Rustup` / `Microsoft.VisualStudio.2022.BuildTools` (`--override "--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"`) / `Google.Protobuf`. ### Pending / Incomplete Tasks (this update) - **GC v2 Phase 1 is COMPLETE (Tasks 1-7).** Next: **Task 8 — live hardware validation** (esp. the H.264 first-cut go-live gates), then **Phase 2** (file transfer + dashboard + web viewer — v2 has NO operator dashboard yet, so it is NOT a full v1 replacement until Phase 2), **Phase 3** (`/api/integration/v1/` RMM contract), **Phase 4** (multi-tenancy switch-on). - **Open coord todos (guruconnect):** `9a462965` (viewer-token revocation on logout), `542137df` (multi-instance fail-closed DB single-use gate), `addd7eea` (add agent-clippy to the build-agent CI job), + the H.264-go-live gating todo (live-validate, real force-IDR via CODECAPI, document the no-spawn invariant, graceful decode-worker spawn). **Closed this update:** `3c1f372a` (trusted-proxy). - **GC v2 deploy:** `deploy.yml` SSH step still a stub; v1→v2 cutover deferred until at least Phase 2 (needs the dashboard). ### Reference Information (this update) - **New commit SHAs — guru-connect:** `5d5cd26`+`8cb0b5b` (trusted-proxy IP), `9082e11`+`fbf9e26` (Task 5 consent), `d0de888` (agent clippy cleanup), `bb73ba6` (Task 6 key fidelity), `f9bdecb` (Task 7 codec). - **Local toolchain memory:** `.claude/memory/reference_guru5070_rust_toolchain.md`. - **Plan (source of truth):** `guru-connect/specs/v2-secure-session-core/plan.md` (Tasks 1-7 all marked done/implemented).