Merge lp:~dbarth/trust-store/cleaner into lp:trust-store

Proposed by David Barth
Status: Needs review
Proposed branch: lp:~dbarth/trust-store/cleaner
Merge into: lp:trust-store
Diff against target: 588 lines (+414/-4)
12 files modified
include/core/trust/store.h (+9/-0)
src/CMakeLists.txt (+31/-0)
src/core/trust/cleaner.cpp (+84/-0)
src/core/trust/cleaner.h (+74/-0)
src/core/trust/cleaner_main.cpp (+26/-0)
src/core/trust/impl/sqlite3/store.cpp (+29/-3)
src/core/trust/impl/sqlite3/store.h (+1/-1)
src/core/trust/resolve.cpp (+6/-0)
tests/CMakeLists.txt (+18/-0)
tests/cleaner_test.cpp (+129/-0)
tests/mock_store.h (+2/-0)
tests/test_data.h.in (+5/-0)
To merge this branch: bzr merge lp:~dbarth/trust-store/cleaner
Reviewer Review Type Date Requested Status
Alexandre Abreu (community) Disapprove
PS Jenkins bot continuous-integration Pending
Review via email: mp+299294@code.launchpad.net

Commit message

Provide a new command line tool to clean the trust dbs of entries related to a particular app. Use when an application is being uninstalled.

Description of the change

Provide a new command line tool to clean the trust dbs of entries related to a particular app. Use when an application is being uninstalled.

To post a comment you must log in.
lp:~dbarth/trust-store/cleaner updated
161. By David Barth

define extra PurgeableStore class to preserve the vtable ABI, as suggested by tvoss; switch to using it

Revision history for this message
David Barth (dbarth) wrote :

I updated the branch with the PurgeableStore suggestion, but got straight to calling the sqlite impl class; i would have preferred to dynamic_cast instead, but my c++11 is not so great :/

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :
review: Disapprove

Unmerged revisions

161. By David Barth

define extra PurgeableStore class to preserve the vtable ABI, as suggested by tvoss; switch to using it

160. By David Barth

provide trust-store-cleaner cli tool; add unit tests for the new command

159. By David Barth

