Merge pull request #11074 from Sumynwa/sumsharma/genpolicy_test

genpolicy: Refactor tests to allow different request types in a testcases json.
This commit is contained in:
Saul Paredes 2025-03-25 12:38:19 -07:00 committed by GitHub
commit ae5c587efc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 72 additions and 19 deletions

View File

@ -6,7 +6,7 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use base64::prelude::*; use base64::prelude::*;
use std::any; use std::fmt::{self, Display};
use std::fs::{self, File}; use std::fs::{self, File};
use std::path; use std::path;
use std::str; use std::str;
@ -15,16 +15,39 @@ mod tests {
CopyFileRequest, CreateContainerRequest, CreateSandboxRequest, UpdateInterfaceRequest, CopyFileRequest, CreateContainerRequest, CreateSandboxRequest, UpdateInterfaceRequest,
UpdateRoutesRequest, UpdateRoutesRequest,
}; };
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use kata_agent_policy::policy::AgentPolicy; use kata_agent_policy::policy::AgentPolicy;
// Translate each test case in testcases.json
// to one request type.
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
struct TestCase<T> { #[serde(tag = "type")]
enum TestRequest {
CopyFile(CopyFileRequest),
CreateContainer(CreateContainerRequest),
CreateSandbox(CreateSandboxRequest),
UpdateInterface(UpdateInterfaceRequest),
UpdateRoutes(UpdateRoutesRequest),
}
impl Display for TestRequest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TestRequest::CopyFile(_) => write!(f, "CopyFileRequest"),
TestRequest::CreateContainer(_) => write!(f, "CreateContainerRequest"),
TestRequest::CreateSandbox(_) => write!(f, "CreateSandboxRequest"),
TestRequest::UpdateInterface(_) => write!(f, "UpdateInterfaceRequest"),
TestRequest::UpdateRoutes(_) => write!(f, "UpdateRoutesRequest"),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
struct TestCase {
description: String, description: String,
allowed: bool, allowed: bool,
request: T, request: TestRequest,
} }
/// Run tests from the given directory. /// Run tests from the given directory.
@ -32,11 +55,9 @@ mod tests {
/// it must contain a `resources.yaml` file as well as a `testcases.json` file. /// it must contain a `resources.yaml` file as well as a `testcases.json` file.
/// The resources must produce a policy when fed into genpolicy, so there /// The resources must produce a policy when fed into genpolicy, so there
/// should be exactly one entry with a PodSpec. The test case file must contain /// should be exactly one entry with a PodSpec. The test case file must contain
/// a JSON list of [TestCase] instances appropriate for `T`. /// a JSON list of [TestCase] instances. Each instance will be of type enum TestRequest,
async fn runtests<T>(test_case_dir: &str) /// with the tag `type` listing the exact type of request.
where async fn runtests(test_case_dir: &str) {
T: DeserializeOwned + Serialize,
{
// Prepare temp dir for running genpolicy. // Prepare temp dir for running genpolicy.
let workdir = path::PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join(test_case_dir); let workdir = path::PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join(test_case_dir);
fs::create_dir_all(&workdir) fs::create_dir_all(&workdir)
@ -102,7 +123,7 @@ mod tests {
let case_file = let case_file =
File::open(testdata_dir.join("testcases.json")).expect("test case file should open"); File::open(testdata_dir.join("testcases.json")).expect("test case file should open");
let test_cases: Vec<TestCase<T>> = let test_cases: Vec<TestCase> =
serde_json::from_reader(case_file).expect("test case file should parse"); serde_json::from_reader(case_file).expect("test case file should parse");
for test_case in test_cases { for test_case in test_cases {
@ -112,7 +133,7 @@ mod tests {
let results = pol let results = pol
.allow_request( .allow_request(
any::type_name::<T>().split("::").last().unwrap(), &test_case.request.to_string(),
&serde_json::to_string(&v).unwrap(), &serde_json::to_string(&v).unwrap(),
) )
.await; .await;
@ -130,36 +151,36 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn test_copyfile() { async fn test_copyfile() {
runtests::<CopyFileRequest>("copyfile").await; runtests("copyfile").await;
} }
#[tokio::test] #[tokio::test]
async fn test_create_sandbox() { async fn test_create_sandbox() {
runtests::<CreateSandboxRequest>("createsandbox").await; runtests("createsandbox").await;
} }
#[tokio::test] #[tokio::test]
async fn test_update_routes() { async fn test_update_routes() {
runtests::<UpdateRoutesRequest>("updateroutes").await; runtests("updateroutes").await;
} }
#[tokio::test] #[tokio::test]
async fn test_update_interface() { async fn test_update_interface() {
runtests::<UpdateInterfaceRequest>("updateinterface").await; runtests("updateinterface").await;
} }
#[tokio::test] #[tokio::test]
async fn test_create_container_network_namespace() { async fn test_create_container_network_namespace() {
runtests::<CreateContainerRequest>("createcontainer/network_namespace").await; runtests("createcontainer/network_namespace").await;
} }
#[tokio::test] #[tokio::test]
async fn test_create_container_sysctls() { async fn test_create_container_sysctls() {
runtests::<CreateContainerRequest>("createcontainer/sysctls").await; runtests("createcontainer/sysctls").await;
} }
#[tokio::test] #[tokio::test]
async fn test_create_container_generate_name() { async fn test_create_container_generate_name() {
runtests::<CreateContainerRequest>("createcontainer/generate_name").await; runtests("createcontainer/generate_name").await;
} }
} }

View File

@ -3,6 +3,7 @@
"description": "copy initiated by k8s mount", "description": "copy initiated by k8s mount",
"allowed": true, "allowed": true,
"request": { "request": {
"type": "CopyFile",
"path": "/run/kata-containers/shared/containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc-ce23cfeb91e75aaa-resolv.conf" "path": "/run/kata-containers/shared/containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc-ce23cfeb91e75aaa-resolv.conf"
} }
}, },
@ -10,6 +11,7 @@
"description": "a dirname can have trailing dots", "description": "a dirname can have trailing dots",
"allowed": true, "allowed": true,
"request": { "request": {
"type": "CopyFile",
"path": "/run/kata-containers/shared/containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc-ce23cfeb91e75aaa-foo../bar" "path": "/run/kata-containers/shared/containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc-ce23cfeb91e75aaa-foo../bar"
} }
}, },
@ -17,6 +19,7 @@
"description": "attempt to copy outside of container root", "description": "attempt to copy outside of container root",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "CopyFile",
"path": "/etc/ssl/cert.pem" "path": "/etc/ssl/cert.pem"
} }
}, },
@ -24,6 +27,7 @@
"description": "attempt to write into container root", "description": "attempt to write into container root",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "CopyFile",
"path": "/run/kata-containers/shared/containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc/rootfs/bin/sh" "path": "/run/kata-containers/shared/containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc/rootfs/bin/sh"
} }
}, },
@ -31,6 +35,7 @@
"description": "attempt to write into container root - guest pull", "description": "attempt to write into container root - guest pull",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "CopyFile",
"path": "/run/kata-containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc/rootfs/bin/sh" "path": "/run/kata-containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc/rootfs/bin/sh"
} }
}, },
@ -38,6 +43,7 @@
"description": "attempted directory traversal", "description": "attempted directory traversal",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "CopyFile",
"path": "/run/kata-containers/shared/containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc-ce23cfeb91e75aaa-foo/../../../../../etc/ssl/cert.pem" "path": "/run/kata-containers/shared/containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc-ce23cfeb91e75aaa-foo/../../../../../etc/ssl/cert.pem"
} }
}, },
@ -45,6 +51,7 @@
"description": "attempted directory traversal - parent directory", "description": "attempted directory traversal - parent directory",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "CopyFile",
"path": "/run/kata-containers/shared/containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc-ce23cfeb91e75aaa-foo/.." "path": "/run/kata-containers/shared/containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc-ce23cfeb91e75aaa-foo/.."
} }
}, },
@ -52,6 +59,7 @@
"description": "relative path", "description": "relative path",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "CopyFile",
"path": "etc/ssl/cert.pem" "path": "etc/ssl/cert.pem"
} }
}, },
@ -59,6 +67,7 @@
"description": "relative path - parent directory", "description": "relative path - parent directory",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "CopyFile",
"path": ".." "path": ".."
} }
} }

