File indexing completed on 2024-09-01 14:31:26
0001 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0002 // SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk> 0003 // SPDX-FileCopyrightText: 2023 Harald Sitter <sitter@kde.org> 0004 0005 #include <QAbstractItemModel> 0006 #include <QDebug> 0007 #include <QMetaEnum> 0008 #include <QTest> 0009 0010 #include <KConfig> 0011 #include <KConfigGroup> 0012 #include <KLocalizedString> 0013 0014 #include <array> 0015 0016 #include "flatpakcommon.h" 0017 #include "flatpakpermission.h" 0018 0019 class FlatpakPermissionModelTest : public QObject 0020 { 0021 Q_OBJECT 0022 private: 0023 /** KConfig comparison with a grain of Flatpak specifics. */ 0024 bool operatorFlatpakConfigEquals(const KConfig &actual, const KConfig &expected) 0025 { 0026 auto actualGroups = actual.groupList(); 0027 actualGroups.sort(); 0028 auto expectedGroups = expected.groupList(); 0029 expectedGroups.sort(); 0030 0031 if (actualGroups != expectedGroups) { 0032 return false; 0033 } 0034 0035 for (const auto &group : std::as_const(actualGroups)) { 0036 const auto actualGroup = actual.group(group); 0037 const auto expectedGroup = expected.group(group); 0038 0039 auto actualKeys = actualGroup.keyList(); 0040 actualKeys.sort(); 0041 auto expectedKeys = expectedGroup.keyList(); 0042 expectedKeys.sort(); 0043 0044 if (actualKeys != expectedKeys) { 0045 return false; 0046 } 0047 0048 for (const auto &key : std::as_const(actualKeys)) { 0049 if (group == QLatin1String(FLATPAK_METADATA_GROUP_CONTEXT)) { 0050 // Treat everything in [Context] as XDG lists 0051 auto actualValues = actualGroup.readXdgListEntry(key); 0052 actualValues.sort(); 0053 auto expectedValues = expectedGroup.readXdgListEntry(key); 0054 expectedValues.sort(); 0055 0056 if (actualValues != expectedValues) { 0057 return false; 0058 } 0059 } else { 0060 auto actualValue = actualGroup.readEntry(key); 0061 auto expectedValue = expectedGroup.readEntry(key); 0062 0063 if (actualValue != expectedValue) { 0064 return false; 0065 } 0066 } 0067 } 0068 } 0069 return true; 0070 } 0071 0072 bool modelContains(const QAbstractItemModel *model, const QVariant &value, int role = Qt::DisplayRole) 0073 { 0074 for (int i = 0; i < model->rowCount(); i++) { 0075 const auto &data = model->data(model->index(i, 0), role); 0076 if (data == value) { 0077 return true; 0078 } 0079 } 0080 return false; 0081 } 0082 0083 QStringList mockMetadataAndOverridesFiles(const QString &flatpakName) const 0084 { 0085 const auto metadata = QFINDTESTDATA(QStringLiteral("fixtures/metadata/%1").arg(flatpakName)); 0086 // Metadata should exist, but overrides file might be created on the fly. 0087 static const auto overridesDirectory = QFINDTESTDATA(QStringLiteral("fixtures/overrides")); 0088 const auto override = QStringLiteral("%1/%2").arg(overridesDirectory, flatpakName); 0089 return {metadata, override}; 0090 } 0091 0092 // These are little helpers to avoid writing out default-constructed flags 0093 // every time. These flags are for pure in-memory configs to avoid any 0094 // possible surprizes from KConfig infrastructure. 0095 0096 static void write(KConfigGroup &group, const QString &key, const QString &value) 0097 { 0098 group.writeEntry(key, value, KConfig::WriteConfigFlags()); 0099 }; 0100 0101 static void write(KConfigGroup &group, const QString &key, const QStringList &values) 0102 { 0103 group.writeXdgListEntry(key, values, KConfig::WriteConfigFlags()); 0104 }; 0105 0106 private Q_SLOTS: 0107 void init() 0108 { 0109 QDir().rmdir(QFINDTESTDATA("fixtures/overrides/")); 0110 } 0111 0112 void testCompareFlatpakConfigsEqual() 0113 { 0114 KConfig configA(QString(), KConfig::SimpleConfig); 0115 KConfig configB(QString(), KConfig::SimpleConfig); 0116 0117 const std::array configs = {&configA, &configB}; 0118 for (const auto &config : configs) { 0119 auto group1 = config->group(QLatin1String(FLATPAK_METADATA_GROUP_ENVIRONMENT)); 0120 auto group2 = config->group(QLatin1String(FLATPAK_METADATA_GROUP_CONTEXT)); 0121 0122 write(group1, QStringLiteral("key1"), QStringLiteral("value1")); 0123 write(group1, QStringLiteral("key2"), QStringLiteral("value2")); 0124 0125 auto values = QStringList{QStringLiteral("itemA"), QStringLiteral("itemB")}; 0126 write(group2, QStringLiteral("key3"), values); 0127 // Reorder list entries 0128 if (config == &configB) { 0129 values = QStringList{QStringLiteral("itemC"), QStringLiteral("itemD")}; 0130 } else { 0131 values = QStringList{QStringLiteral("itemD"), QStringLiteral("itemC")}; 0132 } 0133 write(group2, QStringLiteral("key4"), values); 0134 } 0135 0136 QVERIFY(operatorFlatpakConfigEquals(configA, configB)); 0137 } 0138 0139 void testCompareFlatpakConfigsWhereXDGListsDiffer() 0140 { 0141 KConfig configA(QString(), KConfig::SimpleConfig); 0142 KConfig configB(QString(), KConfig::SimpleConfig); 0143 0144 auto groupA = configA.group(QLatin1String(FLATPAK_METADATA_GROUP_CONTEXT)); 0145 auto groupB = configB.group(QLatin1String(FLATPAK_METADATA_GROUP_CONTEXT)); 0146 0147 QStringList values = QStringList{QStringLiteral("itemA"), QStringLiteral("itemB")}; 0148 write(groupA, QStringLiteral("key4"), values); 0149 values.append(QStringLiteral("itemC")); 0150 write(groupB, QStringLiteral("key4"), values); 0151 0152 QVERIFY(!operatorFlatpakConfigEquals(configA, configB)); 0153 } 0154 0155 void testCompareFlatpakConfigsWhereNumberOfGroupsDiffers() 0156 { 0157 KConfig configA(QString(), KConfig::SimpleConfig); 0158 KConfig configB(QString(), KConfig::SimpleConfig); 0159 0160 const std::array configs = {&configA, &configB}; 0161 for (const auto &config : configs) { 0162 const std::array groupNames = {QLatin1String("G1"), QLatin1String("G2")}; 0163 for (const auto &groupName : groupNames) { 0164 auto group = config->group(groupName); 0165 write(group, QStringLiteral("key1"), QStringLiteral("value1")); 0166 } 0167 } 0168 QVERIFY(operatorFlatpakConfigEquals(configA, configB)); 0169 const auto extraGroupName = QLatin1String("GExtra"); 0170 { 0171 auto groupA3 = configA.group(extraGroupName); 0172 write(groupA3, QStringLiteral("key1"), QStringLiteral("value1")); 0173 } 0174 QVERIFY(!operatorFlatpakConfigEquals(configA, configB)); 0175 configA.deleteGroup(extraGroupName); 0176 QVERIFY(operatorFlatpakConfigEquals(configA, configB)); 0177 { 0178 // Test the other way around too 0179 auto groupB3 = configB.group(extraGroupName); 0180 write(groupB3, QStringLiteral("key1"), QStringLiteral("value1")); 0181 } 0182 QVERIFY(!operatorFlatpakConfigEquals(configA, configB)); 0183 configB.deleteGroup(extraGroupName); 0184 QVERIFY(operatorFlatpakConfigEquals(configA, configB)); 0185 } 0186 0187 void testMergeConfigObjectsWithBareTarget() 0188 { 0189 KConfig target(QString(), KConfig::SimpleConfig); 0190 KConfig source(QString(), KConfig::SimpleConfig); 0191 KConfig expected(QString(), KConfig::SimpleConfig); 0192 0193 for (const auto config : {&source, &expected}) { 0194 auto group = config->group(QLatin1String(FLATPAK_METADATA_GROUP_CONTEXT)); 0195 write(group, QLatin1String(FLATPAK_METADATA_KEY_SHARED), {QStringLiteral("network")}); 0196 write(group, QLatin1String(FLATPAK_METADATA_KEY_SOCKETS), {QStringLiteral("x11"), QStringLiteral("wayland"), QStringLiteral("fallback-x11")}); 0197 write(group, QLatin1String(FLATPAK_METADATA_KEY_DEVICES), {QStringLiteral("dri"), QStringLiteral("kvm")}); 0198 write(group, QLatin1String(FLATPAK_METADATA_KEY_FEATURES), {QStringLiteral("bluetooth"), QStringLiteral("devel")}); 0199 write(group, QLatin1String(FLATPAK_METADATA_KEY_FILESYSTEMS), {QStringLiteral("xdg-download"), QStringLiteral("~/path")}); 0200 0201 for (const auto &groupName : { 0202 QLatin1String(FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY), 0203 QLatin1String(FLATPAK_METADATA_GROUP_SYSTEM_BUS_POLICY), 0204 QLatin1String(FLATPAK_METADATA_GROUP_ENVIRONMENT), 0205 }) { 0206 auto group = config->group(groupName); 0207 write(group, QStringLiteral("abc.def"), QStringLiteral("talk")); 0208 write(group, QStringLiteral("xyz.xyz"), QStringLiteral("see")); 0209 } 0210 } 0211 0212 FlatpakOverrides::merge(target, source); 0213 QVERIFY(operatorFlatpakConfigEquals(target, expected)); 0214 } 0215 0216 void testMergeConfigObjectsNonOverlapping() 0217 { 0218 // In this test case entries are not overlapping, i.e. they are unique to source and target. 0219 0220 KConfig target(QString(), KConfig::SimpleConfig); 0221 KConfig source(QString(), KConfig::SimpleConfig); 0222 KConfig expected(QString(), KConfig::SimpleConfig); 0223 0224 // put some stuff in target, some in source, and both in the expected config. 0225 { 0226 auto group = target.group(QLatin1String(FLATPAK_METADATA_GROUP_CONTEXT)); 0227 write(group, QLatin1String(FLATPAK_METADATA_KEY_SHARED), {QStringLiteral("network")}); 0228 write(group, QLatin1String(FLATPAK_METADATA_KEY_SOCKETS), {QStringLiteral("fallback-x11")}); 0229 write(group, QLatin1String(FLATPAK_METADATA_KEY_DEVICES), {QStringLiteral("dri")}); 0230 write(group, QLatin1String(FLATPAK_METADATA_KEY_FEATURES), {QStringLiteral("devel")}); 0231 write(group, QLatin1String(FLATPAK_METADATA_KEY_FILESYSTEMS), {QStringLiteral("~/path")}); 0232 0233 for (const auto &groupName : { 0234 QLatin1String(FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY), 0235 QLatin1String(FLATPAK_METADATA_GROUP_SYSTEM_BUS_POLICY), 0236 QLatin1String(FLATPAK_METADATA_GROUP_ENVIRONMENT), 0237 }) { 0238 auto group = target.group(groupName); 0239 write(group, QStringLiteral("abc.def"), QStringLiteral("talk")); 0240 } 0241 } 0242 { 0243 auto group = source.group(QLatin1String(FLATPAK_METADATA_GROUP_CONTEXT)); 0244 write(group, QLatin1String(FLATPAK_METADATA_KEY_SHARED), {QStringLiteral("ipc")}); 0245 write(group, QLatin1String(FLATPAK_METADATA_KEY_SOCKETS), {QStringLiteral("x11"), QStringLiteral("wayland")}); 0246 write(group, QLatin1String(FLATPAK_METADATA_KEY_DEVICES), {QStringLiteral("kvm")}); 0247 write(group, QLatin1String(FLATPAK_METADATA_KEY_FEATURES), {QStringLiteral("bluetooth")}); 0248 write(group, QLatin1String(FLATPAK_METADATA_KEY_FILESYSTEMS), {QStringLiteral("xdg-download")}); 0249 0250 for (const auto &groupName : { 0251 QLatin1String(FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY), 0252 QLatin1String(FLATPAK_METADATA_GROUP_SYSTEM_BUS_POLICY), 0253 QLatin1String(FLATPAK_METADATA_GROUP_ENVIRONMENT), 0254 }) { 0255 auto group = source.group(groupName); 0256 write(group, QStringLiteral("xyz.xyz"), QStringLiteral("see")); 0257 } 0258 } 0259 { 0260 auto group = expected.group(QLatin1String(FLATPAK_METADATA_GROUP_CONTEXT)); 0261 write(group, QLatin1String(FLATPAK_METADATA_KEY_SHARED), {QStringLiteral("network"), QStringLiteral("ipc")}); 0262 write(group, QLatin1String(FLATPAK_METADATA_KEY_SOCKETS), {QStringLiteral("x11"), QStringLiteral("wayland"), QStringLiteral("fallback-x11")}); 0263 write(group, QLatin1String(FLATPAK_METADATA_KEY_DEVICES), {QStringLiteral("dri"), QStringLiteral("kvm")}); 0264 write(group, QLatin1String(FLATPAK_METADATA_KEY_FEATURES), {QStringLiteral("bluetooth"), QStringLiteral("devel")}); 0265 write(group, QLatin1String(FLATPAK_METADATA_KEY_FILESYSTEMS), {QStringLiteral("xdg-download"), QStringLiteral("~/path")}); 0266 0267 for (const auto &groupName : { 0268 QLatin1String(FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY), 0269 QLatin1String(FLATPAK_METADATA_GROUP_SYSTEM_BUS_POLICY), 0270 QLatin1String(FLATPAK_METADATA_GROUP_ENVIRONMENT), 0271 }) { 0272 auto group = expected.group(groupName); 0273 write(group, QStringLiteral("abc.def"), QStringLiteral("talk")); 0274 write(group, QStringLiteral("xyz.xyz"), QStringLiteral("see")); 0275 } 0276 } 0277 0278 FlatpakOverrides::merge(target, source); 0279 QVERIFY(operatorFlatpakConfigEquals(target, expected)); 0280 } 0281 0282 void testMergeConfigObjectsOverlapping() 0283 { 0284 // In this test some entries in target are overridden by source. 0285 0286 KConfig target(QString(), KConfig::SimpleConfig); 0287 KConfig source(QString(), KConfig::SimpleConfig); 0288 KConfig expected(QString(), KConfig::SimpleConfig); 0289 0290 { 0291 auto group = target.group(QLatin1String(FLATPAK_METADATA_GROUP_CONTEXT)); 0292 write(group, QLatin1String(FLATPAK_METADATA_KEY_SHARED), {QStringLiteral("!network"), QStringLiteral("ipc")}); 0293 write(group, QLatin1String(FLATPAK_METADATA_KEY_SOCKETS), {QStringLiteral("x11"), QStringLiteral("wayland"), QStringLiteral("fallback-x11")}); 0294 write(group, QLatin1String(FLATPAK_METADATA_KEY_DEVICES), {QStringLiteral("dri"), QStringLiteral("kvm")}); 0295 write(group, QLatin1String(FLATPAK_METADATA_KEY_FEATURES), {QStringLiteral("bluetooth"), QStringLiteral("!devel")}); 0296 write(group, QLatin1String(FLATPAK_METADATA_KEY_FILESYSTEMS), {QStringLiteral("xdg-download"), QStringLiteral("~/path")}); 0297 0298 for (const auto &groupName : { 0299 QLatin1String(FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY), 0300 QLatin1String(FLATPAK_METADATA_GROUP_SYSTEM_BUS_POLICY), 0301 QLatin1String(FLATPAK_METADATA_GROUP_ENVIRONMENT), 0302 }) { 0303 auto group = target.group(groupName); 0304 write(group, QStringLiteral("abc.def"), QStringLiteral("talk")); 0305 write(group, QStringLiteral("xyz.xyz"), QStringLiteral("own")); 0306 } 0307 } 0308 { 0309 auto group = source.group(QLatin1String(FLATPAK_METADATA_GROUP_CONTEXT)); 0310 write(group, QLatin1String(FLATPAK_METADATA_KEY_SHARED), {QStringLiteral("network"), QStringLiteral("!ipc")}); 0311 write(group, QLatin1String(FLATPAK_METADATA_KEY_SOCKETS), {QStringLiteral("!fallback-x11"), QStringLiteral("pulseaudio")}); 0312 write(group, QLatin1String(FLATPAK_METADATA_KEY_DEVICES), {QStringLiteral("!dri")}); 0313 write(group, QLatin1String(FLATPAK_METADATA_KEY_FEATURES), {QStringLiteral("devel")}); 0314 write(group, QLatin1String(FLATPAK_METADATA_KEY_FILESYSTEMS), {QStringLiteral("!xdg-download"), QStringLiteral("host-etc")}); 0315 0316 for (const auto &groupName : { 0317 QLatin1String(FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY), 0318 QLatin1String(FLATPAK_METADATA_GROUP_SYSTEM_BUS_POLICY), 0319 QLatin1String(FLATPAK_METADATA_GROUP_ENVIRONMENT), 0320 }) { 0321 auto group = source.group(groupName); 0322 write(group, QStringLiteral("xyz.xyz"), QStringLiteral("none")); 0323 write(group, QStringLiteral("org.kde.*"), QStringLiteral("see")); 0324 } 0325 } 0326 { 0327 auto group = expected.group(QLatin1String(FLATPAK_METADATA_GROUP_CONTEXT)); 0328 write(group, QLatin1String(FLATPAK_METADATA_KEY_SHARED), {QStringLiteral("network"), QStringLiteral("!ipc")}); 0329 write(group, 0330 QLatin1String(FLATPAK_METADATA_KEY_SOCKETS), 0331 {QStringLiteral("x11"), QStringLiteral("wayland"), QStringLiteral("!fallback-x11"), QStringLiteral("pulseaudio")}); 0332 write(group, QLatin1String(FLATPAK_METADATA_KEY_DEVICES), {QStringLiteral("!dri"), QStringLiteral("kvm")}); 0333 write(group, QLatin1String(FLATPAK_METADATA_KEY_FEATURES), {QStringLiteral("bluetooth"), QStringLiteral("devel")}); 0334 write(group, 0335 QLatin1String(FLATPAK_METADATA_KEY_FILESYSTEMS), 0336 {QStringLiteral("!xdg-download"), QStringLiteral("~/path"), QStringLiteral("host-etc")}); 0337 0338 for (const auto &groupName : { 0339 QLatin1String(FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY), 0340 QLatin1String(FLATPAK_METADATA_GROUP_SYSTEM_BUS_POLICY), 0341 QLatin1String(FLATPAK_METADATA_GROUP_ENVIRONMENT), 0342 }) { 0343 auto group = expected.group(groupName); 0344 write(group, QStringLiteral("abc.def"), QStringLiteral("talk")); 0345 write(group, QStringLiteral("xyz.xyz"), QStringLiteral("none")); 0346 write(group, QStringLiteral("org.kde.*"), QStringLiteral("see")); 0347 } 0348 } 0349 0350 FlatpakOverrides::merge(target, source); 0351 QVERIFY(operatorFlatpakConfigEquals(target, expected)); 0352 } 0353 0354 void testMergeConfigFiles() 0355 { 0356 const QStringList overridesFiles = { 0357 QFINDTESTDATA(QStringLiteral("fixtures/metadata/com.example.cascade.metadata")), 0358 QFINDTESTDATA(QStringLiteral("fixtures/overrides.in/com.example.cascade.system-global")), 0359 QFINDTESTDATA(QStringLiteral("fixtures/overrides.in/com.example.cascade.user-global")), 0360 QFINDTESTDATA(QStringLiteral("fixtures/overrides.in/com.example.cascade.user-app")), 0361 }; 0362 const auto expectedFilepath = QFINDTESTDATA(QStringLiteral("fixtures/overrides.out/com.example.cascade.final")); 0363 0364 const auto actual = FlatpakOverrides::loadAndMerge(overridesFiles); 0365 const KConfig expected(expectedFilepath, KConfig::SimpleConfig); 0366 0367 QVERIFY(operatorFlatpakConfigEquals(*actual, expected)); 0368 } 0369 0370 void testReadMergedMultiLevelOverrides() 0371 { 0372 const QStringList overrideFiles = { 0373 QFINDTESTDATA(QStringLiteral("fixtures/metadata/com.example.cascade.metadata")), 0374 QFINDTESTDATA(QStringLiteral("fixtures/overrides.in/com.example.cascade.system-global")), 0375 QFINDTESTDATA(QStringLiteral("fixtures/overrides.in/com.example.cascade.user-global")), 0376 QFINDTESTDATA(QStringLiteral("fixtures/overrides.in/com.example.cascade.user-app")), 0377 }; 0378 FlatpakPermissionModel model; 0379 FlatpakReferencesModel referencesModel; 0380 FlatpakReference 0381 reference(&referencesModel, "com.example.cascade.metadata", "x86_64", "stable", "1.0.0", "com.example.cascade.metadata", QUrl(), overrideFiles); 0382 model.setReference(&reference); 0383 model.setShowAdvanced(true); 0384 model.load(); 0385 0386 { 0387 const auto index = model.findPermissionIndex(FlatpakPermissionsSectionType::Sockets, QLatin1String("x11")); 0388 QVERIFY(index.isValid()); 0389 QVERIFY(!model.data(index, FlatpakPermissionModel::IsDefaultEnabled).toBool()); 0390 QVERIFY(model.data(index, FlatpakPermissionModel::IsEffectiveEnabled).toBool()); 0391 } 0392 { 0393 const auto index = model.findPermissionIndex(FlatpakPermissionsSectionType::Filesystems, QLatin1String("xdg-pictures")); 0394 QVERIFY(index.isValid()); 0395 QVERIFY(model.data(index, FlatpakPermissionModel::IsDefaultEnabled).toBool()); 0396 QVERIFY(model.data(index, FlatpakPermissionModel::IsEffectiveEnabled).toBool()); 0397 QCOMPARE(model.data(index, FlatpakPermissionModel::DefaultValue).value<FlatpakFilesystemsEntry::AccessMode>(), 0398 FlatpakFilesystemsEntry::AccessMode::ReadOnly); 0399 QCOMPARE(model.data(index, FlatpakPermissionModel::EffectiveValue).value<FlatpakFilesystemsEntry::AccessMode>(), 0400 FlatpakFilesystemsEntry::AccessMode::Create); 0401 } 0402 { 0403 const auto index = model.findPermissionIndex(FlatpakPermissionsSectionType::SystemBus, QLatin1String("com.example.system1")); 0404 QVERIFY(index.isValid()); 0405 QCOMPARE(model.data(index, FlatpakPermissionModel::DefaultValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_TALK); 0406 QCOMPARE(model.data(index, FlatpakPermissionModel::EffectiveValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_SEE); 0407 } 0408 { 0409 const auto index = model.findPermissionIndex(FlatpakPermissionsSectionType::SystemBus, QLatin1String("com.example.system2")); 0410 QVERIFY(index.isValid()); 0411 QVERIFY(!model.data(index, FlatpakPermissionModel::IsDefaultEnabled).toBool()); 0412 QVERIFY(model.data(index, FlatpakPermissionModel::IsEffectiveEnabled).toBool()); 0413 QCOMPARE(model.data(index, FlatpakPermissionModel::DefaultValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_OWN); 0414 QCOMPARE(model.data(index, FlatpakPermissionModel::EffectiveValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_OWN); 0415 } 0416 { 0417 const auto index = model.findPermissionIndex(FlatpakPermissionsSectionType::SessionBus, QLatin1String("com.example.session1")); 0418 QVERIFY(index.isValid()); 0419 QCOMPARE(model.data(index, FlatpakPermissionModel::DefaultValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_TALK); 0420 QCOMPARE(model.data(index, FlatpakPermissionModel::EffectiveValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_NONE); 0421 } 0422 { 0423 const auto index = model.findPermissionIndex(FlatpakPermissionsSectionType::Environment, QLatin1String("EXAMPLE_NAME")); 0424 QVERIFY(index.isValid()); 0425 QCOMPARE(model.data(index, FlatpakPermissionModel::DefaultValue).toString(), QLatin1String("user")); 0426 QCOMPARE(model.data(index, FlatpakPermissionModel::EffectiveValue).toString(), QLatin1String("user-app")); 0427 } 0428 } 0429 0430 void testRead() 0431 { 0432 // The primary motivation behind this test is to make sure that translations aren't being pulled in for the raw names. 0433 FlatpakPermissionModel model; 0434 FlatpakReferencesModel referencesModel; 0435 FlatpakReference reference(&referencesModel, 0436 "com.discordapp.Discord", 0437 "x86_64", 0438 "stable", 0439 "0.0.24", 0440 "Discord", 0441 QUrl(), 0442 mockMetadataAndOverridesFiles("com.discordapp.Discord")); 0443 model.setReference(&reference); 0444 model.load(); 0445 bool containsNetwork = false; 0446 bool containsXdgDownload = false; 0447 for (auto i = 0; i < model.rowCount(); ++i) { 0448 const QString name = model.data(model.index(i, 0), FlatpakPermissionModel::Name).toString(); 0449 if (name == "network") { 0450 containsNetwork = true; 0451 } 0452 0453 if (name == "xdg-download") { 0454 containsXdgDownload = true; 0455 QVERIFY(!model.data(model.index(i, 0), FlatpakPermissionModel::CanBeDisabled).toBool()); 0456 QCOMPARE(model.data(model.index(i, 0), FlatpakPermissionModel::IsEffectiveEnabled), true); 0457 QCOMPARE(model.data(model.index(i, 0), FlatpakPermissionModel::EffectiveValue).value<FlatpakFilesystemsEntry::AccessMode>(), 0458 FlatpakFilesystemsEntry::AccessMode::ReadWrite); 0459 } 0460 } 0461 0462 QVERIFY(containsNetwork); 0463 QVERIFY(containsXdgDownload); 0464 QVERIFY(model.permissionExists(FlatpakPermissionsSectionType::Basic, QLatin1String("network"))); 0465 QVERIFY(!model.permissionExists(FlatpakPermissionsSectionType::Basic, QLatin1String("yolo-foobar"))); 0466 } 0467 0468 void testLoadSameSimpleOverride() 0469 { 0470 // Test that values that are for some reason enabled and present in 0471 // both defaults and overrides are parsed correctly. 0472 FlatpakPermissionModel model; 0473 FlatpakReferencesModel referencesModel; 0474 FlatpakReference reference(&referencesModel, 0475 "com.example.same.override", 0476 "x86_64", 0477 "stable", 0478 "0.0.24", 0479 "Test Same Simple Override", 0480 QUrl(), 0481 mockMetadataAndOverridesFiles("com.example.same.override")); 0482 model.setReference(&reference); 0483 model.setShowAdvanced(true); 0484 model.load(); 0485 0486 QStringList found; 0487 0488 for (auto i = 0; i < model.rowCount(); ++i) { 0489 const auto name = model.data(model.index(i, 0), FlatpakPermissionModel::Name).toString(); 0490 0491 const auto isDefaultEnabled = model.data(model.index(i, 0), FlatpakPermissionModel::IsDefaultEnabled).toBool(); 0492 const auto isEffectiveEnabled = model.data(model.index(i, 0), FlatpakPermissionModel::IsEffectiveEnabled).toBool(); 0493 0494 if (name == QLatin1String("ipc")) { 0495 QVERIFY(isDefaultEnabled); 0496 QVERIFY(isEffectiveEnabled); 0497 } else if (name == QLatin1String("pulseaudio")) { 0498 QVERIFY(isDefaultEnabled); 0499 QVERIFY(isEffectiveEnabled); 0500 } else if (name == QLatin1String("dri")) { 0501 QVERIFY(!isDefaultEnabled); 0502 QVERIFY(!isEffectiveEnabled); 0503 } else if (name == QLatin1String("bluetooth")) { 0504 QVERIFY(!isDefaultEnabled); 0505 QVERIFY(isEffectiveEnabled); 0506 } else if (name == QLatin1String("xdg-download")) { 0507 QVERIFY(isDefaultEnabled); 0508 QVERIFY(isEffectiveEnabled); 0509 } else { 0510 continue; 0511 } 0512 0513 found.append(name); 0514 } 0515 0516 QVERIFY(found.contains(QLatin1String("ipc"))); 0517 QVERIFY(found.contains(QLatin1String("pulseaudio"))); 0518 QVERIFY(found.contains(QLatin1String("dri"))); 0519 QVERIFY(found.contains(QLatin1String("bluetooth"))); 0520 QVERIFY(found.contains(QLatin1String("xdg-download"))); 0521 } 0522 0523 void testDefaultFilesystemsGoFirst() 0524 { 0525 // If there are no custom filesystems specified in defaults, then all custom ones should go below it. 0526 // The Discord test above can't be reused, because it has custom filesystems in base metadata, so 0527 // the well-known "host-etc" filesystem would not be the last one. But we want to test for the last 0528 // default index too. 0529 FlatpakPermissionModel model; 0530 FlatpakReferencesModel referencesModel; 0531 FlatpakReference reference(&referencesModel, // 0532 "org.gnome.dfeet", 0533 "x86_64", 0534 "stable", 0535 "0.3.16", 0536 "D-Feet", 0537 QUrl(), 0538 mockMetadataAndOverridesFiles("org.gnome.dfeet")); 0539 model.setReference(&reference); 0540 model.load(); 0541 QStringList filesystems; 0542 for (auto i = 0; i < model.rowCount(); ++i) { 0543 const QString name = model.data(model.index(i, 0), FlatpakPermissionModel::Name).toString(); 0544 // collect all filesystems 0545 const auto section = model.data(model.index(i, 0), FlatpakPermissionModel::Section).value<FlatpakPermissionsSectionType::Type>(); 0546 if (section == FlatpakPermissionsSectionType::Filesystems) { 0547 filesystems.append(name); 0548 } 0549 } 0550 0551 // Note: update this name when more standard filesystems are added. 0552 const QString hostEtc = QLatin1String("host-etc"); 0553 const auto indexOfHostEtc = filesystems.indexOf(hostEtc); 0554 QCOMPARE(indexOfHostEtc, 3); 0555 // But custom overrides should come after standard ones anyway. 0556 const auto custom = QLatin1String("/custom/path"); 0557 const auto indexOfCustom = filesystems.indexOf(custom); 0558 QVERIFY(indexOfCustom != -1); 0559 QVERIFY(indexOfHostEtc < indexOfCustom); 0560 } 0561 0562 void testDBusNonePolicy() 0563 { 0564 // This test verifies that "none" policy for D-Bus services works just 0565 // like other regular policies. It can be loaded, changed to, changed 0566 // from, and saved. 0567 const auto metadataAndOverridesFiles = mockMetadataAndOverridesFiles("org.gnome.dfeet"); 0568 FlatpakPermissionModel model; 0569 FlatpakReferencesModel referencesModel; 0570 FlatpakReference reference(&referencesModel, // 0571 "org.gnome.dfeet", 0572 "x86_64", 0573 "stable", 0574 "0.3.16", 0575 "D-Feet", 0576 QUrl(), 0577 metadataAndOverridesFiles); 0578 model.setReference(&reference); 0579 model.load(); 0580 model.setShowAdvanced(true); 0581 0582 // This service is set to "none" by default (in metadata). 0583 const auto service0 = QLatin1String("com.example.service0"); 0584 int indexOfService0 = -1; 0585 // This service is set to "none" in override file. 0586 const auto service1 = QLatin1String("com.example.service1"); 0587 int indexOfService1 = -1; 0588 // This service is set to "see" in override, but will be changed to "none". 0589 const auto service2 = QLatin1String("com.example.service2"); 0590 int indexOfService2 = -1; 0591 0592 for (auto i = 0; i < model.rowCount(); ++i) { 0593 const QString name = model.data(model.index(i, 0), FlatpakPermissionModel::Name).toString(); 0594 const auto section = model.data(model.index(i, 0), FlatpakPermissionModel::Section).value<FlatpakPermissionsSectionType::Type>(); 0595 if (section == FlatpakPermissionsSectionType::SessionBus) { 0596 if (name == service0) { 0597 indexOfService0 = i; 0598 } else if (name == service1) { 0599 indexOfService1 = i; 0600 } else if (name == service2) { 0601 indexOfService2 = i; 0602 } 0603 } 0604 } 0605 QVERIFY(indexOfService0 != -1); 0606 QVERIFY(indexOfService1 != -1); 0607 QVERIFY(indexOfService2 != -1); 0608 const auto name0 = model.data(model.index(indexOfService0, 0), FlatpakPermissionModel::EffectiveValue).value<FlatpakPolicy>(); 0609 const auto name1 = model.data(model.index(indexOfService1, 0), FlatpakPermissionModel::EffectiveValue).value<FlatpakPolicy>(); 0610 const auto name2 = model.data(model.index(indexOfService2, 0), FlatpakPermissionModel::EffectiveValue).value<FlatpakPolicy>(); 0611 QCOMPARE(name0, FlatpakPolicy::FLATPAK_POLICY_NONE); 0612 QCOMPARE(name1, FlatpakPolicy::FLATPAK_POLICY_NONE); 0613 QCOMPARE(name2, FlatpakPolicy::FLATPAK_POLICY_SEE); 0614 QVERIFY(model.data(model.index(indexOfService0, 0), FlatpakPermissionModel::IsDefaultEnabled).toBool()); 0615 QVERIFY(!model.data(model.index(indexOfService1, 0), FlatpakPermissionModel::IsDefaultEnabled).toBool()); 0616 QVERIFY(!model.data(model.index(indexOfService2, 0), FlatpakPermissionModel::IsDefaultEnabled).toBool()); 0617 QVERIFY(!model.data(model.index(indexOfService0, 0), FlatpakPermissionModel::CanBeDisabled).toBool()); 0618 QVERIFY(model.data(model.index(indexOfService1, 0), FlatpakPermissionModel::CanBeDisabled).toBool()); 0619 QVERIFY(model.data(model.index(indexOfService2, 0), FlatpakPermissionModel::CanBeDisabled).toBool()); 0620 0621 const auto setAndCheckBus = [&](const QString &value, FlatpakPolicy newPolicy) { 0622 model.setPermissionValueAtRow(indexOfService2, newPolicy); 0623 const auto name2i18nValue = model.data(model.index(indexOfService2, 0), FlatpakPermissionModel::EffectiveValue).value<FlatpakPolicy>(); 0624 QCOMPARE(name2i18nValue, newPolicy); 0625 0626 QVERIFY(model.isSaveNeeded()); 0627 model.save(); 0628 0629 const KConfig expectedDesktopFile(metadataAndOverridesFiles.last()); 0630 const auto group = expectedDesktopFile.group(QLatin1String(FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY)); 0631 const auto name2value = group.readEntry(service2); 0632 QCOMPARE(name2value, value); 0633 }; 0634 0635 setAndCheckBus(QLatin1String("none"), FlatpakPolicy::FLATPAK_POLICY_NONE); 0636 setAndCheckBus(QLatin1String("see"), FlatpakPolicy::FLATPAK_POLICY_SEE); 0637 setAndCheckBus(QLatin1String("talk"), FlatpakPolicy::FLATPAK_POLICY_TALK); 0638 setAndCheckBus(QLatin1String("own"), FlatpakPolicy::FLATPAK_POLICY_OWN); 0639 0640 const auto checkPossibleValues = [&](int row) { 0641 const auto values = model.data(model.index(row, 0), FlatpakPermissionModel::ValuesModel).value<QAbstractListModel *>(); 0642 QVERIFY(modelContains(values, i18n("None"))); 0643 QVERIFY(modelContains(values, i18n("see"))); 0644 QVERIFY(modelContains(values, i18n("talk"))); 0645 QVERIFY(modelContains(values, i18n("own"))); 0646 }; 0647 checkPossibleValues(indexOfService0); 0648 checkPossibleValues(indexOfService1); 0649 checkPossibleValues(indexOfService2); 0650 0651 const auto isEffectiveEnabled = [&](int row) -> bool { 0652 return model.data(model.index(row, 0), FlatpakPermissionModel::IsEffectiveEnabled).toBool(); 0653 }; 0654 QVERIFY(isEffectiveEnabled(indexOfService0)); 0655 QVERIFY(isEffectiveEnabled(indexOfService1)); 0656 QVERIFY(isEffectiveEnabled(indexOfService2)); 0657 0658 // Toggling non-default bus entry should disable it (i.e. mark for deletion) 0659 model.togglePermissionAtRow(indexOfService2); 0660 QVERIFY(!isEffectiveEnabled(indexOfService2)); 0661 // Reloading data should re-enable it again. 0662 model.load(); 0663 QVERIFY(isEffectiveEnabled(indexOfService2)); 0664 // Disabling non-default bus entry and saving it should remove it from override file. 0665 model.togglePermissionAtRow(indexOfService2); 0666 QVERIFY(!isEffectiveEnabled(indexOfService2)); 0667 model.save(); 0668 { 0669 const KConfig expectedDesktopFile(metadataAndOverridesFiles.last()); 0670 const auto group = expectedDesktopFile.group(QLatin1String(FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY)); 0671 QVERIFY(!group.hasKey(service2)); 0672 } 0673 // Re-enabling non-default bus entry and saving it should add it back to override file. 0674 model.togglePermissionAtRow(indexOfService2); 0675 QVERIFY(isEffectiveEnabled(indexOfService2)); 0676 model.save(); 0677 { 0678 const KConfig expectedDesktopFile(metadataAndOverridesFiles.last()); 0679 const auto group = expectedDesktopFile.group(QLatin1String(FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY)); 0680 QVERIFY(group.hasKey(service2)); 0681 } 0682 } 0683 0684 void testDBusBrokenPolicies() 0685 { 0686 FlatpakPermissionModel model; 0687 FlatpakReferencesModel referencesModel; 0688 FlatpakReference reference(&referencesModel, // 0689 "org.gnome.Boxes", 0690 "x86_64", 0691 "stable", 0692 "43.1", 0693 "Boxes", 0694 QUrl(), 0695 mockMetadataAndOverridesFiles("org.gnome.Boxes")); 0696 model.setReference(&reference); 0697 model.load(); 0698 model.setShowAdvanced(true); 0699 0700 // This service is set to "hello" by default (in metadata). 0701 const auto session0 = QLatin1String("org.freedesktop.secrets"); 0702 int indexOfSession0 = -1; 0703 // This service is set to "talk" by default (in metadata) but overriden with an invalid policy string. 0704 const auto session1 = QLatin1String("ca.desrt.dconf"); 0705 int indexOfSession1 = -1; 0706 // This service is set to an invalid policy string by default (in metadata) but overridden with "see". 0707 const auto system = QLatin1String("org.freedesktop.timedate1"); 0708 int indexOfSystem = -1; 0709 0710 for (auto i = 0; i < model.rowCount(); ++i) { 0711 const auto name = model.data(model.index(i, 0), FlatpakPermissionModel::Name).toString(); 0712 const auto section = model.data(model.index(i, 0), FlatpakPermissionModel::Section).value<FlatpakPermissionsSectionType::Type>(); 0713 if (section == FlatpakPermissionsSectionType::SessionBus) { 0714 if (name == session0) { 0715 indexOfSession0 = i; 0716 } else if (name == session1) { 0717 indexOfSession1 = i; 0718 } 0719 } else if (section == FlatpakPermissionsSectionType::SystemBus) { 0720 if (name == system) { 0721 indexOfSystem = i; 0722 } 0723 } 0724 } 0725 QVERIFY(indexOfSession0 != -1); 0726 QVERIFY(indexOfSession1 != -1); 0727 QVERIFY(indexOfSystem != -1); 0728 0729 QVERIFY(model.data(model.index(indexOfSession0, 0), FlatpakPermissionModel::IsDefaultEnabled).toBool()); 0730 QCOMPARE(model.data(model.index(indexOfSession0, 0), FlatpakPermissionModel::DefaultValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_NONE); 0731 QCOMPARE(model.data(model.index(indexOfSession0, 0), FlatpakPermissionModel::EffectiveValue).value<FlatpakPolicy>(), 0732 FlatpakPolicy::FLATPAK_POLICY_NONE); 0733 0734 QVERIFY(model.data(model.index(indexOfSession1, 0), FlatpakPermissionModel::IsDefaultEnabled).toBool()); 0735 QVERIFY(model.data(model.index(indexOfSession1, 0), FlatpakPermissionModel::IsEffectiveEnabled).toBool()); 0736 QCOMPARE(model.data(model.index(indexOfSession1, 0), FlatpakPermissionModel::DefaultValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_TALK); 0737 QCOMPARE(model.data(model.index(indexOfSession1, 0), FlatpakPermissionModel::EffectiveValue).value<FlatpakPolicy>(), 0738 FlatpakPolicy::FLATPAK_POLICY_NONE); 0739 0740 QVERIFY(model.data(model.index(indexOfSystem, 0), FlatpakPermissionModel::IsDefaultEnabled).toBool()); 0741 QVERIFY(model.data(model.index(indexOfSystem, 0), FlatpakPermissionModel::IsEffectiveEnabled).toBool()); 0742 QCOMPARE(model.data(model.index(indexOfSystem, 0), FlatpakPermissionModel::DefaultValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_NONE); 0743 QCOMPARE(model.data(model.index(indexOfSystem, 0), FlatpakPermissionModel::EffectiveValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_SEE); 0744 } 0745 0746 void testMutable() 0747 { 0748 // Ensure override files mutate properly 0749 const auto metadataAndOverridesFiles = mockMetadataAndOverridesFiles("com.discordapp.Discord"); 0750 FlatpakPermissionModel model; 0751 FlatpakReferencesModel referencesModel; 0752 FlatpakReference reference(&referencesModel, // 0753 "com.discordapp.Discord", 0754 "x86_64", 0755 "stable", 0756 "0.0.24", 0757 "Discord", 0758 QUrl(), 0759 metadataAndOverridesFiles); 0760 model.setReference(&reference); 0761 model.load(); 0762 model.setShowAdvanced(true); 0763 0764 const auto filesystem = QLatin1String("~/path"); 0765 const auto session = QLatin1String("com.example.session"); 0766 const auto system = QLatin1String("com.example.system"); 0767 const auto envName = QLatin1String("SOME_ENV"); 0768 const auto envValue = QLatin1String("abc123"); 0769 0770 model.addUserEnteredPermission(FlatpakPermissionsSectionType::Filesystems, 0771 filesystem, 0772 QVariant::fromValue(FlatpakFilesystemsEntry::AccessMode::Create)); 0773 model.addUserEnteredPermission(FlatpakPermissionsSectionType::SessionBus, session, FlatpakPolicy::FLATPAK_POLICY_TALK); 0774 // Try int cast to make sure QML/JS works fine too. 0775 model.addUserEnteredPermission(FlatpakPermissionsSectionType::SystemBus, system, FlatpakPolicy::FLATPAK_POLICY_SEE); 0776 model.addUserEnteredPermission(FlatpakPermissionsSectionType::Environment, envName, envValue); 0777 0778 for (auto i = 0; i < model.rowCount(); ++i) { 0779 const QString name = model.data(model.index(i, 0), FlatpakPermissionModel::Name).toString(); 0780 if (name == "host") { 0781 const auto metaEnum = QMetaEnum::fromType<FlatpakPermissionModel::Roles>(); 0782 for (auto j = 0; j < metaEnum.keyCount(); ++j) { // purely for debugging purposes 0783 qDebug() << metaEnum.key(j) << model.data(model.index(i, 0), metaEnum.value(j)); 0784 } 0785 0786 QCOMPARE(model.data(model.index(i, 0), FlatpakPermissionModel::IsEffectiveEnabled), false); 0787 QVERIFY(model.data(model.index(i, 0), FlatpakPermissionModel::CanBeDisabled).toBool()); 0788 model.togglePermissionAtRow(i); 0789 QCOMPARE(model.data(model.index(i, 0), FlatpakPermissionModel::IsEffectiveEnabled), true); 0790 } 0791 0792 if (name == "org.kde.StatusNotifierWatcher") { 0793 model.setPermissionValueAtRow(i, FlatpakPolicy::FLATPAK_POLICY_OWN); 0794 } 0795 0796 if (name == "host-os") { 0797 // Make sure the config manipulation works across multiple changes 0798 model.setPermissionValueAtRow(i, QVariant::fromValue(FlatpakFilesystemsEntry::AccessMode::ReadOnly)); 0799 model.setPermissionValueAtRow(i, QVariant::fromValue(FlatpakFilesystemsEntry::AccessMode::ReadWrite)); 0800 model.setPermissionValueAtRow(i, QVariant::fromValue(FlatpakFilesystemsEntry::AccessMode::Create)); 0801 model.setPermissionValueAtRow(i, QVariant::fromValue(FlatpakFilesystemsEntry::AccessMode::ReadOnly)); 0802 } 0803 0804 if (name == filesystem) { 0805 QVERIFY(model.data(model.index(i, 0), FlatpakPermissionModel::CanBeDisabled).toBool()); 0806 QVERIFY(!model.data(model.index(i, 0), FlatpakPermissionModel::IsDefaultEnabled).toBool()); 0807 QVERIFY(model.data(model.index(i, 0), FlatpakPermissionModel::IsEffectiveEnabled).toBool()); 0808 QCOMPARE(model.data(model.index(i, 0), FlatpakPermissionModel::DefaultValue).value<FlatpakFilesystemsEntry::AccessMode>(), 0809 FlatpakFilesystemsEntry::AccessMode::Create); 0810 QCOMPARE(model.data(model.index(i, 0), FlatpakPermissionModel::EffectiveValue).value<FlatpakFilesystemsEntry::AccessMode>(), 0811 FlatpakFilesystemsEntry::AccessMode::Create); 0812 } 0813 0814 if (name == session) { 0815 QVERIFY(model.data(model.index(i, 0), FlatpakPermissionModel::CanBeDisabled).toBool()); 0816 QVERIFY(!model.data(model.index(i, 0), FlatpakPermissionModel::IsDefaultEnabled).toBool()); 0817 QVERIFY(model.data(model.index(i, 0), FlatpakPermissionModel::IsEffectiveEnabled).toBool()); 0818 QCOMPARE(model.data(model.index(i, 0), FlatpakPermissionModel::DefaultValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_TALK); 0819 QCOMPARE(model.data(model.index(i, 0), FlatpakPermissionModel::EffectiveValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_TALK); 0820 } 0821 0822 if (name == system) { 0823 QVERIFY(model.data(model.index(i, 0), FlatpakPermissionModel::CanBeDisabled).toBool()); 0824 QVERIFY(!model.data(model.index(i, 0), FlatpakPermissionModel::IsDefaultEnabled).toBool()); 0825 QVERIFY(model.data(model.index(i, 0), FlatpakPermissionModel::IsEffectiveEnabled).toBool()); 0826 QCOMPARE(model.data(model.index(i, 0), FlatpakPermissionModel::DefaultValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_SEE); 0827 QCOMPARE(model.data(model.index(i, 0), FlatpakPermissionModel::EffectiveValue).value<FlatpakPolicy>(), FlatpakPolicy::FLATPAK_POLICY_SEE); 0828 } 0829 0830 if (name == envName) { 0831 QVERIFY(model.data(model.index(i, 0), FlatpakPermissionModel::CanBeDisabled).toBool()); 0832 QVERIFY(!model.data(model.index(i, 0), FlatpakPermissionModel::IsDefaultEnabled).toBool()); 0833 QVERIFY(model.data(model.index(i, 0), FlatpakPermissionModel::IsEffectiveEnabled).toBool()); 0834 QCOMPARE(model.data(model.index(i, 0), FlatpakPermissionModel::DefaultValue).toString(), envValue); 0835 QCOMPARE(model.data(model.index(i, 0), FlatpakPermissionModel::EffectiveValue).toString(), envValue); 0836 } 0837 } 0838 model.save(); 0839 const KConfig actual(metadataAndOverridesFiles.last()); 0840 const KConfig expected(QFINDTESTDATA("fixtures/overrides.out/com.discordapp.Discord")); 0841 QVERIFY(operatorFlatpakConfigEquals(actual, expected)); 0842 } 0843 0844 void testValuesModelForSectionsWithoutModels() 0845 { 0846 const auto values = FlatpakPermissionModel::valuesModelForSectionType(FlatpakPermissionsSectionType::Features); 0847 QCOMPARE(values, nullptr); 0848 } 0849 0850 void testValuesModelForFilesystemsSection() 0851 { 0852 const auto values = FlatpakPermissionModel::valuesModelForFilesystemsSection(); 0853 QCOMPARE(values->rowCount(QModelIndex()), 4); 0854 QVERIFY(modelContains(values, i18n("OFF"))); // Filesystems logic is not ready to use this value yet. 0855 QVERIFY(modelContains(values, i18n("read/write"))); 0856 QVERIFY(modelContains(values, i18n("read-only"))); 0857 QVERIFY(modelContains(values, i18n("create"))); 0858 } 0859 0860 void testValuesModelForBusSections() 0861 { 0862 const auto values = FlatpakPermissionModel::valuesModelForBusSections(); 0863 QCOMPARE(values->rowCount(QModelIndex()), 4); 0864 QVERIFY(modelContains(values, i18n("None"))); 0865 QVERIFY(modelContains(values, i18n("talk"))); 0866 QVERIFY(modelContains(values, i18n("own"))); 0867 QVERIFY(modelContains(values, i18n("see"))); 0868 } 0869 0870 void testValuesModelMapping() 0871 { 0872 auto expected = FlatpakPermissionModel::valuesModelForFilesystemsSection(); 0873 auto actual = FlatpakPermissionModel::valuesModelForSectionType(FlatpakPermissionsSectionType::Filesystems); 0874 QCOMPARE(actual, expected); 0875 0876 expected = FlatpakPermissionModel::valuesModelForBusSections(); 0877 actual = FlatpakPermissionModel::valuesModelForSectionType(FlatpakPermissionsSectionType::SessionBus); 0878 QCOMPARE(actual, expected); 0879 0880 actual = FlatpakPermissionModel::valuesModelForSectionType(FlatpakPermissionsSectionType::SystemBus); 0881 QCOMPARE(actual, expected); 0882 } 0883 0884 void testUnparsableFilesystems() 0885 { 0886 const auto metadataAndOverridesFiles = mockMetadataAndOverridesFiles("com.example.unparsable.filesystems"); 0887 FlatpakPermissionModel model; 0888 FlatpakReferencesModel referencesModel; 0889 FlatpakReference reference(&referencesModel, 0890 "com.example.unparsable.filesystems", 0891 "x86_64", 0892 "stable", 0893 "0.0.24", 0894 "Unparsable Filesystems", 0895 QUrl(), 0896 metadataAndOverridesFiles); 0897 model.setReference(&reference); 0898 model.load(); 0899 model.setShowAdvanced(true); 0900 0901 const auto filesystem = QLatin1String("xdg-data/path"); 0902 model.addUserEnteredPermission(FlatpakPermissionsSectionType::Filesystems, 0903 filesystem, 0904 QVariant::fromValue(FlatpakFilesystemsEntry::AccessMode::ReadOnly)); 0905 model.save(); 0906 0907 const KConfig actual(metadataAndOverridesFiles.last()); 0908 const KConfig expected(QFINDTESTDATA("fixtures/overrides.out/com.example.unparsable.filesystems")); 0909 QVERIFY(operatorFlatpakConfigEquals(actual, expected)); 0910 } 0911 0912 void testDefaultHomeFilesystem() 0913 { 0914 FlatpakReferencesModel referencesModel; 0915 FlatpakReference reference(&referencesModel, 0916 "com.example.home.filesystems", 0917 "x86_64", 0918 "stable", 0919 "0.0.24", 0920 "Default Home Filesystems", 0921 QUrl(), 0922 mockMetadataAndOverridesFiles("com.example.home.filesystems")); 0923 FlatpakPermissionModel model; 0924 model.setReference(&reference); 0925 model.load(); 0926 0927 int dConfIndex = -1; 0928 int homeIndex = -1; 0929 0930 for (int i = 0; i < model.rowCount(); i++) { 0931 const auto section = model.data(model.index(i), FlatpakPermissionModel::Section).value<FlatpakPermissionsSectionType::Type>(); 0932 const auto name = model.data(model.index(i), FlatpakPermissionModel::Name).toString(); 0933 0934 if (section == FlatpakPermissionsSectionType::Filesystems) { 0935 const auto value = model.data(model.index(i), FlatpakPermissionModel::DefaultValue).value<FlatpakFilesystemsEntry::AccessMode>(); 0936 0937 if (name.contains(QLatin1String("dconf"))) { 0938 dConfIndex = i; 0939 QCOMPARE(value, FlatpakFilesystemsEntry::AccessMode::ReadWrite); 0940 } else if (name == QLatin1String("home")) { 0941 homeIndex = i; 0942 QCOMPARE(value, FlatpakFilesystemsEntry::AccessMode::ReadOnly); 0943 } 0944 } 0945 } 0946 0947 QVERIFY(dConfIndex != -1); 0948 QVERIFY(homeIndex != -1); 0949 } 0950 0951 void testValidNames() 0952 { 0953 FlatpakPermissionModel model; 0954 FlatpakReferencesModel referencesModel; 0955 FlatpakReference reference(&referencesModel, 0956 "com.example.valid.names", 0957 "x86_64", 0958 "stable", 0959 "1.0", 0960 "Valid Names", 0961 QUrl(), 0962 mockMetadataAndOverridesFiles("com.example.valid.names")); 0963 model.setReference(&reference); 0964 model.load(); 0965 model.setShowAdvanced(true); 0966 0967 QVERIFY(!model.isFilesystemNameValid(QString())); 0968 QVERIFY(model.permissionExists(FlatpakPermissionsSectionType::Filesystems, QLatin1String("~/path"))); 0969 QVERIFY(model.isFilesystemNameValid(QLatin1String("~/valid/path"))); 0970 QVERIFY(model.isFilesystemNameValid(QLatin1String("~/other"))); 0971 0972 QVERIFY(!model.isDBusServiceNameValid(QString())); 0973 QVERIFY(!model.isDBusServiceNameValid(QLatin1String("com"))); 0974 QVERIFY(!model.isDBusServiceNameValid(QLatin1String("#$%"))); 0975 QVERIFY(model.permissionExists(FlatpakPermissionsSectionType::SessionBus, QLatin1String("com.example.session"))); 0976 QVERIFY(model.permissionExists(FlatpakPermissionsSectionType::SystemBus, QLatin1String("com.example.system"))); 0977 QVERIFY(model.isDBusServiceNameValid(QLatin1String("com.example.session"))); 0978 QVERIFY(model.isDBusServiceNameValid(QLatin1String("com.example.system"))); 0979 QVERIFY(model.isDBusServiceNameValid(QLatin1String("com.example.session2"))); 0980 QVERIFY(model.isDBusServiceNameValid(QLatin1String("com.example.*"))); 0981 QVERIFY(!model.isDBusServiceNameValid(QLatin1String("com.example."))); 0982 0983 QVERIFY(!model.isEnvironmentVariableNameValid(QString())); 0984 QVERIFY(!model.isEnvironmentVariableNameValid(QLatin1String("ABC=DEF"))); 0985 QVERIFY(model.permissionExists(FlatpakPermissionsSectionType::Environment, QLatin1String("EXAMPLE_NAME"))); 0986 QVERIFY(model.isEnvironmentVariableNameValid(QLatin1String("EXAMPLE_NAME"))); 0987 QVERIFY(model.isEnvironmentVariableNameValid(QLatin1String("whatever"))); 0988 } 0989 }; 0990 0991 QTEST_MAIN(FlatpakPermissionModelTest) 0992 0993 #include "flatpakpermissiontest.moc"