Port openframe-client updates from openframe-oss-tenant (round 2: Jul 6–22) - #1527
Conversation
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: denys-gif <denys@flamingo.cx>
…ken.enc (#2092) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… tool-restart flow, silence detection (#2138) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: denys-gif <denys@flamingo.cx>
… with sibling listeners (#2163) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Ivan <ivan@flamingo.cx>
sort_by(|a, b| b.0.cmp(&a.0)) -> sort_by_key(Reverse) per the repo -D warnings gate; originates in tenant #2169, same fix applies upstream. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011z7MGH2qYeKt2ZQV88EaD8
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe client adds update verification and rollback handling, reconnect-aware NATS listeners, bounded execution concurrency, guarded tool restarts, proactive token refresh, atomic configuration writes, and MeshCentral self-healing changes. TacticalRMM wiring and installer scripts are removed. ChangesClient lifecycle and update orchestration
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…s_borrows_in_formatting) CI runners moved to Rust 1.97 whose new lint fires on pre-existing code in registration_client.rs (untouched by this port; latent on main). Verified clippy-clean on 1.97 for both the host target and x86_64-pc-windows-gnu. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011z7MGH2qYeKt2ZQV88EaD8
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
clients/openframe-client/src/services/openframe_client_info_service.rs (1)
68-81: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winSame read-modify-write hazard just fixed elsewhere in this PR is still present here.
reconcile_version(and the pre-existingupdate_version/set_update_status/set_binary_path) all doget()→ mutate a field →save()with no synchronization — the identical lost-update pattern that this PR just fixed inAgentConfigurationServicevia a newwrite_lock: Arc<Mutex<()>>(seeagent_configuration_service.rs). If two of these methods are ever called concurrently (e.g. update-flow status transitions racing with a version reconciliation), one write can silently clobber the other's field.Consider applying the same
Arc<Mutex<()>>guard pattern used inAgentConfigurationServicehere for consistency.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@clients/openframe-client/src/services/openframe_client_info_service.rs` around lines 68 - 81, Protect the read-modify-write sequences in OpenFrameClientInfoService methods reconcile_version, update_version, set_update_status, and set_binary_path with the same Arc<Mutex<()>> write-lock pattern used by AgentConfigurationService. Initialize the lock with the service and acquire it before each get/mutation/save sequence, ensuring concurrent updates cannot overwrite one another.clients/openframe-client/src/services/token_refresh_run_manager.rs (1)
49-67: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winConsider capped/backoff retry instead of a fixed 60s forever-retry.
On persistent
reauthenticate()failure (e.g. revoked refresh token, prolonged auth-server outage), this inner loop retries everyRETRY_INTERVALindefinitely with no backoff or cap. That's a steady drumbeat of auth calls with no eventual escalation (e.g. falling back to re-registration).♻️ Suggested backoff sketch
- sleep(RETRY_INTERVAL).await; + sleep(next_backoff_delay(&mut consecutive_failures)).await;Please confirm whether
AgentAuthService::reauthenticate()already applies its own backoff/circuit-breaking internally — if so this is lower priority.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@clients/openframe-client/src/services/token_refresh_run_manager.rs` around lines 49 - 67, Update the retry loop surrounding AgentAuthService::reauthenticate() to avoid fixed-interval retries forever: add bounded exponential backoff and a maximum retry duration or attempt count, then escalate through the existing re-registration or failure path when the limit is reached. Preserve the immediate success exit and distinguish timeout from authentication errors; first verify whether reauthenticate() already provides equivalent backoff or circuit breaking and avoid duplicating it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@clients/openframe-client/src/services/openframe_client_update_service.rs`:
- Around line 104-111: Normalize the build-time OPENFRAME_VERSION value to
canonical semver before comparing it in the update flow. Apply the same
normalized value to the already-running check around canonical_version and
downstream target_version comparisons, preserving the short-circuit when
versions are semantically equal despite a v prefix or build metadata.
In `@clients/openframe-client/src/services/tool_kill_service.rs`:
- Around line 52-74: Update collect_matching_processes to ignore empty pattern
entries before applying cmdline or executable-path matching. Ensure empty
strings cannot satisfy contains and cause every process to be collected,
preserving normal matching for non-empty patterns and protecting callers such as
is_installed_tool_running and stop_tool_by_path.
In `@clients/openframe-client/src/utils/fs.rs`:
- Around line 16-21: The atomic write utility must not force replacement files
to world-readable 0644. Update atomic_write to accept an explicit file mode from
each caller, use 0600 for token-bearing agent configuration, and preserve
appropriate modes for non-sensitive callers; revise the affected test to assert
the secure caller-specific mode instead of 0644.
In `@clients/openframe-client/src/utils/jwt.rs`:
- Around line 12-18: Update the JWT segment validation around the token split to
reject empty header, payload, or signature components before decoding. Preserve
the existing three-segment-only requirement and return None for any empty
segment so malformed tokens use the existing fallback path.
---
Nitpick comments:
In `@clients/openframe-client/src/services/openframe_client_info_service.rs`:
- Around line 68-81: Protect the read-modify-write sequences in
OpenFrameClientInfoService methods reconcile_version, update_version,
set_update_status, and set_binary_path with the same Arc<Mutex<()>> write-lock
pattern used by AgentConfigurationService. Initialize the lock with the service
and acquire it before each get/mutation/save sequence, ensuring concurrent
updates cannot overwrite one another.
In `@clients/openframe-client/src/services/token_refresh_run_manager.rs`:
- Around line 49-67: Update the retry loop surrounding
AgentAuthService::reauthenticate() to avoid fixed-interval retries forever: add
bounded exponential backoff and a maximum retry duration or attempt count, then
escalate through the existing re-registration or failure path when the limit is
reached. Preserve the immediate success exit and distinguish timeout from
authentication errors; first verify whether reauthenticate() already provides
equivalent backoff or circuit breaking and avoid duplicating it.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 061ba8ac-ce81-4348-af1d-77ab2c09893d
📒 Files selected for processing (53)
clients/openframe-client/Cargo.tomlclients/openframe-client/build.rsclients/openframe-client/config/agent.tomlclients/openframe-client/docs/PERMISSIONS.mdclients/openframe-client/infrastructure/meshcentral/mac.shclients/openframe-client/infrastructure/meshcentral/win.ps1clients/openframe-client/infrastructure/tactical-rmm/mac_arm64.shclients/openframe-client/infrastructure/tactical-rmm/win_amd64.ps1clients/openframe-client/src/config/update_config.rsclients/openframe-client/src/executor/windows/mod.rsclients/openframe-client/src/lib.rsclients/openframe-client/src/listener/client_update_gate.rsclients/openframe-client/src/listener/execution_listener.rsclients/openframe-client/src/listener/mod.rsclients/openframe-client/src/listener/openframe_client_update_listener.rsclients/openframe-client/src/listener/tool_agent_update_listener.rsclients/openframe-client/src/listener/tool_installation_message_listener.rsclients/openframe-client/src/listener/tool_restart_message_listener.rsclients/openframe-client/src/listener/tool_uninstall_message_listener.rsclients/openframe-client/src/models/execution.rsclients/openframe-client/src/models/mod.rsclients/openframe-client/src/models/tool_restart_message.rsclients/openframe-client/src/models/tool_version_overrides.rsclients/openframe-client/src/models/update_state.rsclients/openframe-client/src/platform/installation_detector.rsclients/openframe-client/src/platform/system_service.rsclients/openframe-client/src/platform/update_scripts/macos.rsclients/openframe-client/src/platform/update_scripts/mod.rsclients/openframe-client/src/platform/update_scripts/windows.rsclients/openframe-client/src/platform/updater_launcher/macos.rsclients/openframe-client/src/platform/updater_launcher/mod.rsclients/openframe-client/src/platform/updater_launcher/windows.rsclients/openframe-client/src/service.rsclients/openframe-client/src/service_adapter.rsclients/openframe-client/src/services/agent_configuration_service.rsclients/openframe-client/src/services/execution_service.rsclients/openframe-client/src/services/last_known_good_service.rsclients/openframe-client/src/services/mesh_self_heal_service.rsclients/openframe-client/src/services/mod.rsclients/openframe-client/src/services/nats_connection_manager.rsclients/openframe-client/src/services/openframe_client_info_service.rsclients/openframe-client/src/services/openframe_client_update_service.rsclients/openframe-client/src/services/shared_token_service.rsclients/openframe-client/src/services/token_refresh_run_manager.rsclients/openframe-client/src/services/tool_kill_service.rsclients/openframe-client/src/services/tool_restart_service.rsclients/openframe-client/src/services/tool_run_manager.rsclients/openframe-client/src/services/update_cleanup_service.rsclients/openframe-client/src/services/update_handler_service.rsclients/openframe-client/src/services/update_state_service.rsclients/openframe-client/src/utils.rsclients/openframe-client/src/utils/fs.rsclients/openframe-client/src/utils/jwt.rs
💤 Files with no reviewable changes (8)
- clients/openframe-client/infrastructure/meshcentral/mac.sh
- clients/openframe-client/infrastructure/tactical-rmm/mac_arm64.sh
- clients/openframe-client/Cargo.toml
- clients/openframe-client/src/models/tool_version_overrides.rs
- clients/openframe-client/config/agent.toml
- clients/openframe-client/infrastructure/meshcentral/win.ps1
- clients/openframe-client/infrastructure/tactical-rmm/win_amd64.ps1
- clients/openframe-client/build.rs
What & why
Second sync round of the shared Rust agent from
openframe-oss-tenant. The previous port (#1359) covered tenant history through019691eba(Jul 2). This PR ports every client commit merged to tenantmainsince, through922f664d7(Jul 22) — 17 commits, 1:1, original authorship and messages preserved.Ported commits (tenant → this branch)
60dd6e472454b59f97e72734f39478483dadf865c3ad325f2feb2037e6b2100279d5a232b9e49451f80438571b75a2428914b295f023ed49c0ee1e5e07fb22d8c4b6c006b674dcb32e755d9011f090c43bd82668956c17eda8407f63f6b3f2b2e2fa6c4f6f97b42882e18dce7026f76b147006c6acf4a2d1952059c161e1908d42e12dc55a832cd1b51c9447fcbd7210922f664d7de9455b90Deliberately not ported:
cf8d20296(#2143) +c81348c83(its revert) — verified to cancel exactly (empty combined diff); v2 (#2169) is included. The two "client files only" commits also touched tenant-wide files (docs, configs, pom.xml, .gitignore) that don't apply to this repo — only theirclients/openframe-client/changes are ported.Plus one follow-up commit: clippy fix in the new LKG service (
sort_by→sort_by_key(Reverse),clippy::unnecessary_sort_byunder this repo's-D warningsgate; same fix applies upstream).Deviations from verbatim tenant code
Same policy as #1359:
cargo fmtfolded per commit (pre-commit hook), extraction-era clippy idioms preserved (sorted module/import lists,derive(Default), no unused imports), and the one clippy fix above.Verification (4 independent methods, same harness as #1359)
Default-idiom diffs.TokenRefreshRunManager,LastKnownGoodService,client_update_gate,ToolRestartService, execution semaphore, ascii-script tests, …); removed code absent (tacticalrmm-agent-versionfeature, tactical-rmm infra scripts).Gates
cargo clippy --all-targets --features bin -- -D warnings✅ (and hook variant ✅)cargo fmt --all -- --check✅ every commitcargo test --features bin: 102 passed, 0 failed, 3 ignored (the test(client): ignore privileged/interactive tests that fail or hang in headless CI #1352 CI-safe ignores, intact after the port)Note on #1360
The open follow-up #1360 (update/uninstall per-tool-lock +
to_ascii_lowercase) targets files this PR also changes (tool_agent_update_listener,system_service); tenant still has neither fix. After this merges, #1360 needs a rebase onto the new listener shape — I'll handle it.🤖 Generated with Claude Code
https://claude.ai/code/session_011z7MGH2qYeKt2ZQV88EaD8
Summary by CodeRabbit