Skip to content

Commit 35372d4

Browse files
committed
feat: add settings model for notation image verifier
Add basic setting for an image verifier plugin that configures the notation CLI with a trustpolicy. The settings accepts a base64 encoded trustpolicy.json to be decoded and written to notation's configuration. Signed-off-by: Gavin Inglis <[email protected]>
1 parent 724d2fc commit 35372d4

File tree

7 files changed

+192
-0
lines changed

7 files changed

+192
-0
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ members = [
3030
"bottlerocket-settings-models/settings-extensions/dns",
3131
"bottlerocket-settings-models/settings-extensions/ecs",
3232
"bottlerocket-settings-models/settings-extensions/host-containers",
33+
"bottlerocket-settings-models/settings-extensions/image-verifier-plugins",
3334
"bottlerocket-settings-models/settings-extensions/kernel",
3435
"bottlerocket-settings-models/settings-extensions/kubernetes",
3536
"bottlerocket-settings-models/settings-extensions/kubelet-device-plugins",
@@ -75,6 +76,7 @@ settings-extension-container-runtime-plugins = { path = "./bottlerocket-settings
7576
settings-extension-dns = { path = "./bottlerocket-settings-models/settings-extensions/dns", version = "0.1" }
7677
settings-extension-ecs = { path = "./bottlerocket-settings-models/settings-extensions/ecs", version = "0.1" }
7778
settings-extension-host-containers = { path = "./bottlerocket-settings-models/settings-extensions/host-containers", version = "0.2" }
79+
settings-extension-image-verifier-plugins = { path = "./bottlerocket-settings-models/settings-extensions/image-verifier-plugins", version = "0.1" }
7880
settings-extension-kernel = { path = "./bottlerocket-settings-models/settings-extensions/kernel", version = "0.1" }
7981
settings-extension-kubernetes = { path = "./bottlerocket-settings-models/settings-extensions/kubernetes", version = "0.6" }
8082
settings-extension-kubelet-device-plugins = { path = "./bottlerocket-settings-models/settings-extensions/kubelet-device-plugins", version = "0.3" }
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "settings-extension-image-verifier-plugins"
3+
version = "0.1.0"
4+
authors = ["Gavin Inglis <[email protected]>"]
5+
license = "Apache-2.0 OR MIT"
6+
edition = "2021"
7+
publish = false
8+
9+
[dependencies]
10+
bottlerocket-modeled-types.workspace = true
11+
bottlerocket-model-derive.workspace = true
12+
bottlerocket-settings-sdk.workspace = true
13+
env_logger.workspace = true
14+
serde = { workspace = true, features = ["derive"] }
15+
serde_json.workspace = true
16+
17+
[lints]
18+
workspace = true
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[extension]
2+
supported-versions = [
3+
"v1"
4+
]
5+
default-version = "v1"
6+
7+
[v1]
8+
[v1.validation.cross-validates]
9+
10+
[v1.templating]
11+
helpers = []
12+
13+
[v1.generation.requires]
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
//! Settings related to Image Verifier Plugins
2+
3+
use bottlerocket_model_derive::model;
4+
use bottlerocket_modeled_types::ValidBase64;
5+
use bottlerocket_settings_sdk::{GenerateResult, SettingsModel};
6+
use std::convert::Infallible;
7+
8+
#[model(impl_default = true)]
9+
pub struct ImageVerifierPluginsSettingsV1 {
10+
enabled: bool,
11+
notation: NotationSettings,
12+
}
13+
14+
#[model(impl_default = true)]
15+
pub struct NotationSettings {
16+
/// Base64 encoded trustpolicy.json
17+
/// https://github.com/notaryproject/specifications/blob/main/specs/trust-store-trust-policy.md#trust-store
18+
trustpolicy: ValidBase64,
19+
}
20+
21+
type Result<T> = std::result::Result<T, Infallible>;
22+
23+
impl SettingsModel for ImageVerifierPluginsSettingsV1 {
24+
type PartialKind = Self;
25+
type ErrorKind = Infallible;
26+
27+
fn get_version() -> &'static str {
28+
"v1"
29+
}
30+
31+
fn set(_current_value: Option<Self>, _target: Self) -> Result<()> {
32+
// Set anything that can be parsed as ImageVerifierPluginsSettingsV1.
33+
Ok(())
34+
}
35+
36+
fn generate(
37+
existing_partial: Option<Self::PartialKind>,
38+
_dependent_settings: Option<serde_json::Value>,
39+
) -> Result<GenerateResult<Self::PartialKind, Self>> {
40+
Ok(GenerateResult::Complete(
41+
existing_partial.unwrap_or_default(),
42+
))
43+
}
44+
45+
fn validate(_value: Self, _validated_settings: Option<serde_json::Value>) -> Result<()> {
46+
// ImageVerifierPluginsSettingsV1 is validated during deserialization.
47+
Ok(())
48+
}
49+
}
50+
51+
#[cfg(test)]
52+
mod test {
53+
use super::*;
54+
use serde_json::json;
55+
56+
#[test]
57+
fn test_generate_image_verifier_plugins_settings() {
58+
assert_eq!(
59+
ImageVerifierPluginsSettingsV1::generate(None, None),
60+
Ok(GenerateResult::Complete(ImageVerifierPluginsSettingsV1 {
61+
enabled: None,
62+
notation: None
63+
}))
64+
)
65+
}
66+
67+
#[test]
68+
fn test_serde_image_verifier_plugins() {
69+
let test_json = json!({
70+
"enabled": true,
71+
"notation": {
72+
"trustpolicy": "ewogICJ2ZXJzaW9uIjogIjEuMCIsCiAgInRydXN0UG9saWNpZXMiOiBbXQp9"
73+
}
74+
});
75+
76+
let test_json_str = test_json.to_string();
77+
78+
let image_verifier_plugins_settings: ImageVerifierPluginsSettingsV1 =
79+
serde_json::from_str(&test_json_str).unwrap();
80+
81+
assert_eq!(image_verifier_plugins_settings.enabled, Some(true));
82+
assert_eq!(
83+
image_verifier_plugins_settings
84+
.notation
85+
.as_ref()
86+
.unwrap()
87+
.trustpolicy
88+
.as_ref()
89+
.unwrap()
90+
.as_ref(),
91+
"ewogICJ2ZXJzaW9uIjogIjEuMCIsCiAgInRydXN0UG9saWNpZXMiOiBbXQp9"
92+
);
93+
}
94+
95+
#[test]
96+
fn test_serde_image_verifier_plugins_empty() {
97+
let test_json = json!({});
98+
99+
let test_json_str = test_json.to_string();
100+
101+
let image_verifier_plugins_settings: ImageVerifierPluginsSettingsV1 =
102+
serde_json::from_str(&test_json_str).unwrap();
103+
104+
assert!(image_verifier_plugins_settings.enabled.is_none());
105+
assert!(image_verifier_plugins_settings.notation.is_none());
106+
}
107+
108+
#[test]
109+
fn test_serde_image_verifier_plugins_enabled_only() {
110+
let test_json = json!({
111+
"enabled": false
112+
});
113+
114+
let test_json_str = test_json.to_string();
115+
116+
let image_verifier_plugins_settings: ImageVerifierPluginsSettingsV1 =
117+
serde_json::from_str(&test_json_str).unwrap();
118+
119+
assert_eq!(image_verifier_plugins_settings.enabled, Some(false));
120+
assert!(image_verifier_plugins_settings.notation.is_none());
121+
}
122+
123+
#[test]
124+
fn test_serde_image_verifier_plugins_invalid_base64() {
125+
let test_json = json!({
126+
"notation": {
127+
"trustpolicy": "invalid-base64!"
128+
}
129+
});
130+
131+
let test_json_str = test_json.to_string();
132+
133+
let result = serde_json::from_str::<ImageVerifierPluginsSettingsV1>(&test_json_str);
134+
135+
assert!(result.is_err());
136+
}
137+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder};
2+
use settings_extension_image_verifier_plugins::ImageVerifierPluginsSettingsV1;
3+
use std::process::ExitCode;
4+
5+
fn main() -> ExitCode {
6+
env_logger::init();
7+
8+
match NullMigratorExtensionBuilder::with_name("image-verifier-plugins")
9+
.with_models(vec![
10+
BottlerocketSetting::<ImageVerifierPluginsSettingsV1>::model(),
11+
])
12+
.build()
13+
{
14+
Ok(extension) => extension.run(),
15+
Err(e) => {
16+
println!("{e}");
17+
ExitCode::FAILURE
18+
}
19+
}
20+
}

bottlerocket-settings-models/settings-models/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ settings-extension-container-runtime-plugins.workspace = true
3333
settings-extension-dns.workspace = true
3434
settings-extension-ecs.workspace = true
3535
settings-extension-host-containers.workspace = true
36+
settings-extension-image-verifier-plugins.workspace = true
3637
settings-extension-kernel.workspace = true
3738
settings-extension-kubernetes.workspace = true
3839
settings-extension-kubelet-device-plugins.workspace = true

bottlerocket-settings-models/settings-models/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub use settings_extension_container_runtime_plugins::{self, ContainerRuntimePlu
3636
pub use settings_extension_dns::{self, DnsSettingsV1};
3737
pub use settings_extension_ecs::{self, ECSSettingsV1};
3838
pub use settings_extension_host_containers::{self, HostContainersSettingsV1};
39+
pub use settings_extension_image_verifier_plugins::{self, ImageVerifierPluginsSettingsV1};
3940
pub use settings_extension_kernel::{self, KernelSettingsV1};
4041
pub use settings_extension_kubelet_device_plugins::{self, KubeletDevicePluginsV1};
4142
pub use settings_extension_kubernetes::{self, KubernetesSettingsV1};

0 commit comments

Comments
 (0)