fix(managed-runtime): secure auth and lifecycle control across runtimes (#437)

* feat: add OpenCode server authentication with auto-generated passwords

* fix(auth): separate user env and managed OpenCode password state

* fix(auth): enforce env precedence and managed password rotation across runtimes

* fix(vscode): rotate managed auth on startup and harden webview proxy

* build: add dev icons and config for Tauri desktop development

* fix(runtime): start managed OpenCode via CLI and expose active API port

* fix(managed-runtime): control OpenCode lifecycle and surface secure diagnostics

* docs: remove VS Code plugin test runbook
This commit is contained in:
Iuliia Ivashko
2026-02-17 18:01:57 +02:00
committed by GitHub
parent 58b27fa621
commit 138772e66e
22 changed files with 717 additions and 88 deletions
+25
View File
@@ -1476,10 +1476,27 @@ fn kill_sidecar(app: tauri::AppHandle) {
return;
};
let sidecar_url = state.url.lock().expect("sidecar url mutex").clone();
if let Some(url) = sidecar_url {
let shutdown_url = format!("{}/api/system/shutdown", url.trim_end_matches('/'));
if let Ok(client) = reqwest::blocking::Client::builder()
.no_proxy()
.timeout(Duration::from_millis(1500))
.build()
{
if let Ok(resp) = client.post(shutdown_url).send() {
if resp.status().is_success() {
std::thread::sleep(Duration::from_millis(100));
}
}
}
}
let mut guard = state.child.lock().expect("sidecar mutex");
if let Some(child) = guard.take() {
let _ = child.kill();
}
*state.url.lock().expect("sidecar url mutex") = None;
}
fn build_local_url(port: u16) -> String {
@@ -1627,6 +1644,7 @@ async fn spawn_local_server(app: &tauri::AppHandle) -> Result<String> {
.args(["--port", &port.to_string()])
.env("OPENCHAMBER_HOST", "127.0.0.1")
.env("OPENCHAMBER_DIST_DIR", dist_dir.clone())
.env("OPENCHAMBER_RUNTIME", "desktop")
.env("OPENCHAMBER_DESKTOP_NOTIFY", "true")
.env("PATH", augmented_path.clone())
.env("NO_PROXY", no_proxy)
@@ -1643,6 +1661,13 @@ async fn spawn_local_server(app: &tauri::AppHandle) -> Result<String> {
}
}
if let Ok(password) = env::var("OPENCODE_SERVER_PASSWORD") {
let trimmed = password.trim();
if !trimmed.is_empty() {
cmd = cmd.env("OPENCODE_SERVER_PASSWORD", trimmed);
}
}
let (rx, child) = match cmd.spawn() {
Ok(v) => v,
Err(err) => {