Remove list_sibling_containers, which nothing called
It listed every container on the daemon — including the user's unrelated postgres, mysql and other work — and handed the summaries to the webview. It had a registration, a command, a docker-layer helper, a typed frontend wrapper and a `SiblingContainer` type, and zero call sites. An audit named it as step one of an escalation chain: enumerate the daemon's containers, then point `update_project`'s unvalidated `container_id` at one and read its files through the file-command surface. The second half of that chain is closed now, but a command that exposes the user's unrelated containers and serves no feature is surface with no upside. Found by the registration test added in the previous commit, which is the answer to "why test something the compiler already checks": the compiler is perfectly happy with a command nobody calls. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBq2rGum6GX7xXgsas1fDc
This commit is contained in:
@@ -37,20 +37,3 @@ pub async fn get_container_info(
|
|||||||
docker::get_container_info(&project).await
|
docker::get_container_info(&project).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn list_sibling_containers() -> Result<Vec<serde_json::Value>, String> {
|
|
||||||
let containers = docker::list_sibling_containers().await?;
|
|
||||||
let result: Vec<serde_json::Value> = containers
|
|
||||||
.into_iter()
|
|
||||||
.map(|c| {
|
|
||||||
serde_json::json!({
|
|
||||||
"id": c.id,
|
|
||||||
"names": c.names,
|
|
||||||
"image": c.image,
|
|
||||||
"state": c.state,
|
|
||||||
"status": c.status,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3895,30 +3895,6 @@ pub async fn is_container_running(container_id: &str) -> Result<bool, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_sibling_containers() -> Result<Vec<ContainerSummary>, String> {
|
|
||||||
let docker = get_docker()?;
|
|
||||||
|
|
||||||
let all_containers: Vec<ContainerSummary> = docker
|
|
||||||
.list_containers(Some(ListContainersOptions::<String> {
|
|
||||||
all: true,
|
|
||||||
..Default::default()
|
|
||||||
}))
|
|
||||||
.await
|
|
||||||
.map_err(|e| format!("Failed to list containers: {}", e))?;
|
|
||||||
|
|
||||||
let siblings: Vec<ContainerSummary> = all_containers
|
|
||||||
.into_iter()
|
|
||||||
.filter(|c| {
|
|
||||||
if let Some(labels) = &c.labels {
|
|
||||||
!labels.contains_key(LABEL_MANAGED)
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(siblings)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|||||||
@@ -435,7 +435,6 @@ pub fn run() {
|
|||||||
commands::docker_commands::check_image_exists,
|
commands::docker_commands::check_image_exists,
|
||||||
commands::docker_commands::build_image,
|
commands::docker_commands::build_image,
|
||||||
commands::docker_commands::get_container_info,
|
commands::docker_commands::get_container_info,
|
||||||
commands::docker_commands::list_sibling_containers,
|
|
||||||
// Projects
|
// Projects
|
||||||
commands::project_commands::list_projects,
|
commands::project_commands::list_projects,
|
||||||
commands::project_commands::add_project,
|
commands::project_commands::add_project,
|
||||||
@@ -699,9 +698,11 @@ mod tests {
|
|||||||
///
|
///
|
||||||
/// The reverse direction matters too, and for a sharper reason: a command
|
/// The reverse direction matters too, and for a sharper reason: a command
|
||||||
/// that is registered but reachable from nowhere is still IPC surface a
|
/// that is registered but reachable from nowhere is still IPC surface a
|
||||||
/// compromised webview can call. `list_sibling_containers` — which returns
|
/// compromised webview can call. `list_sibling_containers` — which returned
|
||||||
/// every container on the daemon, including the user's unrelated work —
|
/// every container on the daemon, including the user's unrelated work —
|
||||||
/// sat in exactly that state.
|
/// sat in exactly that state, and this test is what found it. It has since
|
||||||
|
/// been removed at all four levels: registration, command, docker helper,
|
||||||
|
/// and the frontend wrapper and type.
|
||||||
///
|
///
|
||||||
/// So this asserts the two lists agree, and leaves *deciding* what belongs
|
/// So this asserts the two lists agree, and leaves *deciding* what belongs
|
||||||
/// on them to a human. It cannot see frontend call sites; `tsc` and the
|
/// on them to a human. It cannot see frontend call sites; `tsc` and the
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import type { Project, ProjectPath, ContainerInfo, SiblingContainer, AppSettings, UpdateInfo, ImageUpdateInfo, FileEntry, FileContents, WebTerminalInfo, SttStatus, GatewayStatus, InstallOptions, ClaudeSession, ContainerCapabilities, ScheduledTask, ScheduledTaskInput, SchedulerNotification, AuthBridgeStatus, BrowserViewStatus, BrowserViewPopoutState, BrowserPageState, PlaywrightDetection, BrowserSetupOutcome, BrowserInstallTarget, ContainerStaleness, MigrationOptions, MigrationReport, MigrationState, ClearTokenOutcome, CaCertInfo } from "./types";
|
import type { Project, ProjectPath, ContainerInfo, AppSettings, UpdateInfo, ImageUpdateInfo, FileEntry, FileContents, WebTerminalInfo, SttStatus, GatewayStatus, InstallOptions, ClaudeSession, ContainerCapabilities, ScheduledTask, ScheduledTaskInput, SchedulerNotification, AuthBridgeStatus, BrowserViewStatus, BrowserViewPopoutState, BrowserPageState, PlaywrightDetection, BrowserSetupOutcome, BrowserInstallTarget, ContainerStaleness, MigrationOptions, MigrationReport, MigrationState, ClearTokenOutcome, CaCertInfo } from "./types";
|
||||||
|
|
||||||
// Docker
|
// Docker
|
||||||
export const checkDocker = () => invoke<boolean>("check_docker");
|
export const checkDocker = () => invoke<boolean>("check_docker");
|
||||||
@@ -7,8 +7,6 @@ export const checkImageExists = () => invoke<boolean>("check_image_exists");
|
|||||||
export const buildImage = () => invoke<void>("build_image");
|
export const buildImage = () => invoke<void>("build_image");
|
||||||
export const getContainerInfo = (projectId: string) =>
|
export const getContainerInfo = (projectId: string) =>
|
||||||
invoke<ContainerInfo | null>("get_container_info", { projectId });
|
invoke<ContainerInfo | null>("get_container_info", { projectId });
|
||||||
export const listSiblingContainers = () =>
|
|
||||||
invoke<SiblingContainer[]>("list_sibling_containers");
|
|
||||||
|
|
||||||
// Projects
|
// Projects
|
||||||
export const listProjects = () => invoke<Project[]>("list_projects");
|
export const listProjects = () => invoke<Project[]>("list_projects");
|
||||||
|
|||||||
@@ -193,13 +193,6 @@ export interface ContainerInfo {
|
|||||||
image: string;
|
image: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SiblingContainer {
|
|
||||||
id: string;
|
|
||||||
names: string[] | null;
|
|
||||||
image: string;
|
|
||||||
state: string;
|
|
||||||
status: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TerminalSession {
|
export interface TerminalSession {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user