Skip to content

Commit 2ed1b0e

Browse files
committed
EnsureFilePermissionsTest: behaviors all cases
Signed-off-by: Krzysztof Kanas <kkanas@microsoft.com>
1 parent 7026e0d commit 2ed1b0e

File tree

1 file changed

+374
-0
lines changed

1 file changed

+374
-0
lines changed

src/modules/complianceengine/tests/procedures/EnsureFilePermissionsTest.cpp

Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,3 +849,377 @@ TEST_F(EnsureFilePermissionsTest, AuditCollectionRecurseTrueNoneExists)
849849

850850
ASSERT_TRUE(mFormatter.Format(indicators).Value().find(", behavior none_exist") != std::string::npos);
851851
}
852+
853+
TEST_F(EnsureFilePermissionsTest, AuditCollectionRecurseTrueOnlyOneExists)
854+
{
855+
// Create top-level compliant file
856+
CreateFileInDir("top.txt", 0, 0, 0644);
857+
// Create nested directory and a non-compliant file inside it (wrong owner)
858+
std::string nestedDir = testDir + "/nested2";
859+
ASSERT_EQ(mkdir(nestedDir.c_str(), 0755), 0);
860+
861+
{
862+
std::string nestedFile = nestedDir + "/good1.txt";
863+
std::ofstream nf(nestedFile);
864+
nf << "content";
865+
nf.close();
866+
ASSERT_EQ(chmod(nestedFile.c_str(), 0644), 0);
867+
ASSERT_EQ(chown(nestedFile.c_str(), 0, 0), 0);
868+
files.push_back(nestedFile);
869+
}
870+
871+
{
872+
std::string nestedFile = nestedDir + "/good2.txt";
873+
std::ofstream nf(nestedFile);
874+
nf << "content";
875+
nf.close();
876+
ASSERT_EQ(chmod(nestedFile.c_str(), 0644), 0);
877+
ASSERT_EQ(chown(nestedFile.c_str(), 0, 0), 0);
878+
files.push_back(nestedFile);
879+
}
880+
EnsureFilePermissionsCollectionParams params;
881+
params.directory = testDir;
882+
params.ext = "*.txt"; // Matches both files but recurse true and Behavior OnlyOneExists
883+
auto owner = Pattern::Make("root");
884+
ASSERT_TRUE(owner.HasValue());
885+
params.owner = {{std::move(owner).Value()}};
886+
params.permissions = 0644;
887+
params.recurse = true;
888+
params.behavior = Behavior::OnlyOneExists;
889+
890+
auto result = AuditEnsureFilePermissionsCollection(params, indicators, mContext);
891+
ASSERT_TRUE(result.HasValue());
892+
ASSERT_EQ(result.Value(), Status::Compliant);
893+
894+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find(", behavior only_one_exists") != std::string::npos);
895+
}
896+
897+
TEST_F(EnsureFilePermissionsTest, AuditCollectionRecurseTrueOnlyOneExistsOneBad)
898+
{
899+
// Create top-level compliant file
900+
CreateFileInDir("top.txt", 0, 0, 0644);
901+
// Create nested directory and a non-compliant file inside it (wrong owner)
902+
std::string nestedDir = testDir + "/nested2";
903+
ASSERT_EQ(mkdir(nestedDir.c_str(), 0755), 0);
904+
905+
{
906+
std::string nestedFile = nestedDir + "/good1.txt";
907+
std::ofstream nf(nestedFile);
908+
nf << "content";
909+
nf.close();
910+
ASSERT_EQ(chmod(nestedFile.c_str(), 0644), 0);
911+
ASSERT_EQ(chown(nestedFile.c_str(), 0, 0), 0);
912+
files.push_back(nestedFile);
913+
}
914+
915+
{
916+
std::string nestedFile = nestedDir + "/bad.txt";
917+
std::ofstream nf(nestedFile);
918+
nf << "content";
919+
nf.close();
920+
ASSERT_EQ(chmod(nestedFile.c_str(), 0644), 0);
921+
ASSERT_EQ(chown(nestedFile.c_str(), 1, 0), 0);
922+
files.push_back(nestedFile);
923+
}
924+
EnsureFilePermissionsCollectionParams params;
925+
params.directory = testDir;
926+
params.ext = "*.txt"; // Matches both files but recurse true and Behavior OnlyOneExists
927+
auto owner = Pattern::Make("root");
928+
ASSERT_TRUE(owner.HasValue());
929+
params.owner = {{std::move(owner).Value()}};
930+
params.permissions = 0644;
931+
params.recurse = true;
932+
params.behavior = Behavior::OnlyOneExists;
933+
934+
auto result = AuditEnsureFilePermissionsCollection(params, indicators, mContext);
935+
ASSERT_TRUE(result.HasValue());
936+
ASSERT_EQ(result.Value(), Status::NonCompliant);
937+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find(", behavior only_one_exists") != std::string::npos);
938+
}
939+
940+
TEST_F(EnsureFilePermissionsTest, AuditCollectionRecurseTrueAtLeastOneExists)
941+
{
942+
// Create top-level compliant file
943+
CreateFileInDir("top.txt", 0, 0, 0644);
944+
// Create nested directory and a non-compliant file inside it (wrong owner)
945+
std::string nestedDir = testDir + "/nested2";
946+
ASSERT_EQ(mkdir(nestedDir.c_str(), 0755), 0);
947+
948+
{
949+
std::string nestedFile = nestedDir + "/good1.txt";
950+
std::ofstream nf(nestedFile);
951+
nf << "content";
952+
nf.close();
953+
ASSERT_EQ(chmod(nestedFile.c_str(), 0644), 0);
954+
ASSERT_EQ(chown(nestedFile.c_str(), 0, 0), 0);
955+
files.push_back(nestedFile);
956+
}
957+
958+
{
959+
std::string nestedFile = nestedDir + "/good2.txt";
960+
std::ofstream nf(nestedFile);
961+
nf << "content";
962+
nf.close();
963+
ASSERT_EQ(chmod(nestedFile.c_str(), 0644), 0);
964+
ASSERT_EQ(chown(nestedFile.c_str(), 0, 0), 0);
965+
files.push_back(nestedFile);
966+
}
967+
EnsureFilePermissionsCollectionParams params;
968+
params.directory = testDir;
969+
params.ext = "*.txt"; // Matches both files but recurse true and Behavior OnlyOneExists
970+
auto owner = Pattern::Make("root");
971+
ASSERT_TRUE(owner.HasValue());
972+
params.owner = {{std::move(owner).Value()}};
973+
params.permissions = 0644;
974+
params.recurse = true;
975+
params.behavior = Behavior::AtLeastOneExists;
976+
977+
auto result = AuditEnsureFilePermissionsCollection(params, indicators, mContext);
978+
ASSERT_TRUE(result.HasValue());
979+
ASSERT_EQ(result.Value(), Status::Compliant);
980+
981+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find(", behavior at_least_one_exists") != std::string::npos);
982+
}
983+
TEST_F(EnsureFilePermissionsTest, AuditCollectionRecurseTrueAtLeastOneExistsOneBad)
984+
{
985+
// Create top-level compliant file
986+
CreateFileInDir("top.txt", 0, 0, 0644);
987+
// Create nested directory and a non-compliant file inside it (wrong owner)
988+
std::string nestedDir = testDir + "/nested2";
989+
ASSERT_EQ(mkdir(nestedDir.c_str(), 0755), 0);
990+
991+
{
992+
std::string nestedFile = nestedDir + "/good1.txt";
993+
std::ofstream nf(nestedFile);
994+
nf << "content";
995+
nf.close();
996+
ASSERT_EQ(chmod(nestedFile.c_str(), 0644), 0);
997+
ASSERT_EQ(chown(nestedFile.c_str(), 0, 0), 0);
998+
files.push_back(nestedFile);
999+
}
1000+
1001+
{
1002+
std::string nestedFile = nestedDir + "/bad.txt";
1003+
std::ofstream nf(nestedFile);
1004+
nf << "content";
1005+
nf.close();
1006+
ASSERT_EQ(chmod(nestedFile.c_str(), 0644), 0);
1007+
ASSERT_EQ(chown(nestedFile.c_str(), 1, 0), 0);
1008+
files.push_back(nestedFile);
1009+
}
1010+
EnsureFilePermissionsCollectionParams params;
1011+
params.directory = testDir;
1012+
params.ext = "*.txt"; // Matches both files but recurse true and Behavior OnlyOneExists
1013+
auto owner = Pattern::Make("root");
1014+
ASSERT_TRUE(owner.HasValue());
1015+
params.owner = {{std::move(owner).Value()}};
1016+
params.permissions = 0644;
1017+
params.recurse = true;
1018+
params.behavior = Behavior::AtLeastOneExists;
1019+
1020+
auto result = AuditEnsureFilePermissionsCollection(params, indicators, mContext);
1021+
ASSERT_TRUE(result.HasValue());
1022+
ASSERT_EQ(result.Value(), Status::NonCompliant);
1023+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find(", behavior at_least_one_exists") != std::string::npos);
1024+
}
1025+
1026+
// ── Single-file: file exists, all Behavior values that are not NoneExist ──────
1027+
1028+
TEST_F(EnsureFilePermissionsTest, AuditFileExistsAnyExist)
1029+
{
1030+
EnsureFilePermissionsParams params;
1031+
CreateFile(params.filename, 0, 0, 0600);
1032+
params.behavior = Behavior::AnyExist;
1033+
1034+
auto result = AuditEnsureFilePermissions(params, indicators, mContext);
1035+
ASSERT_TRUE(result.HasValue());
1036+
ASSERT_EQ(result.Value(), Status::Compliant);
1037+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find("correct permissions and ownership, behavior any_exist") != std::string::npos);
1038+
}
1039+
1040+
TEST_F(EnsureFilePermissionsTest, AuditFileExistsOnlyOneExists)
1041+
{
1042+
EnsureFilePermissionsParams params;
1043+
CreateFile(params.filename, 0, 0, 0600);
1044+
params.behavior = Behavior::OnlyOneExists;
1045+
1046+
auto result = AuditEnsureFilePermissions(params, indicators, mContext);
1047+
ASSERT_TRUE(result.HasValue());
1048+
ASSERT_EQ(result.Value(), Status::Compliant);
1049+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find("correct permissions and ownership, behavior only_one_exists") != std::string::npos);
1050+
}
1051+
1052+
TEST_F(EnsureFilePermissionsTest, AuditFileExistsAtLeastOneExistsExplicit)
1053+
{
1054+
EnsureFilePermissionsParams params;
1055+
CreateFile(params.filename, 0, 0, 0600);
1056+
params.behavior = Behavior::AtLeastOneExists;
1057+
1058+
auto result = AuditEnsureFilePermissions(params, indicators, mContext);
1059+
ASSERT_TRUE(result.HasValue());
1060+
ASSERT_EQ(result.Value(), Status::Compliant);
1061+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find("correct permissions and ownership, behavior at_least_one_exists") != std::string::npos);
1062+
}
1063+
1064+
// ── Single-file: file exists with wrong owner — behavior must not skip perms ──
1065+
1066+
TEST_F(EnsureFilePermissionsTest, AuditFileExistsBadPermsAnyExist)
1067+
{
1068+
EnsureFilePermissionsParams params;
1069+
CreateFile(params.filename, 1, 0, 0600); // owner=bin, not root
1070+
auto owner = Pattern::Make("root");
1071+
ASSERT_TRUE(owner.HasValue());
1072+
params.owner = {{std::move(owner).Value()}};
1073+
params.behavior = Behavior::AnyExist;
1074+
1075+
auto result = AuditEnsureFilePermissions(params, indicators, mContext);
1076+
ASSERT_TRUE(result.HasValue());
1077+
ASSERT_EQ(result.Value(), Status::NonCompliant);
1078+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find("owner") != std::string::npos);
1079+
}
1080+
1081+
TEST_F(EnsureFilePermissionsTest, AuditFileExistsBadPermsOnlyOneExists)
1082+
{
1083+
EnsureFilePermissionsParams params;
1084+
CreateFile(params.filename, 1, 0, 0600); // owner=bin, not root
1085+
auto owner = Pattern::Make("root");
1086+
ASSERT_TRUE(owner.HasValue());
1087+
params.owner = {{std::move(owner).Value()}};
1088+
params.behavior = Behavior::OnlyOneExists;
1089+
1090+
auto result = AuditEnsureFilePermissions(params, indicators, mContext);
1091+
ASSERT_TRUE(result.HasValue());
1092+
ASSERT_EQ(result.Value(), Status::NonCompliant);
1093+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find("owner") != std::string::npos);
1094+
}
1095+
1096+
// ── Collection: no matching files, all Behavior values ────────────────────────
1097+
1098+
TEST_F(EnsureFilePermissionsTest, AuditCollectionNoMatchingFilesNoneExist)
1099+
{
1100+
CreateFileInDir("file1.log", 0, 0, 0644);
1101+
1102+
EnsureFilePermissionsCollectionParams params;
1103+
params.directory = testDir;
1104+
params.ext = "*.txt"; // no txt files exist
1105+
params.behavior = Behavior::NoneExist;
1106+
1107+
auto result = AuditEnsureFilePermissionsCollection(params, indicators, mContext);
1108+
ASSERT_TRUE(result.HasValue());
1109+
ASSERT_EQ(result.Value(), Status::Compliant);
1110+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find("behavior none_exist") != std::string::npos);
1111+
}
1112+
1113+
TEST_F(EnsureFilePermissionsTest, AuditCollectionNoMatchingFilesAllExist)
1114+
{
1115+
CreateFileInDir("file1.log", 0, 0, 0644);
1116+
1117+
EnsureFilePermissionsCollectionParams params;
1118+
params.directory = testDir;
1119+
params.ext = "*.txt";
1120+
params.behavior = Behavior::AllExist;
1121+
1122+
auto result = AuditEnsureFilePermissionsCollection(params, indicators, mContext);
1123+
ASSERT_TRUE(result.HasValue());
1124+
ASSERT_EQ(result.Value(), Status::NonCompliant);
1125+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find("behavior all_exist") != std::string::npos);
1126+
}
1127+
1128+
TEST_F(EnsureFilePermissionsTest, AuditCollectionNoMatchingFilesOnlyOneExists)
1129+
{
1130+
CreateFileInDir("file1.log", 0, 0, 0644);
1131+
1132+
EnsureFilePermissionsCollectionParams params;
1133+
params.directory = testDir;
1134+
params.ext = "*.txt";
1135+
params.behavior = Behavior::OnlyOneExists;
1136+
1137+
auto result = AuditEnsureFilePermissionsCollection(params, indicators, mContext);
1138+
ASSERT_TRUE(result.HasValue());
1139+
ASSERT_EQ(result.Value(), Status::NonCompliant);
1140+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find("behavior only_one_exists") != std::string::npos);
1141+
}
1142+
1143+
TEST_F(EnsureFilePermissionsTest, AuditCollectionNoMatchingFilesAnyExist)
1144+
{
1145+
CreateFileInDir("file1.log", 0, 0, 0644);
1146+
1147+
EnsureFilePermissionsCollectionParams params;
1148+
params.directory = testDir;
1149+
params.ext = "*.txt";
1150+
params.behavior = Behavior::AnyExist;
1151+
1152+
auto result = AuditEnsureFilePermissionsCollection(params, indicators, mContext);
1153+
ASSERT_TRUE(result.HasValue());
1154+
ASSERT_EQ(result.Value(), Status::NonCompliant);
1155+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find("behavior any_exist") != std::string::npos);
1156+
}
1157+
1158+
// ── Collection: AnyExist with matching files ──────────────────────────────────
1159+
1160+
TEST_F(EnsureFilePermissionsTest, AuditCollectionAnyExistAllGood)
1161+
{
1162+
CreateFileInDir("file1.txt", 0, 0, 0644);
1163+
CreateFileInDir("file2.txt", 0, 0, 0644);
1164+
1165+
EnsureFilePermissionsCollectionParams params;
1166+
params.directory = testDir;
1167+
params.ext = "*.txt";
1168+
auto owner = Pattern::Make("root");
1169+
ASSERT_TRUE(owner.HasValue());
1170+
params.owner = {{std::move(owner).Value()}};
1171+
params.permissions = 0644;
1172+
params.behavior = Behavior::AnyExist;
1173+
1174+
auto result = AuditEnsureFilePermissionsCollection(params, indicators, mContext);
1175+
ASSERT_TRUE(result.HasValue());
1176+
ASSERT_EQ(result.Value(), Status::Compliant);
1177+
}
1178+
1179+
TEST_F(EnsureFilePermissionsTest, AuditCollectionAnyExistOneBad)
1180+
{
1181+
CreateFileInDir("file1.txt", 0, 0, 0644); // compliant
1182+
CreateFileInDir("file2.txt", 1, 0, 0644); // wrong owner
1183+
1184+
EnsureFilePermissionsCollectionParams params;
1185+
params.directory = testDir;
1186+
params.ext = "*.txt";
1187+
auto owner = Pattern::Make("root");
1188+
ASSERT_TRUE(owner.HasValue());
1189+
params.owner = {{std::move(owner).Value()}};
1190+
params.permissions = 0644;
1191+
params.behavior = Behavior::AnyExist;
1192+
1193+
auto result = AuditEnsureFilePermissionsCollection(params, indicators, mContext);
1194+
ASSERT_TRUE(result.HasValue());
1195+
ASSERT_EQ(result.Value(), Status::NonCompliant);
1196+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find("owner") != std::string::npos);
1197+
}
1198+
1199+
// ── Collection: missing directory, NoneExist vs AtLeastOneExists ──────────────
1200+
1201+
TEST_F(EnsureFilePermissionsTest, AuditCollectionMissingDirectoryNoneExist)
1202+
{
1203+
EnsureFilePermissionsCollectionParams params;
1204+
params.directory = "/tmp/this_dir_does_not_exist_efp_test_noneexist";
1205+
params.ext = "*.conf";
1206+
params.behavior = Behavior::NoneExist;
1207+
1208+
auto result = AuditEnsureFilePermissionsCollection(params, indicators, mContext);
1209+
ASSERT_TRUE(result.HasValue());
1210+
ASSERT_EQ(result.Value(), Status::Compliant);
1211+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find("behavior none_exist") != std::string::npos);
1212+
}
1213+
1214+
TEST_F(EnsureFilePermissionsTest, AuditCollectionMissingDirectoryAtLeastOneExists)
1215+
{
1216+
EnsureFilePermissionsCollectionParams params;
1217+
params.directory = "/tmp/this_dir_does_not_exist_efp_test_atleastone";
1218+
params.ext = "*.conf";
1219+
params.behavior = Behavior::AtLeastOneExists;
1220+
1221+
auto result = AuditEnsureFilePermissionsCollection(params, indicators, mContext);
1222+
ASSERT_TRUE(result.HasValue());
1223+
ASSERT_EQ(result.Value(), Status::NonCompliant);
1224+
ASSERT_TRUE(mFormatter.Format(indicators).Value().find("behavior at_least_one_exists") != std::string::npos);
1225+
}

0 commit comments

Comments
 (0)