fix(agent): SPEC-018 review fixes — agent_id persistence, managed fallback, HKEY typing
Some checks failed
Build and Test / Build Server (Linux) (pull_request) Failing after 7m12s
Build and Test / Build Agent (Windows) (pull_request) Successful in 14m56s
Build and Test / Security Audit (pull_request) Successful in 7m57s
Build and Test / Build Summary (pull_request) Has been skipped

Address the SPEC-018 Phase 1 code review (reports/2026-06-03-spec018-review.md):

- Bug 2 (config.rs): stop agent_id churn on every restart. The embedded-config
  path always wins in Config::load, so the saved agent_id was never read back.
  Add Config::persisted_agent_id() and reuse a prior id from the TOML; only mint
  a new UUID when none exists.
- Bug 1 (main.rs): remove the non-functional in-process fallback in
  run_permanent_agent_managed. A managed agent's cak_ store is SYSTEM-only ACL'd,
  so a non-elevated in-process run cannot authenticate (load_cak permission-denied,
  or enroll C1 read-back failure). Return an actionable "install elevated" error
  instead of pretending to provide an agent; update the misleading comments.
- Issue 6 (startup.rs): replace the fragile transmute::<HANDLE, HKEY> with the
  windows crate's typed HKEY out-param; add SAFETY comments.

cargo check -p guruconnect --target x86_64-pc-windows-msvc passes clean.
Deferred lower-severity items tracked in #8.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 16:27:27 -07:00
parent 11af9dff8e
commit 9eaabdd6a5
5 changed files with 212 additions and 30 deletions

View File

@@ -9,7 +9,7 @@ use tracing::{info, warn};
use windows::core::PCWSTR;
#[cfg(windows)]
use windows::Win32::System::Registry::{
RegCloseKey, RegDeleteValueW, RegOpenKeyExW, RegSetValueExW, HKEY_CURRENT_USER, KEY_WRITE,
RegCloseKey, RegDeleteValueW, RegOpenKeyExW, RegSetValueExW, HKEY, HKEY_CURRENT_USER, KEY_WRITE,
REG_SZ,
};
@@ -42,40 +42,39 @@ pub fn add_to_startup() -> Result<()> {
.chain(std::iter::once(0))
.collect();
// SAFETY: FFI into the Win32 registry API. `key_path`/`value_name`/`value_data`
// are NUL-terminated wide strings that outlive the calls. `RegOpenKeyExW`
// writes the opened key into `hkey`; we only use it after confirming success,
// and always pair it with `RegCloseKey`.
unsafe {
let mut hkey = windows::Win32::Foundation::HANDLE::default();
let mut hkey = HKEY::default();
// Open the Run key
// Open the Run key. RegOpenKeyExW takes a `*mut HKEY` out-param.
let result = RegOpenKeyExW(
HKEY_CURRENT_USER,
PCWSTR(key_path.as_ptr()),
0,
KEY_WRITE,
&mut hkey as *mut _ as *mut _,
&mut hkey,
);
if result.is_err() {
anyhow::bail!("Failed to open registry key: {:?}", result);
}
let hkey_raw = std::mem::transmute::<
windows::Win32::Foundation::HANDLE,
windows::Win32::System::Registry::HKEY,
>(hkey);
// Set the value
let data_bytes =
std::slice::from_raw_parts(value_data.as_ptr() as *const u8, value_data.len() * 2);
let set_result = RegSetValueExW(
hkey_raw,
hkey,
PCWSTR(value_name.as_ptr()),
0,
REG_SZ,
Some(data_bytes),
);
let _ = RegCloseKey(hkey_raw);
let _ = RegCloseKey(hkey);
if set_result.is_err() {
anyhow::bail!("Failed to set registry value: {:?}", set_result);
@@ -103,15 +102,19 @@ pub fn remove_from_startup() -> Result<()> {
.chain(std::iter::once(0))
.collect();
// SAFETY: FFI into the Win32 registry API. `key_path`/`value_name` are
// NUL-terminated wide strings that outlive the calls. `RegOpenKeyExW` writes
// the opened key into `hkey`; we only use it after confirming success, and
// always pair it with `RegCloseKey`.
unsafe {
let mut hkey = windows::Win32::Foundation::HANDLE::default();
let mut hkey = HKEY::default();
let result = RegOpenKeyExW(
HKEY_CURRENT_USER,
PCWSTR(key_path.as_ptr()),
0,
KEY_WRITE,
&mut hkey as *mut _ as *mut _,
&mut hkey,
);
if result.is_err() {
@@ -119,14 +122,9 @@ pub fn remove_from_startup() -> Result<()> {
return Ok(()); // Not an error if key doesn't exist
}
let hkey_raw = std::mem::transmute::<
windows::Win32::Foundation::HANDLE,
windows::Win32::System::Registry::HKEY,
>(hkey);
let delete_result = RegDeleteValueW(hkey, PCWSTR(value_name.as_ptr()));
let delete_result = RegDeleteValueW(hkey_raw, PCWSTR(value_name.as_ptr()));
let _ = RegCloseKey(hkey_raw);
let _ = RegCloseKey(hkey);
if delete_result.is_err() {
warn!("Registry value may not exist: {:?}", delete_result);