Skip to content

Commit 19f2369

Browse files
committed
test(podman): cover proxy-auth secret cleanup across lifecycle failures
The per-sandbox proxy-auth credential secret is staged before the container is created and removed on cleanup, but no test proved the cleanup paths actually issue the secret removal. Add Podman-stub tests that drive create_sandbox to a container-create failure and to a start failure, and delete_sandbox for an out-of-band deletion, asserting each path issues the DELETE for the per-sandbox proxy-auth secret so a credential can never outlive the sandbox that owned it. Signed-off-by: Philippe Martin <[email protected]>
1 parent 3192ee8 commit 19f2369

1 file changed

Lines changed: 152 additions & 1 deletion

File tree

‎crates/openshell-driver-podman/src/driver.rs‎

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,7 @@ mod tests {
906906
};
907907
use std::collections::HashMap;
908908
use std::fs;
909-
use std::path::PathBuf;
909+
use std::path::{Path, PathBuf};
910910

911911
fn cdi_devices_config(device_ids: &[&str]) -> prost_types::Struct {
912912
prost_types::Struct {
@@ -1554,6 +1554,157 @@ mod tests {
15541554
let _ = fs::remove_file(socket_path);
15551555
}
15561556

1557+
/// Write a valid `user:pass` credential to a unique path for proxy-auth
1558+
/// secret tests. Caller removes it.
1559+
fn write_proxy_auth_file(test_name: &str) -> PathBuf {
1560+
let path = crate::test_utils::unique_socket_path(test_name).with_extension("auth");
1561+
fs::write(&path, "user:pass\n").expect("write proxy auth file");
1562+
path
1563+
}
1564+
1565+
fn proxy_auth_config(socket_path: PathBuf, auth_file: &Path) -> PodmanComputeConfig {
1566+
PodmanComputeConfig {
1567+
socket_path,
1568+
stop_timeout_secs: 10,
1569+
proxy_auth_file: Some(auth_file.to_string_lossy().into_owned()),
1570+
proxy_auth_allow_insecure: Some(true),
1571+
..PodmanComputeConfig::default()
1572+
}
1573+
}
1574+
1575+
fn plain_sandbox(id: &str, name: &str) -> DriverSandbox {
1576+
DriverSandbox {
1577+
id: id.to_string(),
1578+
name: name.to_string(),
1579+
namespace: String::new(),
1580+
spec: None,
1581+
status: None,
1582+
}
1583+
}
1584+
1585+
fn secret_delete_request(sandbox_id: &str) -> String {
1586+
format!(
1587+
"DELETE {}",
1588+
api_path(&format!(
1589+
"/libpod/secrets/{}",
1590+
container::proxy_auth_secret_name(sandbox_id)
1591+
))
1592+
)
1593+
}
1594+
1595+
#[tokio::test]
1596+
async fn create_sandbox_removes_proxy_auth_secret_on_container_create_failure() {
1597+
// A credential secret is staged before the container is created, so a
1598+
// container-create failure must remove it — no credential residue.
1599+
let sandbox_id = "sandbox-cc";
1600+
let auth_file = write_proxy_auth_file("create-fail");
1601+
let (socket_path, request_log, handle) = spawn_podman_stub(
1602+
"create-container-fail",
1603+
vec![
1604+
StubResponse::new(StatusCode::OK, "{}"), // pull supervisor image
1605+
StubResponse::new(StatusCode::OK, "{}"), // pull sandbox image
1606+
StubResponse::new(StatusCode::CREATED, "{}"), // create volume
1607+
StubResponse::new(StatusCode::CREATED, "{}"), // create proxy-auth secret
1608+
StubResponse::new(StatusCode::INTERNAL_SERVER_ERROR, r#"{"message":"boom"}"#), // create container
1609+
StubResponse::new(StatusCode::NO_CONTENT, ""), // cleanup: remove volume
1610+
StubResponse::new(StatusCode::NO_CONTENT, ""), // cleanup: remove proxy-auth secret
1611+
],
1612+
);
1613+
let driver = test_driver_with_config(proxy_auth_config(socket_path.clone(), &auth_file));
1614+
1615+
driver
1616+
.create_sandbox(&plain_sandbox(sandbox_id, "demo"))
1617+
.await
1618+
.expect_err("container create should fail");
1619+
1620+
handle.await.expect("stub task should finish");
1621+
let requests = request_log
1622+
.lock()
1623+
.expect("request log lock should not be poisoned")
1624+
.clone();
1625+
assert!(
1626+
requests.contains(&secret_delete_request(sandbox_id)),
1627+
"proxy-auth secret must be removed on container-create failure: {requests:?}"
1628+
);
1629+
let _ = fs::remove_file(&auth_file);
1630+
let _ = fs::remove_file(socket_path);
1631+
}
1632+
1633+
#[tokio::test]
1634+
async fn create_sandbox_removes_proxy_auth_secret_on_start_failure() {
1635+
// The container is created but fails to start; the staged credential
1636+
// secret must still be removed.
1637+
let sandbox_id = "sandbox-sf";
1638+
let auth_file = write_proxy_auth_file("start-fail");
1639+
let (socket_path, request_log, handle) = spawn_podman_stub(
1640+
"create-start-fail",
1641+
vec![
1642+
StubResponse::new(StatusCode::OK, "{}"), // pull supervisor image
1643+
StubResponse::new(StatusCode::OK, "{}"), // pull sandbox image
1644+
StubResponse::new(StatusCode::CREATED, "{}"), // create volume
1645+
StubResponse::new(StatusCode::CREATED, "{}"), // create proxy-auth secret
1646+
StubResponse::new(StatusCode::CREATED, "{}"), // create container
1647+
StubResponse::new(StatusCode::INTERNAL_SERVER_ERROR, r#"{"message":"boom"}"#), // start container
1648+
StubResponse::new(StatusCode::NO_CONTENT, ""), // cleanup: remove container
1649+
StubResponse::new(StatusCode::NO_CONTENT, ""), // cleanup: remove volume
1650+
StubResponse::new(StatusCode::NO_CONTENT, ""), // cleanup: remove proxy-auth secret
1651+
],
1652+
);
1653+
let driver = test_driver_with_config(proxy_auth_config(socket_path.clone(), &auth_file));
1654+
1655+
driver
1656+
.create_sandbox(&plain_sandbox(sandbox_id, "demo"))
1657+
.await
1658+
.expect_err("container start should fail");
1659+
1660+
handle.await.expect("stub task should finish");
1661+
let requests = request_log
1662+
.lock()
1663+
.expect("request log lock should not be poisoned")
1664+
.clone();
1665+
assert!(
1666+
requests.contains(&secret_delete_request(sandbox_id)),
1667+
"proxy-auth secret must be removed on start failure: {requests:?}"
1668+
);
1669+
let _ = fs::remove_file(&auth_file);
1670+
let _ = fs::remove_file(socket_path);
1671+
}
1672+
1673+
#[tokio::test]
1674+
async fn delete_sandbox_removes_proxy_auth_secret() {
1675+
// Deleting a sandbox (here already gone out of band) must remove the
1676+
// per-sandbox proxy-auth secret so credentials never outlive it.
1677+
let sandbox_id = "sandbox-del";
1678+
let (socket_path, request_log, handle) = spawn_podman_stub(
1679+
"delete-proxy-auth",
1680+
vec![
1681+
StubResponse::new(StatusCode::NOT_FOUND, r#"{"message":"gone"}"#), // inspect
1682+
StubResponse::new(StatusCode::NOT_FOUND, r#"{"message":"gone"}"#), // stop
1683+
StubResponse::new(StatusCode::NOT_FOUND, r#"{"message":"gone"}"#), // remove container
1684+
StubResponse::new(StatusCode::NO_CONTENT, ""), // remove volume
1685+
StubResponse::new(StatusCode::NO_CONTENT, ""), // remove token secret
1686+
StubResponse::new(StatusCode::NO_CONTENT, ""), // remove proxy-auth secret
1687+
],
1688+
);
1689+
let driver = test_driver(socket_path.clone());
1690+
1691+
driver
1692+
.delete_sandbox(sandbox_id, "demo")
1693+
.await
1694+
.expect("delete should succeed");
1695+
1696+
handle.await.expect("stub task should finish");
1697+
let requests = request_log
1698+
.lock()
1699+
.expect("request log lock should not be poisoned")
1700+
.clone();
1701+
assert!(
1702+
requests.contains(&secret_delete_request(sandbox_id)),
1703+
"proxy-auth secret must be removed on delete: {requests:?}"
1704+
);
1705+
let _ = fs::remove_file(socket_path);
1706+
}
1707+
15571708
#[tokio::test]
15581709
async fn delete_sandbox_uses_request_id_when_container_label_disagrees() {
15591710
let sandbox_id = "sandbox-request-id";

0 commit comments

Comments
 (0)