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
+19 -1
View File
@@ -264,11 +264,29 @@ export const debugUtils = {
const resp = await fetch('/api/health');
const contentType = resp.headers.get('content-type') || '';
const body = await safeText(resp);
const isJson = contentType.toLowerCase().includes('application/json');
let parsed: Record<string, unknown> | null = null;
if (isJson && body) {
try {
const candidate = JSON.parse(body) as unknown;
if (candidate && typeof candidate === 'object' && !Array.isArray(candidate)) {
parsed = candidate as Record<string, unknown>;
}
} catch {
parsed = null;
}
}
opencodeHealth = {
status: resp.status,
ok: resp.ok,
contentType,
type: contentType.includes('application/json') ? 'json' : 'html',
type: isJson ? 'json' : 'html',
openCodePort: parsed?.openCodePort ?? null,
openCodeRunning: parsed?.openCodeRunning ?? null,
openCodeSecureConnection: parsed?.openCodeSecureConnection ?? null,
openCodeAuthSource: parsed?.openCodeAuthSource ?? null,
isOpenCodeReady: parsed?.isOpenCodeReady ?? null,
lastOpenCodeError: parsed?.lastOpenCodeError ?? null,
preview: body ? body.slice(0, 120) : null,
};
} catch (error) {
+27
View File
@@ -13,6 +13,8 @@ type ProbeResult = {
type OpenChamberHealthSnapshot = {
openCodePort?: unknown;
openCodeRunning?: unknown;
openCodeSecureConnection?: unknown;
openCodeAuthSource?: unknown;
isOpenCodeReady?: unknown;
lastOpenCodeError?: unknown;
opencodeBinaryResolved?: unknown;
@@ -100,6 +102,19 @@ const formatIso = (timestamp: number | null | undefined): string => {
}
};
const normalizePort = (value: unknown): number | null => {
if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
return Math.trunc(value);
}
if (typeof value === 'string') {
const parsed = Number.parseInt(value, 10);
if (Number.isFinite(parsed) && parsed > 0) {
return parsed;
}
}
return null;
};
export const buildOpenCodeStatusReport = async (): Promise<string> => {
const now = new Date();
const appVersion = typeof __APP_VERSION__ !== 'undefined' ? __APP_VERSION__ : '(unknown)';
@@ -215,6 +230,18 @@ export const buildOpenCodeStatusReport = async (): Promise<string> => {
lines.push(`Directory: ${directory || '(none)'}`);
lines.push(`Platform: ${platform}`);
const runtimeOpenCodePort = normalizePort(openChamberHealth?.openCodePort);
lines.push(`OpenCode runtime port: ${runtimeOpenCodePort ?? '(unknown)'}`);
if (typeof openChamberHealth?.openCodeRunning === 'boolean') {
lines.push(`OpenCode runtime running: ${openChamberHealth.openCodeRunning ? 'yes' : 'no'}`);
}
if (typeof openChamberHealth?.openCodeSecureConnection === 'boolean') {
lines.push(`Secure OpenCode connection: ${openChamberHealth.openCodeSecureConnection ? 'true' : 'false'}`);
}
if (typeof openChamberHealth?.openCodeAuthSource === 'string' && openChamberHealth.openCodeAuthSource.trim()) {
lines.push(`OpenCode auth source: ${openChamberHealth.openCodeAuthSource}`);
}
if (typeof window !== 'undefined') {
const injected = (window as unknown as { __OPENCHAMBER_MACOS_MAJOR__?: unknown }).__OPENCHAMBER_MACOS_MAJOR__;
if (typeof injected === 'number' && Number.isFinite(injected) && injected > 0) {