@@ -602,6 +602,8 @@ impl EvaluationEnvironment {
602
602
Mutex < HashMap < String , PolicyGroupMemberEvaluationResult > > ,
603
603
> = Arc :: new ( Mutex :: new ( HashMap :: new ( ) ) ) ;
604
604
605
+ let policy_ids = policies. clone ( ) ;
606
+
605
607
for sub_policy_name in policies {
606
608
let sub_policy_id = PolicyID :: PolicyGroupPolicy {
607
609
group : policy_id. to_string ( ) ,
@@ -668,9 +670,15 @@ impl EvaluationEnvironment {
668
670
669
671
// Provide some feedback to the end user about the single policy evaluation results
670
672
let evaluation_results = policies_evaluation_results. lock ( ) . unwrap ( ) ;
671
- let warnings: Vec < String > = evaluation_results
673
+ let warnings: Vec < String > = policy_ids
672
674
. iter ( )
673
- . map ( |( policy, result) | format ! ( "{}: {}" , policy, result) )
675
+ . map ( |policy_id| {
676
+ let result = evaluation_results
677
+ . get ( policy_id)
678
+ . map ( |result| result. to_string ( ) )
679
+ . unwrap_or_else ( || "[NOT EVALUATED]" . to_string ( ) ) ;
680
+ format ! ( "{}: {}" , policy_id, result)
681
+ } )
674
682
. collect ( ) ;
675
683
676
684
Ok ( AdmissionResponse {
@@ -728,31 +736,67 @@ fn create_policy_evaluator_pre(
728
736
mod tests {
729
737
use policy_evaluator:: policy_evaluator:: ValidateRequest ;
730
738
use rstest:: * ;
739
+ use sha2:: { Digest , Sha256 } ;
731
740
use std:: collections:: BTreeSet ;
732
741
733
742
use super :: * ;
734
743
use crate :: config:: { PolicyGroupMember , PolicyOrPolicyGroup } ;
735
744
use crate :: test_utils:: build_admission_review_request;
736
745
746
+ /// build a precompiled policy of the given wasm module. Assumes this is a OPA Gatekeeper policy
747
+ fn build_precompiled_policy (
748
+ engine : & wasmtime:: Engine ,
749
+ module_bytes : & [ u8 ] ,
750
+ ) -> PrecompiledPolicy {
751
+ let module = wasmtime:: Module :: new ( engine, module_bytes)
752
+ . expect ( "should be able to build the smallest wasm module ever" ) ;
753
+
754
+ // calculate the digest of the module using sha256
755
+ let mut hasher = Sha256 :: new ( ) ;
756
+ hasher. update ( module_bytes) ;
757
+ let digest = hasher. finalize ( ) ;
758
+
759
+ PrecompiledPolicy {
760
+ precompiled_module : module. serialize ( ) . unwrap ( ) ,
761
+ execution_mode : policy_evaluator:: policy_evaluator:: PolicyExecutionMode :: OpaGatekeeper ,
762
+ digest : format ! ( "{digest:x}" ) ,
763
+ }
764
+ }
765
+
737
766
fn build_evaluation_environment ( ) -> EvaluationEnvironment {
738
767
let engine = wasmtime:: Engine :: default ( ) ;
739
- let policy_ids = vec ! [ "policy_1" , "policy_2" ] ;
740
- let module_bytes = include_bytes ! ( "../../tests/data/gatekeeper_always_happy_policy.wasm" ) ;
768
+ let module_bytes_always_happy =
769
+ include_bytes ! ( "../../tests/data/gatekeeper_always_happy_policy.wasm" ) ;
770
+ let module_bytes_always_unhappy =
771
+ include_bytes ! ( "../../tests/data/gatekeeper_always_unhappy_policy.wasm" ) ;
741
772
742
- let module = wasmtime:: Module :: new ( & engine, module_bytes)
743
- . expect ( "should be able to build the smallest wasm module ever" ) ;
744
773
let ( callback_handler_tx, _) = mpsc:: channel ( 10 ) ;
745
774
746
- let precompiled_policy = PrecompiledPolicy {
747
- precompiled_module : module. serialize ( ) . unwrap ( ) ,
748
- execution_mode : policy_evaluator:: policy_evaluator:: PolicyExecutionMode :: OpaGatekeeper ,
749
- digest : "unique-digest" . to_string ( ) ,
750
- } ;
775
+ let precompiled_policy_happy = build_precompiled_policy ( & engine, module_bytes_always_happy) ;
776
+ let precompiled_policy_unhappy =
777
+ build_precompiled_policy ( & engine, module_bytes_always_unhappy) ;
778
+
779
+ let test_policies: HashMap < String , PrecompiledPolicy > = vec ! [
780
+ (
781
+ "happy_policy_1" . to_string( ) ,
782
+ precompiled_policy_happy. clone( ) ,
783
+ ) ,
784
+ (
785
+ "happy_policy_2" . to_string( ) ,
786
+ precompiled_policy_happy. clone( ) ,
787
+ ) ,
788
+ (
789
+ "unhappy_policy_1" . to_string( ) ,
790
+ precompiled_policy_unhappy. clone( ) ,
791
+ ) ,
792
+ ]
793
+ . into_iter ( )
794
+ . collect ( ) ;
751
795
752
796
let mut policies: HashMap < String , crate :: config:: PolicyOrPolicyGroup > = HashMap :: new ( ) ;
753
797
let mut precompiled_policies: PrecompiledPolicies = PrecompiledPolicies :: new ( ) ;
754
798
755
- for policy_id in & policy_ids {
799
+ for ( policy_id, precompiled_policy ) in & test_policies {
756
800
let policy_url = format ! ( "file:///tmp/{policy_id}.wasm" ) ;
757
801
policies. insert (
758
802
policy_id. to_string ( ) ,
@@ -773,16 +817,16 @@ mod tests {
773
817
PolicyOrPolicyGroup :: PolicyGroup {
774
818
policy_mode : PolicyMode :: Protect ,
775
819
policies : vec ! [ (
776
- "policy_1 " . to_string( ) ,
820
+ "happy_policy_1 " . to_string( ) ,
777
821
PolicyGroupMember {
778
- url: "file:///tmp/policy_1 .wasm" . to_string( ) ,
822
+ url: "file:///tmp/happy_policy_1 .wasm" . to_string( ) ,
779
823
settings: None ,
780
824
context_aware_resources: BTreeSet :: new( ) ,
781
825
} ,
782
826
) ]
783
827
. into_iter ( )
784
828
. collect ( ) ,
785
- expression : "true || policy_1 ()" . to_string ( ) ,
829
+ expression : "true || happy_policy_1 ()" . to_string ( ) ,
786
830
message : "something went wrong" . to_string ( ) ,
787
831
} ,
788
832
) ;
@@ -800,16 +844,16 @@ mod tests {
800
844
PolicyOrPolicyGroup :: PolicyGroup {
801
845
policy_mode : PolicyMode :: Protect ,
802
846
policies : vec ! [ (
803
- "policy_1 " . to_string( ) ,
847
+ "happy_policy_1 " . to_string( ) ,
804
848
PolicyGroupMember {
805
- url: "file:///tmp/policy_1 .wasm" . to_string( ) ,
849
+ url: "file:///tmp/happy_policy_1 .wasm" . to_string( ) ,
806
850
settings: None ,
807
851
context_aware_resources: BTreeSet :: new( ) ,
808
852
} ,
809
853
) ]
810
854
. into_iter ( )
811
855
. collect ( ) ,
812
- expression : "not_a_known_policy () || policy_1 ()" . to_string ( ) ,
856
+ expression : "unknown_policy () || happy_policy_1 ()" . to_string ( ) ,
813
857
message : "something went wrong" . to_string ( ) ,
814
858
} ,
815
859
) ;
@@ -837,16 +881,91 @@ mod tests {
837
881
PolicyOrPolicyGroup :: PolicyGroup {
838
882
policy_mode : PolicyMode :: Protect ,
839
883
policies : vec ! [ (
840
- "policy_1 " . to_string( ) ,
884
+ "happy_policy_1 " . to_string( ) ,
841
885
PolicyGroupMember {
842
- url: "file:///tmp/policy_1 .wasm" . to_string( ) ,
886
+ url: "file:///tmp/happy_policy_1 .wasm" . to_string( ) ,
843
887
settings: None ,
844
888
context_aware_resources: BTreeSet :: new( ) ,
845
889
} ,
846
890
) ]
847
891
. into_iter ( )
848
892
. collect ( ) ,
849
- expression : "policy_1() + 1" . to_string ( ) ,
893
+ expression : "happy_policy_1() + 1" . to_string ( ) ,
894
+ message : "something went wrong" . to_string ( ) ,
895
+ } ,
896
+ ) ;
897
+ policies. insert (
898
+ "group_policy_with_unhappy_or_bracket_happy_and_unhappy_bracket" . to_string ( ) ,
899
+ PolicyOrPolicyGroup :: PolicyGroup {
900
+ policy_mode : PolicyMode :: Protect ,
901
+ policies : vec ! [
902
+ (
903
+ "happy_policy_1" . to_string( ) ,
904
+ PolicyGroupMember {
905
+ url: "file:///tmp/happy_policy_1.wasm" . to_string( ) ,
906
+ settings: None ,
907
+ context_aware_resources: BTreeSet :: new( ) ,
908
+ } ,
909
+ ) ,
910
+ (
911
+ "unhappy_policy_1" . to_string( ) ,
912
+ PolicyGroupMember {
913
+ url: "file:///tmp/unhappy_policy_1.wasm" . to_string( ) ,
914
+ settings: None ,
915
+ context_aware_resources: BTreeSet :: new( ) ,
916
+ } ,
917
+ ) ,
918
+ (
919
+ "unhappy_policy_2" . to_string( ) ,
920
+ PolicyGroupMember {
921
+ url: "file:///tmp/unhappy_policy_1.wasm" . to_string( ) ,
922
+ settings: None ,
923
+ context_aware_resources: BTreeSet :: new( ) ,
924
+ } ,
925
+ ) ,
926
+ ]
927
+ . into_iter ( )
928
+ . collect ( ) ,
929
+ expression : "unhappy_policy_1() || (happy_policy_1() && unhappy_policy_2())"
930
+ . to_string ( ) ,
931
+ message : "something went wrong" . to_string ( ) ,
932
+ } ,
933
+ ) ;
934
+
935
+ policies. insert (
936
+ "group_policy_with_unhappy_or_happy_or_unhappy" . to_string ( ) ,
937
+ PolicyOrPolicyGroup :: PolicyGroup {
938
+ policy_mode : PolicyMode :: Protect ,
939
+ policies : vec ! [
940
+ (
941
+ "happy_policy_1" . to_string( ) ,
942
+ PolicyGroupMember {
943
+ url: "file:///tmp/happy_policy_1.wasm" . to_string( ) ,
944
+ settings: None ,
945
+ context_aware_resources: BTreeSet :: new( ) ,
946
+ } ,
947
+ ) ,
948
+ (
949
+ "unhappy_policy_1" . to_string( ) ,
950
+ PolicyGroupMember {
951
+ url: "file:///tmp/unhappy_policy_1.wasm" . to_string( ) ,
952
+ settings: None ,
953
+ context_aware_resources: BTreeSet :: new( ) ,
954
+ } ,
955
+ ) ,
956
+ (
957
+ "unhappy_policy_2" . to_string( ) ,
958
+ PolicyGroupMember {
959
+ url: "file:///tmp/unhappy_policy_1.wasm" . to_string( ) ,
960
+ settings: None ,
961
+ context_aware_resources: BTreeSet :: new( ) ,
962
+ } ,
963
+ ) ,
964
+ ]
965
+ . into_iter ( )
966
+ . collect ( ) ,
967
+ expression : "unhappy_policy_1() || happy_policy_1() || unhappy_policy_2()"
968
+ . to_string ( ) ,
850
969
message : "something went wrong" . to_string ( ) ,
851
970
} ,
852
971
) ;
@@ -860,7 +979,7 @@ mod tests {
860
979
861
980
#[ rstest]
862
981
#[ case:: policy_not_defined( "policy_not_defined" , true ) ]
863
- #[ case:: policy_known( "policy_1 " , false ) ]
982
+ #[ case:: policy_known( "happy_policy_1 " , false ) ]
864
983
fn lookup_policy ( #[ case] policy_id : & str , #[ case] expect_error : bool ) {
865
984
let policy_id = PolicyID :: Policy ( policy_id. to_string ( ) ) ;
866
985
let evaluation_environment = Arc :: new ( build_evaluation_environment ( ) ) ;
@@ -892,23 +1011,75 @@ mod tests {
892
1011
assert ! ( evaluation_environment
893
1012
. get_policy_settings( & policy_id)
894
1013
. is_ok( ) ) ;
895
- // note: we do not test `validate` with a known policy because this would
896
- // cause another error. The test policy we're using is just an empty Wasm
897
- // module
1014
+ assert ! ( evaluation_environment
1015
+ . validate( & policy_id, & validate_request)
1016
+ . is_ok( ) ) ;
1017
+ }
1018
+ }
1019
+
1020
+ #[ rstest]
1021
+ #[ case:: all_policies_are_evaluated(
1022
+ "group_policy_with_unhappy_or_bracket_happy_and_unhappy_bracket" ,
1023
+ false ,
1024
+ vec![
1025
+ "unhappy_policy_2: [DENIED] - failing as expected" ,
1026
+ "unhappy_policy_1: [DENIED] - failing as expected" ,
1027
+ "happy_policy_1: [ALLOWED]" ,
1028
+ ] ,
1029
+ ) ]
1030
+ #[ case:: not_all_policies_are_evaluated(
1031
+ "group_policy_with_unhappy_or_happy_or_unhappy" ,
1032
+ true ,
1033
+ vec![
1034
+ "unhappy_policy_1: [DENIED] - failing as expected" ,
1035
+ "unhappy_policy_2: [NOT EVALUATED]" ,
1036
+ "happy_policy_1: [ALLOWED]" ,
1037
+ ] ,
1038
+ ) ]
1039
+ fn group_policy_warning_assignments (
1040
+ #[ case] policy_id : & str ,
1041
+ #[ case] admission_accepted : bool ,
1042
+ #[ case] expected_warnings : Vec < & str > ,
1043
+ ) {
1044
+ let policy_id = PolicyID :: Policy ( policy_id. to_string ( ) ) ;
1045
+ let evaluation_environment = Arc :: new ( build_evaluation_environment ( ) ) ;
1046
+ let validate_request =
1047
+ ValidateRequest :: AdmissionRequest ( build_admission_review_request ( ) . request ) ;
1048
+
1049
+ assert ! ( evaluation_environment. get_policy_mode( & policy_id) . is_ok( ) ) ;
1050
+ assert ! ( evaluation_environment
1051
+ . get_policy_allowed_to_mutate( & policy_id)
1052
+ . is_ok( ) ) ;
1053
+ assert ! ( evaluation_environment
1054
+ . get_policy_settings( & policy_id)
1055
+ . is_ok( ) ) ;
1056
+
1057
+ let response = evaluation_environment
1058
+ . validate ( & policy_id, & validate_request)
1059
+ . expect ( "should not have errored" ) ;
1060
+ assert_eq ! ( response. allowed, admission_accepted) ;
1061
+
1062
+ let warnings = response. warnings . expect ( "should have warnings" ) ;
1063
+ for expected in expected_warnings {
1064
+ assert ! (
1065
+ warnings. iter( ) . any( |w| w. contains( expected) ) ,
1066
+ "could not find {}" ,
1067
+ expected
1068
+ ) ;
898
1069
}
899
1070
}
900
1071
901
1072
/// Given to identical wasm modules, only one instance of PolicyEvaluator is going to be
902
1073
/// created
903
1074
#[ test]
904
- fn avoid_duplicated_instaces_of_policy_evaluator ( ) {
1075
+ fn avoid_duplicated_instances_of_policy_evaluator ( ) {
905
1076
let evaluation_environment = build_evaluation_environment ( ) ;
906
1077
907
1078
assert_eq ! (
908
1079
evaluation_environment
909
1080
. module_digest_to_policy_evaluator_pre
910
1081
. len( ) ,
911
- 1
1082
+ 2
912
1083
) ;
913
1084
}
914
1085
0 commit comments