Commit Graph

7 Commits

Author SHA1 Message Date
Chris Anderson
3b8793db37
feat: winnode CLI for invoking node commands over local MCP (#250)
* feat: winnode CLI for invoking node commands over local MCP

Mirrors `openclaw nodes invoke`'s flag surface but routes to the local
tray's MCP HTTP server (default http://127.0.0.1:8765/) instead of the
gateway. `--node` and `--idempotency-key` are accepted for paste-from-
gateway parity and ignored.

Ships skill.md alongside winnode.exe documenting every supported
command, argument schema, and the A2UI v0.8 JSONL grammar for agent use.

Tests: 62 cases, 100% line/branch on CliRunner via in-process unit tests
plus a loopback HttpListener fake that exercises the full HTTP path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(test): gate MCP readiness on token-bearing client

InitializeAsync would return ready as soon as `GET /` returned 200, even
if `mcp-token.txt` had not been read yet. Against a tray binary built
before the auth-before-dispatch hardening (where `GET /` answers 200
without auth), this raced ahead and handed back a tokenless `Client` —
every subsequent POST then 401'd. Restructure the loop to require both
the token-on-disk and a 200 from a token-bearing GET before declaring
ready.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(winnode): auto-load MCP bearer token

The CLI now sends `Authorization: Bearer <token>` on every MCP request,
without the user having to plumb the token themselves. Resolution chain
mirrors the per-tool secret convention (gh, az, anthropic):

  1. `--mcp-token <literal>` flag
  2. `OPENCLAW_MCP_TOKEN` env var (literal)
  3. `mcp-token.txt` under `$OPENCLAW_TRAY_DATA_DIR` if set, else
     `%APPDATA%\OpenClawTray\` — the same location SettingsManager
     points the tray at, so a sandboxed tray is found automatically.

When the token comes from disk, run `McpAuthToken.VerifyAcl` (the same
hygiene check `NodeService.StartMcpServer` runs at startup) and route
any owner/DACL warning to stderr so the user knows to rotate. `--verbose`
reports the resolved auth source without echoing the secret value.

Tests redirect via `OPENCLAW_TRAY_DATA_DIR` to a temp sandbox dir so they
don't pick up the developer machine's real tray token.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(winnode): apply 19 review findings (F-01..F-21)

Hardens the winnode CLI against the threat model in
C:/temp/winnode-cli-review-2026-04-30/01-findings.md. F-15 (port-0 nit)
was approved as no-action; F-17 was a positive observation.

- F-01/F-09: validate --mcp-url; refuse auto-loaded token off-loopback
- F-02: explicit SocketsHttpHandler with AllowAutoRedirect=false
- F-03: cap response body at 16 MiB with explicit overflow message
- F-04: warn unconditionally when --mcp-token is used (process-listing leak)
- F-05: warn unconditionally when --idempotency-key is supplied
- F-06: TokenLooksValid ASCII-printable check; ignore corrupt tokens
- F-07: don't echo full token-file path in --verbose
- F-08: canonicalize OPENCLAW_TRAY_DATA_DIR; reject symlink redirect
- F-10: RunAsyncTests is now IDisposable (cleans up sandbox dir)
- F-11: SkillMdDriftTests + REGENERATE-ME header in skill.md;
        McpToolBridge.KnownCommands exposes the canonical command set;
        skill.md re-synced with live capability surface
- F-12: --params @<path> loads JSON object from disk
- F-13: Token_file_with_wide_acl_emits_warn (Windows-only, gracefully
        skips when SetAccessControl is denied by hardened CI)
- F-14: BuildToolsCallBody returns (byte[], int) consumed by
        ByteArrayContent without a string round-trip
- F-16+F-21: SanitizeForStderr strips control chars, redacts ≥32-char
        base64url runs, caps at 4 KiB, default-quiet first-line-only,
        full sanitized body under --verbose
- F-18: --invoke-timeout capped at 600000 ms; long arithmetic on the
        +5000 buffer; out-of-range exits 2
- F-19: --mcp-port and OPENCLAW_MCP_PORT bounded [1, 65535]; env-var
        out-of-range falls back to default with a verbose warning
- F-20: distinguish missing/empty/unreadable/loaded token-file states;
        unreadable exits 1 with a diagnostic before any HTTP traffic

Tests: 23 added (115/115 pass). All other suites stay green
(Shared 1046/1066, Tray 245/245, Integration 18/18, UI 62/62).
WinNode CLI line coverage: 91.6% (434/474 in Program.cs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 09:27:50 -07:00
Sytone
1d836390e9
feat: SSH tunnel gateway, device identity, reconnect hardening
Adds SSH local port-forward support for secure remote gateway access, Ed25519 device identity for operator auth, enhanced Quick Send with error remediation, reconnect resilience, and OpenClaw.Cli validator tool.

Includes security fix: SSH user/host input validation to prevent command injection.

615 tests pass (516 shared + 99 tray).

Contributed by @sytone
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-01 00:03:43 -07:00
Scott Hanselman
882937299a docs: remove stale WinForms references, update test counts and capabilities
- README.md: Fix project table (OpenClaw.Tray → OpenClaw.Tray.WinUI),
  remove WinForms run command, add system.run.prepare and system.which
  to capability table and allowCommands JSON, remove '(investigating)'
  from canvas.a2ui commands
- DEVELOPMENT.md: Remove OpenClaw.Tray/ from structure, add
  OpenClaw.Tray.Tests/, update test counts (88 → 571), fix CI section
- build.ps1: Fix broken 'Tray' target to point at WinUI .csproj,
  remove WinForms from default build and run instructions
- docs/VERSIONING.md: Remove reference to deleted OpenClaw.Tray.csproj
- docs/TEST_COVERAGE.md: Full rewrite (88 → 571 tests, .NET 9 → 10)
- docs/CODE_REVIEW.md: Update project names, test counts, .NET version
- docs/WINDOWS_NODE_TESTING.md: Mark system.run as implemented, update
  capability descriptions
- docs/WINDOWS_NODE_ARCHITECTURE.md: Add historical planning note,
  update current state table (Node mode now implemented)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 20:38:13 -07:00
Scott Hanselman
bb06fb12c4 Fix WebView2 in unpackaged WinUI on ARM64
- Enable WindowsAppSDKSelfContained for registration-free WinRT activation
- Build script auto-detects architecture (win-arm64 / win-x64)
- WebChatWindow shows error details instead of silently falling back
- Remove conditional self-contained (always needed for WebView2)

The issue: WebView2 COM activation fails in unpackaged apps because
WinRT registration isn't available. Self-contained mode bundles the
'Undocked RegFree WinRT' which enables COM activation without MSIX.
2026-02-01 15:14:55 -08:00
Scott Hanselman
7b63816368 Add Windows SDK and WebView2 to prerequisites
- build.ps1 now checks for WebView2 Runtime
- README lists all prerequisites for WinUI build
- WebView2 check is informational (app falls back to browser)
2026-02-01 14:35:35 -08:00
Scott Hanselman
758ce08cf0 Upgrade all projects to .NET 10
- OpenClaw.Tray.WinUI: net9.0 -> net10.0
- OpenClaw.Shared: multi-target -> net10.0 single target
- Updated build.ps1 to only require .NET 10
- Updated README with .NET 10 only prerequisites
- Updated issue #10 comment
2026-02-01 14:34:50 -08:00
Scott Hanselman
5f18e7b530 Add build.ps1 script with prerequisite detection
- build.ps1 checks for .NET 9, .NET 10, Windows SDK
- Provides clear guidance on what's missing
- Supports building individual projects or all
- Fix README: correct dotnet run command (needs full .csproj path)
- Expanded Quick Start section with multiple build options

Fixes #10
2026-02-01 14:29:51 -08:00