View File

@ -3,6 +3,7 @@
"description": "generated name with valid prefix (dummyxyz)", "description": "generated name with valid prefix (dummyxyz)",
"allowed": true, "allowed": true,
"request": { "request": {
"type": "CreateContainer",
"OCI": { "OCI": {
"Version": "1.1.0", "Version": "1.1.0",
"Annotations": { "Annotations": {
@ -134,6 +135,7 @@
"description": "generated name with invalid prefix (xyzdummy)", "description": "generated name with invalid prefix (xyzdummy)",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "CreateContainer",
"OCI": { "OCI": {
"Version": "1.1.0", "Version": "1.1.0",
"Annotations": { "Annotations": {

View File

@ -3,6 +3,7 @@
"description": "one network namespace", "description": "one network namespace",
"allowed": true, "allowed": true,
"request": { "request": {
"type": "CreateContainer",
"OCI": { "OCI": {
"Version": "1.1.0", "Version": "1.1.0",
"Annotations": { "Annotations": {
@ -134,6 +135,7 @@
"description": "same network namespace", "description": "same network namespace",
"allowed": true, "allowed": true,
"request": { "request": {
"type": "CreateContainer",
"OCI": { "OCI": {
"Version": "1.1.0", "Version": "1.1.0",
"Annotations": { "Annotations": {
@ -265,6 +267,7 @@
"description": "no network namespace", "description": "no network namespace",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "CreateContainer",
"OCI": { "OCI": {
"Version": "1.1.0", "Version": "1.1.0",
"Annotations": { "Annotations": {
@ -392,6 +395,7 @@
"description": "different network namespace", "description": "different network namespace",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "CreateContainer",
"OCI": { "OCI": {
"Version": "1.1.0", "Version": "1.1.0",
"Annotations": { "Annotations": {

View File

@ -4,6 +4,7 @@
"allowed": true, "allowed": true,
"state": {"sandbox_name": "policy-redis-deployment-6674f9448-xjrzf"}, "state": {"sandbox_name": "policy-redis-deployment-6674f9448-xjrzf"},
"request": { "request": {
"type": "CreateContainer",
"OCI": { "OCI": {
"Annotations": { "Annotations": {
"io.katacontainers.pkg.oci.bundle_path": "/run/containerd/io.containerd.runtime.v2.task/k8s.io/4bae4a8e74302a8edfe17424aff0b632cae893687f4d9ad2f2115666899f9a12", "io.katacontainers.pkg.oci.bundle_path": "/run/containerd/io.containerd.runtime.v2.task/k8s.io/4bae4a8e74302a8edfe17424aff0b632cae893687f4d9ad2f2115666899f9a12",
@ -279,6 +280,7 @@
"allowed": false, "allowed": false,
"state": {"sandbox_name": "policy-redis-deployment-6674f9448-xjrzf"}, "state": {"sandbox_name": "policy-redis-deployment-6674f9448-xjrzf"},
"request": { "request": {
"type": "CreateContainer",
"OCI": { "OCI": {
"Annotations": { "Annotations": {
"io.katacontainers.pkg.oci.bundle_path": "/run/containerd/io.containerd.runtime.v2.task/k8s.io/4bae4a8e74302a8edfe17424aff0b632cae893687f4d9ad2f2115666899f9a12", "io.katacontainers.pkg.oci.bundle_path": "/run/containerd/io.containerd.runtime.v2.task/k8s.io/4bae4a8e74302a8edfe17424aff0b632cae893687f4d9ad2f2115666899f9a12",

View File

@ -3,6 +3,7 @@
"description": "no pidns", "description": "no pidns",
"allowed": true, "allowed": true,
"request": { "request": {
"type": "CreateSandbox",
"sandbox_pidns": false "sandbox_pidns": false
} }
}, },
@ -10,6 +11,7 @@
"description": "pidns", "description": "pidns",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "CreateSandbox",
"sandbox_pidns": true "sandbox_pidns": true
} }
}, },
@ -17,6 +19,7 @@
"description": "kernel modules", "description": "kernel modules",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "CreateSandbox",
"sandbox_pidns": false, "sandbox_pidns": false,
"kernel_modules": [{"name": "evil.ko"}] "kernel_modules": [{"name": "evil.ko"}]
} }
@ -25,6 +28,7 @@
"description": "guest hooks", "description": "guest hooks",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "CreateSandbox",
"sandbox_pidns": false, "sandbox_pidns": false,
"guest_hook_path": "/attacker/controlled/path" "guest_hook_path": "/attacker/controlled/path"
} }

View File

@ -3,6 +3,7 @@
"description": "no flags", "description": "no flags",
"allowed": true, "allowed": true,
"request": { "request": {
"type": "UpdateInterface",
"interface": { "interface": {
"device": "eth0", "device": "eth0",
"name": "eth0", "name": "eth0",
@ -22,6 +23,7 @@
"description": "allowed arp flag", "description": "allowed arp flag",
"allowed": true, "allowed": true,
"request": { "request": {
"type": "UpdateInterface",
"interface": { "interface": {
"device": "eth0", "device": "eth0",
"name": "eth0", "name": "eth0",
@ -41,6 +43,7 @@
"description": "forbidden flag", "description": "forbidden flag",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "UpdateInterface",
"interface": { "interface": {
"device": "eth0", "device": "eth0",
"name": "eth0", "name": "eth0",
@ -60,6 +63,7 @@
"description": "forbidden name", "description": "forbidden name",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "UpdateInterface",
"interface": { "interface": {
"device": "eth0", "device": "eth0",
"name": "lo", "name": "lo",
@ -79,6 +83,7 @@
"description": "forbidden hwAddr", "description": "forbidden hwAddr",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "UpdateInterface",
"interface": { "interface": {
"device": "eth0", "device": "eth0",
"name": "eth0", "name": "eth0",

View File

@ -3,6 +3,7 @@
"description": "compliant routes", "description": "compliant routes",
"allowed": true, "allowed": true,
"request": { "request": {
"type": "UpdateRoutes",
"routes": { "routes": {
"Routes": [ "Routes": [
{ {
@ -21,6 +22,7 @@
"description": "forbidden device", "description": "forbidden device",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "UpdateRoutes",
"routes": { "routes": {
"Routes": [ "Routes": [
{ {
@ -39,6 +41,7 @@
"description": "one compliant route, one noncompliant", "description": "one compliant route, one noncompliant",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "UpdateRoutes",
"routes": { "routes": {
"Routes": [ "Routes": [
{ {
@ -65,6 +68,7 @@
"description": "noncompliant routes", "description": "noncompliant routes",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "UpdateRoutes",
"routes": { "routes": {
"Routes": [ "Routes": [
{ {
@ -83,6 +87,7 @@
"description": "noncompliant routes ipv6 1", "description": "noncompliant routes ipv6 1",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "UpdateRoutes",
"routes": { "routes": {
"Routes": [ "Routes": [
{ {
@ -101,6 +106,7 @@
"description": "noncompliant routes ipv6 2", "description": "noncompliant routes ipv6 2",
"allowed": false, "allowed": false,
"request": { "request": {
"type": "UpdateRoutes",
"routes": { "routes": {
"Routes": [ "Routes": [
{ {