3 #include <boost/test/unit_test.hpp>
5 #include "zypp/ZYppFactory.h"
6 #include "zypp/RepoManager.h"
9 using namespace boost::unit_test;
16 #define COUT if ( TC_VERBOSE ) std::cout
17 #define TAG COUT << "*** " << __PRETTY_FUNCTION__ << endl
19 static TestSetup test( TestSetup::initLater );
22 test = TestSetup( Arch_x86_64, TSO_REPO_DEFAULT_GPG );
24 ~TestInit() { test.reset(); }
26 BOOST_GLOBAL_FIXTURE( TestInit );
27 const Pathname DATADIR( TESTS_SRC_DIR "/repo/RepoSigcheck" );
29 ///////////////////////////////////////////////////////////////////
31 struct KeyRingReceiver : public callback::ReceiveReport<KeyRingReport>
33 typedef callback::ReceiveReport<KeyRingReport> Base;
35 KeyRingReceiver() { TAG; connect(); }
36 ~KeyRingReceiver() { TAG; }
38 virtual void reportbegin() { TAG; cblistCheck( __FUNCTION__ ); }
39 virtual void reportend() { TAG; cblistCheck( __FUNCTION__ ); }
41 virtual KeyTrust askUserToAcceptKey( const PublicKey &key, const KeyContext &keycontext = KeyContext() )
43 TAG; cblistCheck( __FUNCTION__ );
44 return Base::askUserToAcceptKey( key , keycontext );
47 virtual void infoVerify( const std::string & file_r, const PublicKeyData & keyData_r, const KeyContext &keycontext = KeyContext() )
49 TAG; cblistCheck( __FUNCTION__ );
50 return Base::infoVerify( file_r, keyData_r, keycontext );
53 virtual bool askUserToAcceptUnsignedFile( const std::string &file, const KeyContext &keycontext = KeyContext() )
55 TAG; cblistCheck( __FUNCTION__ );
56 return Base::askUserToAcceptUnsignedFile( file, keycontext );
59 virtual bool askUserToAcceptUnknownKey( const std::string &file, const std::string &id, const KeyContext &keycontext = KeyContext() )
61 TAG; cblistCheck( __FUNCTION__ );
62 return Base::askUserToAcceptUnknownKey( file, id, keycontext );
65 virtual bool askUserToAcceptVerificationFailed( const std::string &file, const PublicKey &key, const KeyContext &keycontext = KeyContext() )
67 TAG; cblistCheck( __FUNCTION__ );
68 return Base::askUserToAcceptVerificationFailed( file, key, keycontext );
72 typedef std::list<std::string> CallbackList;
74 void cblistCheck( const std::string & cb_r )
76 BOOST_CHECK_EQUAL( _cblist.empty(), false );
77 if ( !_cblist.empty() )
79 BOOST_CHECK_EQUAL( _cblist.front(), cb_r );
84 CallbackList _cblist; // expected callback sequence list
88 inline std::string chr( const bool & v )
89 { return v ? "1" : "0"; }
91 inline std::string chr( const TriBool & v )
93 return indeterminate(v) ? "*" : chr( bool(v) );
96 ///////////////////////////////////////////////////////////////////
98 * Check the RepoInfo methods returning which checks to perform
99 * based on the global (zypp.conf) and local (.repo file) settings.
101 * *** See table in RepoInfo.h:'Repository gpgchecks'
103 BOOST_AUTO_TEST_CASE(init)
105 ZConfig & zcfg( ZConfig::instance() );
108 std::initializer_list<TriBool> tribools( { TriBool(indeterminate), TriBool(true), TriBool(false) } );
110 // global zconfig values...
111 for ( bool g_GpgCheck : { true, false } )
113 zcfg.setGpgCheck( g_GpgCheck );
114 for ( TriBool g_RepoGpgCheck : tribools )
116 zcfg.setRepoGpgCheck( g_RepoGpgCheck );
117 for ( TriBool g_PkgGpgCheck : tribools )
119 zcfg.setPkgGpgCheck( g_PkgGpgCheck );
122 for ( TriBool r_GpgCheck : tribools )
124 repo.setGpgCheck( r_GpgCheck );
125 for ( TriBool r_RepoGpgCheck : tribools )
127 repo.setRepoGpgCheck( r_RepoGpgCheck );
128 for ( TriBool r_PkgGpgCheck : tribools )
130 repo.setPkgGpgCheck( r_PkgGpgCheck );
132 // check the repo methods returning what to do:
133 bool cfgGpgCheck = indeterminate(r_GpgCheck) ? g_GpgCheck : bool(r_GpgCheck);
134 TriBool cfgRepoGpgCheck = indeterminate(r_GpgCheck) && indeterminate(r_RepoGpgCheck) ? g_RepoGpgCheck : r_RepoGpgCheck;
135 TriBool cfgPkgGpgCheck = indeterminate(r_GpgCheck) && indeterminate(r_PkgGpgCheck) ? g_PkgGpgCheck : r_PkgGpgCheck;
137 COUT << chr(cfgGpgCheck) << "\t" << chr(cfgRepoGpgCheck) << "\t" << chr(cfgPkgGpgCheck)
138 << "\t(" << chr(r_GpgCheck) << "," << chr(g_GpgCheck) << ")"
139 << "\t(" << chr(r_RepoGpgCheck) << "," << chr(g_RepoGpgCheck) << ")"
140 << "\t(" << chr(r_PkgGpgCheck) << "," << chr(g_PkgGpgCheck) << ")"
144 // default gpgCeck follows config
145 BOOST_CHECK_EQUAL( repo.gpgCheck(), cfgGpgCheck );
148 // repoGpgCheck follows gpgCeck
149 // explicitly defined it alters mandatory check
150 bool willCheckRepo = repo.repoGpgCheck();
151 bool mandatoryCheck = repo.repoGpgCheckIsMandatory();
153 COUT << "\t" << ( willCheckRepo ? ( mandatoryCheck ? "!" : "+" ) : "-" ) << flush;
155 if ( mandatoryCheck ) // be a subset of willCheckRepo!
156 BOOST_CHECK_EQUAL( willCheckRepo, mandatoryCheck );
160 BOOST_CHECK_EQUAL( willCheckRepo, true );
161 BOOST_CHECK_EQUAL( mandatoryCheck, !bool(!cfgRepoGpgCheck) ); // TriBool: !false = true or indeterminate
165 BOOST_CHECK_EQUAL( willCheckRepo, bool(cfgRepoGpgCheck) );
166 BOOST_CHECK_EQUAL( mandatoryCheck, bool(cfgRepoGpgCheck) );
170 // pkgGpgCheck may depend on the repoGpgCheck result
171 for ( TriBool r_validSignature : tribools ) // indeterminate <==> unsigned repo
173 repo.setValidRepoSignature( r_validSignature );
175 if ( r_validSignature && !willCheckRepo )
176 // RepoInfo must invalidate any valid (old) signature as soon as the repo check
177 // is turned off. This prevents showing 'valid sig' for not yet refreshed repos.
178 // Instead show 'won't be checked' immediately.
179 BOOST_CHECK( bool(!repo.validRepoSignature()) );
181 BOOST_CHECK( sameTriboolState( repo.validRepoSignature(), r_validSignature ) );
183 bool willCheckPkg = repo.pkgGpgCheck();
184 bool mandatoryCheck = repo.pkgGpgCheckIsMandatory();
186 COUT << "\t" << chr(r_validSignature) << ( willCheckPkg ? ( mandatoryCheck ? "!" : "+" ) : "-" ) << flush;
188 if ( mandatoryCheck ) // be a subset of willCheckPkg!
189 BOOST_CHECK_EQUAL( willCheckPkg, mandatoryCheck );
191 if ( cfgPkgGpgCheck )
193 BOOST_CHECK_EQUAL( willCheckPkg, true );
194 BOOST_CHECK_EQUAL( mandatoryCheck, true );
196 else if ( cfgGpgCheck )
198 if ( r_validSignature )
200 BOOST_CHECK_EQUAL( willCheckPkg, false );
201 BOOST_CHECK_EQUAL( mandatoryCheck, false );
203 else // TriBool: !true = false or indeterminate/unsigned
205 BOOST_CHECK_EQUAL( willCheckPkg, true );
206 BOOST_CHECK_EQUAL( mandatoryCheck, !bool(!cfgPkgGpgCheck) ); // TriBool: !false = true or indeterminate/unsigned
211 BOOST_CHECK_EQUAL( willCheckPkg, false );
212 BOOST_CHECK_EQUAL( mandatoryCheck, false );
225 // reset to defaults:
226 zcfg.setGpgCheck ( true );
227 zcfg.setRepoGpgCheck ( indeterminate );
228 zcfg.setPkgGpgCheck ( indeterminate );
231 // RAII: Protect ZConfig value changes from escaping the block scope
235 : _zcfg( ZConfig::instance() )
237 _g = _zcfg.gpgCheck();
238 _r = _zcfg.repoGpgCheck();
239 _p = _zcfg.pkgGpgCheck();
244 _zcfg.setGpgCheck ( _g );
245 _zcfg.setRepoGpgCheck( _r );
246 _zcfg.setPkgGpgCheck ( _p );
249 ZConfig * operator->() { return &_zcfg; }
258 // RAII: Set and reset KeyRingReceiver callback list and response bits for new testcase
261 KeyRingGuard ( KeyRing::DefaultAccept accept_r = KeyRing::ACCEPT_NOTHING )
263 KeyRing::setDefaultAccept( accept_r );
264 krCallback._cblist.clear();
266 COUT << "================================================================================" << endl;
267 KeyRing & keyRing( *getZYpp()->keyRing() );
268 COUT << "K " << keyRing.publicKeys() << endl;
269 COUT << "T " << keyRing.trustedPublicKeys() << endl;
270 COUT << KeyRing::defaultAccept() << endl;
272 ZConfig & zcfg( ZConfig::instance() );
273 COUT << "ZConf " << chr( zcfg.gpgCheck() ) << chr( zcfg.repoGpgCheck() ) << chr( zcfg.pkgGpgCheck() ) << endl;
279 BOOST_CHECK_EQUAL( krCallback._cblist.empty(), true );
280 KeyRing::setDefaultAccept( KeyRing::ACCEPT_NOTHING );
281 krCallback._cblist.clear();
285 void testLoadRepo( bool succeed_r, // whether loadRepos should succeed or fail with RepoException
286 const std::string & repo_r, // name of the test repo to load
287 KeyRing::DefaultAccept accept_r, // Callback response bits to set (mimics user input)
288 KeyRingReceiver::CallbackList cblist_r ) // Callback sequence list expected
290 KeyRingGuard _guard( accept_r );
291 krCallback._cblist = std::move(cblist_r);
293 test.loadRepo( DATADIR/repo_r, repo_r );
295 BOOST_CHECK_THROW( test.loadRepo( DATADIR/repo_r, repo_r ), repo::RepoException );
298 // ACCEPT_NOTHING = 0x0000,
299 // ACCEPT_UNSIGNED_FILE = 0x0001,
300 // ACCEPT_UNKNOWNKEY = 0x0002,
301 // TRUST_KEY_TEMPORARILY = 0x0004,
302 // TRUST_AND_IMPORT_KEY = 0x0008,
303 // ACCEPT_VERIFICATION_FAILED = 0x0010,
305 BOOST_AUTO_TEST_CASE(unsigned_repo)
307 // askUserToAcceptUnsignedFile actually depends on the gpgcheck settings.
308 // Mandatory on 'R' cases. Otherwise an unsigend repo is accepted but 'pkggpg on'
311 zcfg->setRepoGpgCheck( false ); // unsafe
313 std::string repo( "unsigned_repo" );
314 testLoadRepo( true, repo, KeyRing::ACCEPT_NOTHING,
317 zcfg->setRepoGpgCheck( indeterminate ); // the default
319 testLoadRepo( false, repo, KeyRing::ACCEPT_NOTHING,
320 { "reportbegin", "askUserToAcceptUnsignedFile", "reportend" } );
321 testLoadRepo( true, repo, KeyRing::ACCEPT_UNSIGNED_FILE,
322 { "reportbegin", "askUserToAcceptUnsignedFile", "reportend" } );
325 BOOST_AUTO_TEST_CASE(unknownkey_repo)
327 std::string repo( "unknownkey_repo" );
328 testLoadRepo( false, repo, KeyRing::ACCEPT_NOTHING,
329 { "reportbegin", "askUserToAcceptUnknownKey", "reportend" } );
330 testLoadRepo( true, repo, KeyRing::ACCEPT_UNKNOWNKEY,
331 { "reportbegin", "askUserToAcceptUnknownKey", "reportend" } );
335 BOOST_AUTO_TEST_CASE(wrongsig_repo)
337 std::string repo( "wrongsig_repo" );
338 // IMPORTED KEYS WILL STAY IN KEYRING! FIXIT if it disturbs subsequent tests
340 // 1st testcase with a key, so on the fly check askUserToAcceptKey
341 // being called unless the key is imported in the trusted ring
342 testLoadRepo( false, repo, KeyRing::ACCEPT_NOTHING,
343 { "reportbegin", "askUserToAcceptKey", "reportend" } );
344 testLoadRepo( false, repo, KeyRing::TRUST_KEY_TEMPORARILY,
345 { "reportbegin", "askUserToAcceptKey", "infoVerify", "askUserToAcceptVerificationFailed", "reportend" } );
346 testLoadRepo( false, repo, KeyRing::ACCEPT_NOTHING,
347 { "reportbegin", "askUserToAcceptKey", "reportend" } );
348 testLoadRepo( false, repo, KeyRing::TRUST_AND_IMPORT_KEY,
349 { "reportbegin", "askUserToAcceptKey", "infoVerify", "askUserToAcceptVerificationFailed", "reportend" } );
351 // Now the key is in the trusted ring (no more askUserToAcceptKey)
352 testLoadRepo( false, repo, KeyRing::ACCEPT_NOTHING,
353 { "reportbegin", "infoVerify", "askUserToAcceptVerificationFailed", "reportend" } );
354 testLoadRepo( true, repo, KeyRing::KeyRing::ACCEPT_VERIFICATION_FAILED,
355 { "reportbegin", "infoVerify", "askUserToAcceptVerificationFailed", "reportend" } );
358 BOOST_AUTO_TEST_CASE(signed_repo)
360 std::string repo( "signed_repo" );
361 testLoadRepo( true, repo, KeyRing::KeyRing::ACCEPT_NOTHING, // relies on wrongsig_repo having accepted the key! (already in trusted ring)
362 { "reportbegin", "infoVerify", "reportend" } );
366 BOOST_AUTO_TEST_CASE(summary)
369 KeyRing & keyRing( *getZYpp()->keyRing() );
370 BOOST_CHECK_EQUAL( keyRing.publicKeys().size(), 1 );
371 BOOST_CHECK_EQUAL( keyRing.trustedPublicKeys().size(), 1 );
372 BOOST_CHECK_EQUAL( KeyRing::defaultAccept(), KeyRing::ACCEPT_NOTHING );
373 BOOST_CHECK_EQUAL( test.satpool().repos().size(), 5 ); //