wip

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/core/trust/store.h'
2--- include/core/trust/store.h 2014-07-23 13:55:07 +0000
3+++ include/core/trust/store.h 2016-07-06 16:22:59 +0000
4@@ -203,6 +203,15 @@
5 };
6 };
7
8+class PurgeableStore : public trust::Store
9+{
10+public:
11+ /** @brief purge the store from any reference to the given application
12+ * When this function returns true, the request has been persisted by the implementation.
13+ */
14+ virtual void purge(const std::string& id) = 0;
15+};
16+
17 /**
18 * @brief Creates an instance for the default store implementation.
19 * @throw Error::ServiceNameMustNotBeEmpty.
20
21=== modified file 'src/CMakeLists.txt'
22--- src/CMakeLists.txt 2016-01-11 09:51:51 +0000
23+++ src/CMakeLists.txt 2016-07-06 16:22:59 +0000
24@@ -192,6 +192,19 @@
25 core/trust/preseed_main.cpp
26 )
27
28+add_library(
29+ trust-store-cleaner-helper
30+
31+ core/trust/cleaner.h
32+ core/trust/cleaner.cpp
33+)
34+
35+add_executable(
36+ trust-store-cleaner
37+
38+ core/trust/cleaner_main.cpp
39+)
40+
41 target_link_libraries(
42 trust-store
43
44@@ -242,6 +255,19 @@
45 trust-store-preseed-helper
46 )
47
48+target_link_libraries(
49+ trust-store-cleaner-helper
50+
51+ trust-store
52+)
53+
54+target_link_libraries(
55+ trust-store-cleaner
56+
57+ trust-store-cleaner-helper
58+)
59+
60+
61 # We compile with all symbols visible by default. For the shipping library, we strip
62 # out all symbols that are not in core::trust::*
63 set(symbol_map "${CMAKE_SOURCE_DIR}/symbols.map")
64@@ -277,3 +303,8 @@
65 TARGETS trust-store-preseed
66 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
67 )
68+
69+install(
70+ TARGETS trust-store-cleaner
71+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
72+)
73
74=== added file 'src/core/trust/cleaner.cpp'
75--- src/core/trust/cleaner.cpp 1970-01-01 00:00:00 +0000
76+++ src/core/trust/cleaner.cpp 2016-07-06 16:22:59 +0000
77@@ -0,0 +1,84 @@
78+/*
79+ * Copyright © 2016 Canonical Ltd.
80+ *
81+ * This program is free software: you can redistribute it and/or modify it
82+ * under the terms of the GNU Lesser General Public License version 3,
83+ * as published by the Free Software Foundation.
84+ *
85+ * This program is distributed in the hope that it will be useful,
86+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
87+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
88+ * GNU Lesser General Public License for more details.
89+ *
90+ * You should have received a copy of the GNU Lesser General Public License
91+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
92+ *
93+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
94+ * David Barth <david.barth@canonical.com>
95+ */
96+
97+#include <xdg.h>
98+
99+#include <core/trust/cleaner.h>
100+
101+#include <core/trust/impl/sqlite3/store.h>
102+
103+#include <boost/program_options.hpp>
104+
105+#include <istream>
106+
107+namespace Options = boost::program_options;
108+
109+std::istream& operator>>(std::istream& in, core::trust::Feature& f)
110+{
111+ return in >> f.value;
112+}
113+
114+core::trust::Cleaner::Configuration core::trust::Cleaner::Configuration::parse_from_command_line(int argc, const char** argv)
115+{
116+ Options::variables_map vm;
117+
118+ Options::options_description options{"Known options"};
119+ options.add_options()
120+ (Parameters::ForService::name, Options::value<std::string>()->required(), Parameters::ForService::description)
121+ (Parameters::PurgeRequest::name, Options::value<std::vector<std::string>>()->composing(), Parameters::PurgeRequest::description);
122+
123+ Options::command_line_parser parser
124+ {
125+ argc,
126+ argv
127+ };
128+
129+ auto parsed_options = parser.options(options).allow_unregistered().run();
130+ Options::store(parsed_options, vm);
131+ Options::notify(vm);
132+
133+ auto service_name = vm[Parameters::ForService::name].as<std::string>();
134+ auto requests = vm[Parameters::PurgeRequest::name].as<std::vector<std::string>>();
135+
136+ core::trust::Cleaner::Configuration config
137+ {
138+ core::trust::impl::sqlite::create_for_service(service_name, *xdg::BaseDirSpecification::create()),
139+ {} // The empty set.
140+ };
141+
142+ for (const auto& request : requests)
143+ {
144+ std::stringstream ss{request}; core::trust::Request r;
145+
146+ // Parse the request.
147+ ss >> r.from >> r.feature;
148+
149+ config.purge_requests.push_back(r);
150+ }
151+
152+ return config;
153+}
154+
155+core::posix::exit::Status core::trust::Cleaner::main(const core::trust::Cleaner::Configuration& configuration)
156+{
157+ for (const auto& r : configuration.purge_requests)
158+ configuration.store->purge(r.from);
159+
160+ return core::posix::exit::Status::success;
161+}
162
163=== added file 'src/core/trust/cleaner.h'
164--- src/core/trust/cleaner.h 1970-01-01 00:00:00 +0000
165+++ src/core/trust/cleaner.h 2016-07-06 16:22:59 +0000
166@@ -0,0 +1,74 @@
167+/*
168+ * Copyright © 2016 Canonical Ltd.
169+ *
170+ * This program is free software: you can redistribute it and/or modify it
171+ * under the terms of the GNU Lesser General Public License version 3,
172+ * as published by the Free Software Foundation.
173+ *
174+ * This program is distributed in the hope that it will be useful,
175+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
176+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
177+ * GNU Lesser General Public License for more details.
178+ *
179+ * You should have received a copy of the GNU Lesser General Public License
180+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
181+ *
182+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
183+ * David Barth <david.barth@canonical.com>
184+ */
185+
186+#ifndef CORE_TRUST_CLEANER_H_
187+#define CORE_TRUST_CLEANER_H_
188+
189+#include <core/trust/store.h>
190+
191+#include <core/posix/exit.h>
192+
193+#include <vector>
194+
195+namespace core
196+{
197+namespace trust
198+{
199+// A helper to clean trust caches of authorizations for applications being uninstalled
200+// Invoke with:
201+// <helper>
202+// --for-service MyServiceName
203+// --purge "id.of.app.being.removed"
204+struct Cleaner
205+{
206+ // Command-line parameters, their name and their description
207+ struct Parameters
208+ {
209+ Parameters() = delete;
210+
211+ struct ForService
212+ {
213+ static constexpr const char* name{"for-service"};
214+ static constexpr const char* description{"The name of the service to handle trust for."};
215+ };
216+
217+ struct PurgeRequest
218+ {
219+ static constexpr const char* name{"purge"};
220+ static constexpr const char* description{"App ID which authorizations need be removed from the trust store. Can be specified multiple times."};
221+ };
222+ };
223+
224+ // Parameters for execution of the preseed executable.
225+ struct Configuration
226+ {
227+ // Parses command line args and produces a configuration
228+ static Configuration parse_from_command_line(int argc, const char** argv);
229+ // The store that should be purged of entries for an application
230+ std::shared_ptr<core::trust::PurgeableStore> store;
231+ // The set of requests for cleaning that should be applied to the store.
232+ std::vector<core::trust::Request> purge_requests;
233+ };
234+
235+ static core::posix::exit::Status main(const Configuration& configuration);
236+};
237+}
238+}
239+
240+#endif // CORE_TRUST_CLEANER_H_
241
242=== added file 'src/core/trust/cleaner_main.cpp'
243--- src/core/trust/cleaner_main.cpp 1970-01-01 00:00:00 +0000
244+++ src/core/trust/cleaner_main.cpp 2016-07-06 16:22:59 +0000
245@@ -0,0 +1,26 @@
246+/*
247+ * Copyright © 2014 Canonical Ltd.
248+ *
249+ * This program is free software: you can redistribute it and/or modify it
250+ * under the terms of the GNU Lesser General Public License version 3,
251+ * as published by the Free Software Foundation.
252+ *
253+ * This program is distributed in the hope that it will be useful,
254+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
255+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
256+ * GNU Lesser General Public License for more details.
257+ *
258+ * You should have received a copy of the GNU Lesser General Public License
259+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
260+ *
261+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
262+ */
263+
264+#include <core/trust/cleaner.h>
265+
266+int main(int argc, const char** argv)
267+{
268+ auto result = core::trust::Cleaner::main(core::trust::Cleaner::Configuration::parse_from_command_line(argc, argv));
269+
270+ return result == core::posix::exit::Status::success ? EXIT_SUCCESS : EXIT_FAILURE;
271+}
272
273=== modified file 'src/core/trust/impl/sqlite3/store.cpp'
274--- src/core/trust/impl/sqlite3/store.cpp 2015-12-02 10:05:00 +0000
275+++ src/core/trust/impl/sqlite3/store.cpp 2016-07-06 16:22:59 +0000
276@@ -346,7 +346,7 @@
277
278 // A store implementation persisting requests in an sqlite database.
279 struct Store
280- : public core::trust::Store,
281+ : public core::trust::PurgeableStore,
282 public std::enable_shared_from_this<Store>
283 {
284 // Our schema version constant.
285@@ -473,6 +473,20 @@
286 return s;
287 }
288 };
289+
290+ struct Purge
291+ {
292+ static const std::string& statement()
293+ {
294+ static const std::string s
295+ {
296+ "DELETE FROM " +
297+ Store::RequestsTable::name() +
298+ " WHERE ApplicationId=?;"
299+ };
300+ return s;
301+ }
302+ };
303 };
304
305 // An implementation of the query interface for the SQLite-based store.
306@@ -696,6 +710,7 @@
307 // From core::trust::Store
308 void reset();
309 void add(const Request& request);
310+ void purge(const std::string& id);
311 std::shared_ptr<core::trust::Store::Query> query();
312
313 std::mutex guard;
314@@ -704,6 +719,7 @@
315
316 TaggedPreparedStatement<Statements::Delete> delete_statement;
317 TaggedPreparedStatement<Statements::Insert> insert_statement;
318+ TaggedPreparedStatement<Statements::Purge> purge_statement;
319 };
320 }
321 }
322@@ -721,6 +737,7 @@
323
324 delete_statement = db.prepare_tagged_statement<Statements::Delete>();
325 insert_statement = db.prepare_tagged_statement<Statements::Insert>();
326+ purge_statement = db.prepare_tagged_statement<Statements::Purge>();
327 }
328
329 sqlite::Store::~Store()
330@@ -771,12 +788,21 @@
331 insert_statement.step();
332 }
333
334+void sqlite::Store::purge(const std::string& id)
335+{
336+ std::lock_guard<std::mutex> lg(guard);
337+
338+ purge_statement.reset();
339+ purge_statement.bind_text<sqlite::Store::RequestsTable::Column::ApplicationId::index>(id);
340+ purge_statement.step();
341+}
342+
343 std::shared_ptr<trust::Store::Query> sqlite::Store::query()
344 {
345 return std::shared_ptr<trust::Store::Query>{new sqlite::Store::Query{shared_from_this()}};
346 }
347
348-std::shared_ptr<core::trust::Store> core::trust::impl::sqlite::create_for_service(const std::string& name, xdg::BaseDirSpecification& spec)
349+std::shared_ptr<core::trust::PurgeableStore> core::trust::impl::sqlite::create_for_service(const std::string& name, xdg::BaseDirSpecification& spec)
350 {
351 if (name.empty())
352 throw core::trust::Errors::ServiceNameMustNotBeEmpty();
353@@ -786,5 +812,5 @@
354
355 std::shared_ptr<core::trust::Store> core::trust::create_default_store(const std::string& service_name)
356 {
357- return core::trust::impl::sqlite::create_for_service(service_name, *xdg::BaseDirSpecification::create());
358+ return core::trust::impl::sqlite::create_for_service(service_name, *xdg::BaseDirSpecification::create());
359 }
360
361=== modified file 'src/core/trust/impl/sqlite3/store.h'
362--- src/core/trust/impl/sqlite3/store.h 2015-11-18 08:28:51 +0000
363+++ src/core/trust/impl/sqlite3/store.h 2016-07-06 16:22:59 +0000
364@@ -40,7 +40,7 @@
365 // create_for_service creates a Store implementation relying on sqlite3, managing
366 // trust for the service identified by service_name. Uses spec to determine a user-specific
367 // directory to place the trust database.
368-CORE_TRUST_DLL_PUBLIC std::shared_ptr<core::trust::Store> create_for_service(const std::string& service_name, xdg::BaseDirSpecification& spec);
369+CORE_TRUST_DLL_PUBLIC std::shared_ptr<core::trust::PurgeableStore> create_for_service(const std::string& service_name, xdg::BaseDirSpecification& spec);
370 }
371 }
372 }
373
374=== modified file 'src/core/trust/resolve.cpp'
375--- src/core/trust/resolve.cpp 2014-07-29 17:00:35 +0000
376+++ src/core/trust/resolve.cpp 2016-07-06 16:22:59 +0000
377@@ -195,6 +195,12 @@
378 throw std::runtime_error(response.error().print());
379 }
380
381+ void clean(const std::string& id)
382+ {
383+ (void)id;
384+ throw std::runtime_error("not implemented");
385+ }
386+
387 void reset()
388 {
389 try
390
391=== modified file 'tests/CMakeLists.txt'
392--- tests/CMakeLists.txt 2016-01-11 09:51:51 +0000
393+++ tests/CMakeLists.txt 2016-07-06 16:22:59 +0000
394@@ -86,6 +86,11 @@
395 preseed_test.cpp
396 )
397
398+add_executable(
399+ cleaner_test
400+ cleaner_test.cpp
401+)
402+
403 target_link_libraries(
404 bug_1387734
405
406@@ -241,6 +246,19 @@
407 ${PROCESS_CPP_LIBRARIES}
408 )
409
410+target_link_libraries(
411+ cleaner_test
412+
413+ trust-store-cleaner-helper
414+
415+ gmock
416+
417+ gtest
418+ gtest_main
419+
420+ ${PROCESS_CPP_LIBRARIES}
421+)
422+
423 add_test(bug_1387734 ${CMAKE_CURRENT_BINARY_DIR}/bug_1387734)
424 add_test(trust_store_test ${CMAKE_CURRENT_BINARY_DIR}/trust_store_test)
425 add_test(remote_trust_store_test ${CMAKE_CURRENT_BINARY_DIR}/remote_trust_store_test)
426
427=== added file 'tests/cleaner_test.cpp'
428--- tests/cleaner_test.cpp 1970-01-01 00:00:00 +0000
429+++ tests/cleaner_test.cpp 2016-07-06 16:22:59 +0000
430@@ -0,0 +1,129 @@
431+/*
432+ * Copyright © 2016 Canonical Ltd.
433+ *
434+ * This program is free software: you can redistribute it and/or modify it
435+ * under the terms of the GNU Lesser General Public License version 3,
436+ * as published by the Free Software Foundation.
437+ *
438+ * This program is distributed in the hope that it will be useful,
439+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
440+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
441+ * GNU Lesser General Public License for more details.
442+ *
443+ * You should have received a copy of the GNU Lesser General Public License
444+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
445+ *
446+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
447+ * David Barth <david.barth@canonical.com>
448+ */
449+
450+#include <core/trust/cleaner.h>
451+#include <core/trust/preseed.h>
452+
453+#include "test_data.h"
454+
455+#include <core/posix/exec.h>
456+#include <core/posix/this_process.h>
457+
458+#include <gtest/gtest.h>
459+
460+#include <map>
461+
462+namespace
463+{
464+std::map<std::string, std::string> a_copy_of_the_current_env()
465+{
466+ std::map<std::string, std::string> result;
467+
468+ core::posix::this_process::env::for_each([&result](const std::string& s, const std::string& t)
469+ {
470+ result.insert(std::make_pair(s, t));
471+ });
472+
473+ return result;
474+}
475+}
476+
477+TEST(Cleaner, accepts_parameters)
478+{
479+ const std::string service_name{"JustANameForTesting"};
480+
481+ const std::vector<std::string> argv
482+ {
483+ "--for-service", service_name,
484+ "--purge", "other.app",
485+ "--purge", "does.not.exist.app"
486+ };
487+
488+ auto child = core::posix::exec(
489+ core::trust::testing::trust_store_cleaner_executable_in_build_dir,
490+ argv,
491+ a_copy_of_the_current_env(),
492+ core::posix::StandardStream::empty);
493+
494+ auto result = child.wait_for(core::posix::wait::Flags::untraced);
495+
496+ EXPECT_EQ(core::posix::wait::Result::Status::exited, result.status);
497+ EXPECT_EQ(core::posix::exit::Status::success, result.detail.if_exited.status);
498+}
499+
500+TEST(Cleaner, can_remove_authorization_for_app)
501+{
502+ const std::string service_name{"JustANameForTesting"};
503+ const std::string app_name{"does.not.exist.app"};
504+ const std::string other_app{"other.app"};
505+
506+ const std::vector<std::string> argv_preseed
507+ {
508+ "--for-service", service_name,
509+ "--request", "does.not.exist.app 0 granted", // 1
510+ "--request", "other.app 1 denied", // 2
511+ };
512+
513+ auto child_preseed = core::posix::exec(
514+ core::trust::testing::trust_store_preseed_executable_in_build_dir,
515+ argv_preseed,
516+ a_copy_of_the_current_env(),
517+ core::posix::StandardStream::empty);
518+
519+ auto result_preseed = child_preseed.wait_for(core::posix::wait::Flags::untraced);
520+
521+ EXPECT_EQ(core::posix::wait::Result::Status::exited, result_preseed.status);
522+ EXPECT_EQ(core::posix::exit::Status::success, result_preseed.detail.if_exited.status);
523+
524+ // TODO: should verify that the store is preseeded properly
525+
526+ const std::vector<std::string> argv
527+ {
528+ "--for-service", service_name,
529+ "--purge", app_name
530+ };
531+
532+ auto child = core::posix::exec(
533+ core::trust::testing::trust_store_cleaner_executable_in_build_dir,
534+ argv,
535+ a_copy_of_the_current_env(),
536+ core::posix::StandardStream::empty);
537+
538+ auto result = child.wait_for(core::posix::wait::Flags::untraced);
539+
540+ EXPECT_EQ(core::posix::wait::Result::Status::exited, result.status);
541+ EXPECT_EQ(core::posix::exit::Status::success, result.detail.if_exited.status);
542+
543+ auto store = core::trust::create_default_store(service_name);
544+
545+ auto query = store->query();
546+
547+ EXPECT_NO_THROW(query->execute());
548+
549+ EXPECT_EQ(core::trust::Store::Query::Status::has_more_results, query->status());
550+
551+ std::size_t counter{0};
552+
553+ while (query->status() != core::trust::Store::Query::Status::eor)
554+ {
555+ EXPECT_NE(app_name, query->current().from);
556+ query->next(); counter++;
557+ }
558+
559+}
560
561=== modified file 'tests/mock_store.h'
562--- tests/mock_store.h 2014-07-24 11:30:09 +0000
563+++ tests/mock_store.h 2016-07-06 16:22:59 +0000
564@@ -69,6 +69,8 @@
565 */
566 MOCK_METHOD1(add, void(const core::trust::Request&));
567
568+ MOCK_METHOD1(clean, void(const std::string&));
569+
570 /**
571 * @brief Create a query for this store.
572 */
573
574=== modified file 'tests/test_data.h.in'
575--- tests/test_data.h.in 2015-11-11 15:31:35 +0000
576+++ tests/test_data.h.in 2016-07-06 16:22:59 +0000
577@@ -39,6 +39,11 @@
578 {
579 "@CMAKE_BINARY_DIR@/src/trust-store-preseed"
580 };
581+
582+static constexpr const char* trust_store_cleaner_executable_in_build_dir
583+{
584+ "@CMAKE_BINARY_DIR@/src/trust-store-cleaner"
585+};
586 }
587 }
588 }

Subscribers

People subscribed via source and target branches