-
-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: service_account_missing validation check
- Loading branch information
Showing
16 changed files
with
264 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# SimKube Trace Validation Checks | ||
|
||
| code | name | description | | ||
|---|---|---| | ||
| W0000 | status_field_populated | Indicates that the status field of a Kubernetes object in the trace is non-empty; status fields are updated by their controlling objects and shouldn't be applied "by hand". This is probably "fine" but it would be better to clean them up (and also they take up a lot of space. | | ||
| E0001 | service_account_missing | A pod needs a service account that is not present in the trace file. The simulation will fail because pods cannot be created if their service account does not exist. | | ||
|
||
This file is auto-generated; to rebuild, run `make validation_rules`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
pub mod service_account_missing; | ||
pub mod status_field_populated; | ||
|
||
#[cfg(test)] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
use std::collections::{ | ||
BTreeMap, | ||
HashSet, | ||
}; | ||
use std::sync::{ | ||
Arc, | ||
RwLock, | ||
}; | ||
|
||
use json_patch_ext::prelude::*; | ||
use sk_core::k8s::GVK; | ||
use sk_core::prelude::*; | ||
use sk_store::TracerConfig; | ||
|
||
use crate::validation::validator::{ | ||
CheckResult, | ||
Diagnostic, | ||
Validator, | ||
ValidatorType, | ||
}; | ||
use crate::validation::{ | ||
AnnotatedTraceEvent, | ||
AnnotatedTracePatch, | ||
PatchLocations, | ||
}; | ||
|
||
const HELP: &str = r#"A pod needs a service account that is not present in | ||
the trace file. The simulation will fail because pods cannot be created | ||
if their service account does not exist."#; | ||
|
||
#[derive(Default)] | ||
pub struct ServiceAccountMissing { | ||
pub(crate) seen_service_accounts: HashSet<String>, | ||
} | ||
|
||
impl Diagnostic for ServiceAccountMissing { | ||
fn check_next_event(&mut self, event: &mut AnnotatedTraceEvent, config: &TracerConfig) -> CheckResult { | ||
for obj in &event.data.applied_objs { | ||
if let Some(ref type_meta) = obj.types { | ||
if &type_meta.kind == "ServiceAccount" { | ||
self.seen_service_accounts.insert(obj.namespaced_name()); | ||
} | ||
} | ||
} | ||
for obj in &event.data.deleted_objs { | ||
if let Some(ref type_meta) = obj.types { | ||
if &type_meta.kind == "ServiceAccount" { | ||
self.seen_service_accounts.remove(&obj.namespaced_name()); | ||
} | ||
} | ||
} | ||
|
||
let mut patches = vec![]; | ||
for (i, obj) in event.data.applied_objs.iter().enumerate() { | ||
let gvk = GVK::from_dynamic_obj(obj)?; | ||
if let Some(pod_spec_template_path) = config.pod_spec_template_path(&gvk) { | ||
let sa_ptrs = [ | ||
// serviceAccount is deprecated but still supported (for now) | ||
format_ptr!("{pod_spec_template_path}/spec/serviceAccount"), | ||
format_ptr!("{pod_spec_template_path}/spec/serviceAccountName"), | ||
]; | ||
if let Some(sa) = sa_ptrs.iter().filter_map(|ptr| ptr.resolve(&obj.data).ok()).next() { | ||
if !self.seen_service_accounts.contains(sa.as_str().expect("expected string")) { | ||
let fix = AnnotatedTracePatch { | ||
locations: PatchLocations::ObjectReference( | ||
obj.types.clone().unwrap_or_default(), | ||
obj.namespaced_name(), | ||
), | ||
ops: sa_ptrs.iter().map(|ptr| remove_operation(ptr.clone())).collect(), | ||
}; | ||
patches.push((i, vec![fix])); | ||
} | ||
} | ||
} | ||
} | ||
|
||
Ok(BTreeMap::from_iter(patches)) | ||
} | ||
|
||
fn reset(&mut self) { | ||
self.seen_service_accounts.clear(); | ||
} | ||
} | ||
|
||
pub fn validator() -> Validator { | ||
Validator { | ||
type_: ValidatorType::Error, | ||
name: "service_account_missing", | ||
help: HELP, | ||
diagnostic: Arc::new(RwLock::new(ServiceAccountMissing::default())), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,31 @@ | ||
mod service_account_missing_test; | ||
mod status_field_populated_test; | ||
|
||
use std::collections::HashMap; | ||
|
||
use rstest::*; | ||
use sk_core::prelude::*; | ||
use sk_store::{ | ||
TracerConfig, | ||
TrackedObjectConfig, | ||
}; | ||
|
||
use super::*; | ||
use crate::validation::validator::Diagnostic; | ||
use crate::validation::AnnotatedTraceEvent; | ||
|
||
#[fixture] | ||
fn test_trace_config() -> TracerConfig { | ||
TracerConfig { | ||
tracked_objects: HashMap::from([ | ||
( | ||
DEPL_GVK.clone(), | ||
TrackedObjectConfig { | ||
pod_spec_template_path: Some("/spec/template".into()), | ||
..Default::default() | ||
}, | ||
), | ||
(SA_GVK.clone(), Default::default()), | ||
]), | ||
} | ||
} |
113 changes: 113 additions & 0 deletions
113
sk-cli/src/validation/rules/tests/service_account_missing_test.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
use assertables::*; | ||
use serde_json::json; | ||
use sk_store::{ | ||
TraceEvent, | ||
TracerConfig, | ||
}; | ||
|
||
use super::service_account_missing::ServiceAccountMissing; | ||
use super::*; | ||
|
||
#[fixture] | ||
fn depl_event(test_deployment: DynamicObject, #[default("serviceAccount")] sa_key: &str) -> AnnotatedTraceEvent { | ||
AnnotatedTraceEvent { | ||
data: TraceEvent { | ||
ts: 1, | ||
applied_objs: vec![test_deployment.data(json!({"spec": {"template": {"spec": {sa_key: "foobar"}}}}))], | ||
deleted_objs: vec![], | ||
}, | ||
..Default::default() | ||
} | ||
} | ||
|
||
#[fixture] | ||
fn sa_event(test_service_account: DynamicObject) -> AnnotatedTraceEvent { | ||
AnnotatedTraceEvent { | ||
data: TraceEvent { | ||
ts: 0, | ||
applied_objs: vec![test_service_account], | ||
deleted_objs: vec![], | ||
}, | ||
..Default::default() | ||
} | ||
} | ||
|
||
#[rstest] | ||
#[case("serviceAccount")] | ||
#[case("serviceAccountName")] | ||
fn test_service_account_missing(test_deployment: DynamicObject, test_trace_config: TracerConfig, #[case] sa_key: &str) { | ||
let mut v = ServiceAccountMissing::default(); | ||
let mut evt = depl_event(test_deployment, sa_key); | ||
let annotations = v.check_next_event(&mut evt, &test_trace_config).unwrap(); | ||
|
||
assert_eq!(annotations.keys().collect::<Vec<_>>(), vec![&0]); | ||
} | ||
|
||
#[rstest] | ||
fn test_service_account_missing_deleted( | ||
mut depl_event: AnnotatedTraceEvent, | ||
mut sa_event: AnnotatedTraceEvent, | ||
test_service_account: DynamicObject, | ||
test_trace_config: TracerConfig, | ||
) { | ||
let mut v = ServiceAccountMissing::default(); | ||
let mut sa_event_del = AnnotatedTraceEvent { | ||
data: TraceEvent { | ||
ts: 0, | ||
applied_objs: vec![], | ||
deleted_objs: vec![test_service_account], | ||
}, | ||
..Default::default() | ||
}; | ||
v.check_next_event(&mut sa_event, &test_trace_config).unwrap(); | ||
v.check_next_event(&mut sa_event_del, &test_trace_config).unwrap(); | ||
let annotations = v.check_next_event(&mut depl_event, &test_trace_config).unwrap(); | ||
|
||
assert_eq!(annotations.keys().collect::<Vec<_>>(), vec![&0]); | ||
} | ||
|
||
#[rstest] | ||
fn test_service_account_not_missing( | ||
mut depl_event: AnnotatedTraceEvent, | ||
mut sa_event: AnnotatedTraceEvent, | ||
test_trace_config: TracerConfig, | ||
) { | ||
let mut v = ServiceAccountMissing::default(); | ||
v.check_next_event(&mut sa_event, &test_trace_config).unwrap(); | ||
let annotations = v.check_next_event(&mut depl_event, &test_trace_config).unwrap(); | ||
|
||
assert_eq!(annotations.keys().collect::<Vec<_>>(), vec![&0]); | ||
} | ||
|
||
#[rstest] | ||
fn test_service_account_not_missing_same_evt( | ||
test_deployment: DynamicObject, | ||
test_service_account: DynamicObject, | ||
test_trace_config: TracerConfig, | ||
) { | ||
let mut v = ServiceAccountMissing::default(); | ||
let mut depl_evt = AnnotatedTraceEvent { | ||
data: TraceEvent { | ||
ts: 1, | ||
applied_objs: vec![ | ||
test_deployment | ||
.data(json!({"spec": {"template": {"spec": {"serviceAccountName": TEST_SERVICE_ACCOUNT}}}})), | ||
test_service_account, | ||
], | ||
deleted_objs: vec![], | ||
}, | ||
..Default::default() | ||
}; | ||
let annotations = v.check_next_event(&mut depl_evt, &test_trace_config).unwrap(); | ||
|
||
assert_eq!(annotations.keys().collect::<Vec<_>>(), vec![&0]); | ||
} | ||
|
||
#[rstest] | ||
fn test_service_account_reset(mut depl_event: AnnotatedTraceEvent, test_trace_config: TracerConfig) { | ||
let mut v = ServiceAccountMissing::default(); | ||
v.check_next_event(&mut depl_event, &test_trace_config).unwrap(); | ||
v.reset(); | ||
|
||
assert_is_empty!(v.seen_service_accounts); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.