Merge pull request #10068 from burgerdev/genpolicy-test

genpolicy: add crate-scoped integration test
This commit is contained in:
Dan Mihai 2024-08-06 16:10:46 -07:00 committed by GitHub
commit 2da77c6979
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 293 additions and 18 deletions

View File

@ -876,12 +876,14 @@ dependencies = [
"fs2",
"generic-array",
"k8s-cri",
"libz-ng-sys",
"log",
"oci-distribution",
"oci-spec",
"openssl",
"protobuf 3.3.0",
"protocols",
"regorus",
"serde",
"serde-transcode",
"serde_ignored",
@ -1229,6 +1231,15 @@ dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.6"
@ -1337,9 +1348,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libz-ng-sys"
version = "1.1.9"
version = "1.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2468756f34903b582fe7154dc1ffdebd89d0562c4a43b53c621bb0f1b1043ccb"
checksum = "c6409efc61b12687963e602df8ecf70e8ddacf95bc6576bcf16e3ac6328083c5"
dependencies = [
"cmake",
"libc",
@ -1508,10 +1519,74 @@ dependencies = [
]
[[package]]
name = "num-traits"
version = "0.2.17"
name = "num"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
@ -1626,6 +1701,15 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-src"
version = "111.28.2+1.1.1w"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb1830e20a48a975ca898ca8c1d036a36c3c6c5cb7dabc1c216706587857920f"
dependencies = [
"cc",
]
[[package]]
name = "openssl-sys"
version = "0.9.90"
@ -1634,6 +1718,7 @@ checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6"
dependencies = [
"cc",
"libc",
"openssl-src",
"pkg-config",
"vcpkg",
]
@ -1794,7 +1879,7 @@ checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603"
dependencies = [
"bytes",
"heck 0.3.3",
"itertools",
"itertools 0.10.5",
"log",
"multimap",
"petgraph 0.5.1",
@ -1812,7 +1897,7 @@ checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270"
dependencies = [
"bytes",
"heck 0.4.1",
"itertools",
"itertools 0.10.5",
"lazy_static",
"log",
"multimap",
@ -1833,7 +1918,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba"
dependencies = [
"anyhow",
"itertools",
"itertools 0.10.5",
"proc-macro2",
"quote",
"syn 1.0.109",
@ -1846,7 +1931,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4"
dependencies = [
"anyhow",
"itertools",
"itertools 0.10.5",
"proc-macro2",
"quote",
"syn 1.0.109",
@ -2082,6 +2167,23 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "regorus"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77dd872918e5c172bd42ac49716f89a15e35be513bba3d902e355a531529a87f"
dependencies = [
"anyhow",
"itertools 0.12.1",
"lazy_static",
"num",
"rand",
"regex",
"scientific",
"serde",
"serde_json",
]
[[package]]
name = "rend"
version = "0.4.2"
@ -2259,6 +2361,26 @@ dependencies = [
"windows-sys 0.42.0",
]
[[package]]
name = "scientific"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38a4b339a8de779ecb098a772ecbba2ace74e23ed959a5b4f30631d8bf1799a8"
dependencies = [
"scientific-macro",
]
[[package]]
name = "scientific-macro"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2ee4885492bb655bfa05d039cd9163eb8fe9f79ddebf00ca23a1637510c2fd2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.58",
]
[[package]]
name = "seahash"
version = "4.1.0"

View File

@ -40,8 +40,9 @@ anyhow = "1.0.32"
async-trait = "0.1.68"
docker_credential = "1.3.1"
flate2 = { version = "1.0.26", features = ["zlib-ng"], default-features = false }
libz-ng-sys = "1.1.15" # force newer version that compiles on ppc64le
oci-distribution = { version = "0.10.0" }
openssl = { version = "0.10.54" }
openssl = { version = "0.10.54", features = ["vendored"] }
serde_ignored = "0.1.7"
serde_json = "1.0.39"
serde-transcode = "1.1.1"
@ -67,3 +68,6 @@ k8s-cri = "0.7.0"
tonic = "0.9.2"
tower = "0.4.13"
containerd-client = "0.4.0"
[dev-dependencies]
regorus = { version = "0.1.4", default-features = false, features = ["arc", "regex"]}

View File

@ -40,7 +40,8 @@ clean:
vendor:
cargo vendor
test:
test: $(GENERATED_FILES)
@RUSTFLAGS="$(EXTRA_RUSTFLAGS) --deny warnings" cargo test --all-targets --all-features --target $(TRIPLE)
install: $(GENERATED_FILES)
@RUSTFLAGS="$(EXTRA_RUSTFLAGS) --deny warnings" cargo install --locked --target $(TRIPLE) --path .

View File

@ -57,8 +57,8 @@ pub fn get_policy_mounts(
.find(|m| m.destination.eq(&s_mount.destination))
{
// Update an already existing mount.
policy_mount.type_ = mount.type_.clone();
policy_mount.source = mount.source.clone();
policy_mount.type_.clone_from(&mount.type_);
policy_mount.source.clone_from(&mount.source);
policy_mount.options = mount.options.iter().map(String::from).collect();
} else {
// Add a new mount.
@ -94,7 +94,7 @@ fn keep_settings_mount(
fn adjust_termination_path(mount: &mut policy::KataMount, yaml_container: &pod::Container) {
if mount.destination == "/dev/termination-log" {
if let Some(path) = &yaml_container.terminationMessagePath {
mount.destination = path.clone();
mount.destination.clone_from(path);
}
}
}

View File

@ -570,10 +570,12 @@ impl AgentPolicy {
linux.Namespaces = get_kata_namespaces(is_pause_container, use_host_network);
if !c_settings.Linux.MaskedPaths.is_empty() {
linux.MaskedPaths = c_settings.Linux.MaskedPaths.clone();
linux.MaskedPaths.clone_from(&c_settings.Linux.MaskedPaths);
}
if !c_settings.Linux.ReadonlyPaths.is_empty() {
linux.ReadonlyPaths = c_settings.Linux.ReadonlyPaths.clone();
linux
.ReadonlyPaths
.clone_from(&c_settings.Linux.ReadonlyPaths);
}
let sandbox_pidns = if is_pause_container {
@ -722,7 +724,7 @@ fn get_image_layer_storages(
"previous_chain_id = {}, chain_id = {}",
&previous_chain_id, &chain_id
);
previous_chain_id = chain_id.clone();
previous_chain_id.clone_from(&chain_id);
layer_names.push(name_to_hash(&chain_id));
layer_hashes.push(layer.verity_hash.to_string());

View File

@ -215,7 +215,7 @@ impl Container {
if let Some(working_dir) = &docker_config.WorkingDir {
if !working_dir.is_empty() {
process.Cwd = working_dir.clone();
process.Cwd.clone_from(working_dir);
}
}
@ -344,6 +344,7 @@ pub fn add_verity_to_store(cache_file: &str, diff_id: &str, verity_hash: &str) -
.read(true)
.write(true)
.create(true)
.truncate(false)
.open(cache_file)?;
let mut data: Vec<ImageLayer> = if let Ok(vec) = serde_json::from_reader(read_file) {

View File

@ -0,0 +1,101 @@
// Copyright (c) 2024 Edgeless Systems GmbH
//
// SPDX-License-Identifier: Apache-2.0
//
use std::any;
use std::fs::{self, File};
use std::path;
use std::process::Command;
use std::str;
use protocols::agent::{CopyFileRequest, CreateSandboxRequest};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize)]
struct TestCase<T> {
description: String,
allowed: bool,
request: T,
}
/// Run tests from the given directory.
/// The directory is searched under `src/tools/genpolicy/tests/testdata`, and
/// 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
/// should be exactly one entry with a PodSpec. The test case file must contain
/// a JSON list of [TestCase] instances appropriate for `T`.
fn runtests<T>(test_case_dir: &str)
where
T: DeserializeOwned + Serialize,
{
// Prepare temp dir for running genpolicy.
let workdir = path::PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join(test_case_dir);
fs::create_dir_all(&workdir)
.expect("should be able to create directories under CARGO_TARGET_TMPDIR");
let genpolicy_dir = path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
for base in ["rules.rego", "genpolicy-settings.json"] {
fs::copy(genpolicy_dir.join(base), workdir.join(base))
.expect("copying files around should not fail");
}
let test_data = genpolicy_dir.join("tests/testdata").join(test_case_dir);
fs::copy(test_data.join("pod.yaml"), workdir.join("pod.yaml"))
.expect("copying files around should not fail");
// Run the command and return the generated policy.
let output = Command::new(env!("CARGO_BIN_EXE_genpolicy"))
.current_dir(workdir)
.args(["-u", "-r", "-y", "pod.yaml"])
.output()
.expect("executing the genpolicy command should not fail");
assert_eq!(
output.status.code(),
Some(0),
"genpolicy failed: {}",
str::from_utf8(output.stderr.as_slice()).expect("genpolicy should return status code 0")
);
let policy = str::from_utf8(output.stdout.as_slice())
.unwrap()
.to_string();
// Set up the policy engine.
let mut pol = regorus::Engine::new();
pol.add_policy("policy.rego".to_string(), policy).unwrap();
// Run through the test cases and evaluate the canned requests.
let case_file =
File::open(test_data.join("testcases.json")).expect("test case file should open");
let test_cases: Vec<TestCase<T>> =
serde_json::from_reader(case_file).expect("test case file should parse");
for test_case in test_cases {
println!("\n== case: {} ==\n", test_case.description);
let v = serde_json::to_value(&test_case.request).unwrap();
pol.set_input(v.into());
let query = format!(
"data.agent_policy.{}",
any::type_name::<T>().split("::").last().unwrap()
);
assert_eq!(test_case.allowed, pol.eval_deny_query(query, true));
}
}
#[test]
fn test_copyfile() {
runtests::<CopyFileRequest>("copyfile");
}
#[test]
fn test_create_sandbox() {
runtests::<CreateSandboxRequest>("createsandbox");
}

View File

@ -0,0 +1,9 @@
apiVersion: v1
kind: Pod
metadata:
name: dummy
spec:
runtimeClassName: kata-cc-isolation
containers:
- name: dummy
image: registry.k8s.io/pause:3.6@sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db

View File

@ -0,0 +1,16 @@
[
{
"description": "copy initiated by k8s mount",
"allowed": true,
"request": {
"path": "/run/kata-containers/shared/containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc-ce23cfeb91e75aaa-resolv.conf"
}
},
{
"description": "attempt to copy outside of container root",
"allowed": false,
"request": {
"path": "/etc/ssl/cert.pem"
}
}
]

View File

@ -0,0 +1,9 @@
apiVersion: v1
kind: Pod
metadata:
name: dummy
spec:
runtimeClassName: kata-cc-isolation
containers:
- name: dummy
image: registry.k8s.io/pause:3.6@sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db

View File

@ -0,0 +1,9 @@
[
{
"description": "no pidns",
"allowed": true,
"request": {
"sandbox_pidns": false
}
}
]

View File

@ -30,5 +30,6 @@ RUN apk --no-cache add \
openssl-libs-static \
make \
musl-dev \
perl \
protoc && \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain ${RUST_TOOLCHAIN}