3 #include <boost/test/auto_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 TestSetup test( Arch_x86_64, TSO_REPO_DEFAULT_GPG );
20 const Pathname DATADIR( TESTS_SRC_DIR "/repo/RepoSigcheck" );
22 ///////////////////////////////////////////////////////////////////
24 struct KeyRingReceiver : public callback::ReceiveReport<KeyRingReport>
26 typedef callback::ReceiveReport<KeyRingReport> Base;
28 KeyRingReceiver() { TAG; connect(); }
29 ~KeyRingReceiver() { TAG; }
31 virtual void reportbegin() { TAG; cblistCheck( __FUNCTION__ ); }
32 virtual void reportend() { TAG; cblistCheck( __FUNCTION__ ); }
34 virtual KeyTrust askUserToAcceptKey( const PublicKey &key, const KeyContext &keycontext = KeyContext() )
36 TAG; cblistCheck( __FUNCTION__ );
37 return Base::askUserToAcceptKey( key , keycontext );
40 virtual void infoVerify( const std::string & file_r, const PublicKeyData & keyData_r, const KeyContext &keycontext = KeyContext() )
42 TAG; cblistCheck( __FUNCTION__ );
43 return Base::infoVerify( file_r, keyData_r, keycontext );
46 virtual bool askUserToAcceptUnsignedFile( const std::string &file, const KeyContext &keycontext = KeyContext() )
48 TAG; cblistCheck( __FUNCTION__ );
49 return Base::askUserToAcceptUnsignedFile( file, keycontext );
52 virtual bool askUserToAcceptUnknownKey( const std::string &file, const std::string &id, const KeyContext &keycontext = KeyContext() )
54 TAG; cblistCheck( __FUNCTION__ );
55 return Base::askUserToAcceptUnknownKey( file, id, keycontext );
58 virtual bool askUserToAcceptVerificationFailed( const std::string &file, const PublicKey &key, const KeyContext &keycontext = KeyContext() )
60 TAG; cblistCheck( __FUNCTION__ );
61 return Base::askUserToAcceptVerificationFailed( file, key, keycontext );
65 typedef std::list<std::string> CallbackList;
67 void cblistCheck( const std::string & cb_r )
69 BOOST_CHECK_EQUAL( _cblist.empty(), false );
70 if ( !_cblist.empty() )
72 BOOST_CHECK_EQUAL( _cblist.front(), cb_r );
77 CallbackList _cblist; // expected callback sequence list
81 inline std::string chr( const bool & v )
82 { return v ? "1" : "0"; }
84 inline std::string chr( const TriBool & v )
86 return indeterminate(v) ? "*" : chr( bool(v) );
89 ///////////////////////////////////////////////////////////////////
91 * Check the RepoInfo methods returning which checks to perform
92 * based on the global (zypp.conf) and local (.repo file) settings.
94 * *** See table in RepoInfo.h:'Repository gpgchecks'
96 BOOST_AUTO_TEST_CASE(init)
98 ZConfig & zcfg( ZConfig::instance() );
101 std::initializer_list<TriBool> tribools( { TriBool(indeterminate), TriBool(true), TriBool(false) } );
103 // global zconfig values...
104 for ( bool g_GpgCheck : { true, false } )
106 zcfg.setGpgCheck( g_GpgCheck );
107 for ( TriBool g_RepoGpgCheck : tribools )
109 zcfg.setRepoGpgCheck( g_RepoGpgCheck );
110 for ( TriBool g_PkgGpgCheck : tribools )
112 zcfg.setPkgGpgCheck( g_PkgGpgCheck );
115 for ( TriBool r_GpgCheck : tribools )
117 repo.setGpgCheck( r_GpgCheck );
118 for ( TriBool r_RepoGpgCheck : tribools )
120 repo.setRepoGpgCheck( r_RepoGpgCheck );
121 for ( TriBool r_PkgGpgCheck : tribools )
123 repo.setPkgGpgCheck( r_PkgGpgCheck );
125 // check the repo methods returning what to do:
126 bool cfgGpgCheck = indeterminate(r_GpgCheck) ? g_GpgCheck : bool(r_GpgCheck);
127 TriBool cfgRepoGpgCheck = indeterminate(r_GpgCheck) && indeterminate(r_RepoGpgCheck) ? g_RepoGpgCheck : r_RepoGpgCheck;
128 TriBool cfgPkgGpgCheck = indeterminate(r_GpgCheck) && indeterminate(r_PkgGpgCheck) ? g_PkgGpgCheck : r_PkgGpgCheck;
130 COUT << chr(cfgGpgCheck) << "\t" << chr(cfgRepoGpgCheck) << "\t" << chr(cfgPkgGpgCheck)
131 << "\t(" << chr(r_GpgCheck) << "," << chr(g_GpgCheck) << ")"
132 << "\t(" << chr(r_RepoGpgCheck) << "," << chr(g_RepoGpgCheck) << ")"
133 << "\t(" << chr(r_PkgGpgCheck) << "," << chr(g_PkgGpgCheck) << ")"
137 // default gpgCeck follows config
138 BOOST_CHECK_EQUAL( repo.gpgCheck(), cfgGpgCheck );
141 // repoGpgCheck follows gpgCeck
142 // explicitly defined it alters mandatory check
143 bool willCheckRepo = repo.repoGpgCheck();
144 bool mandatoryCheck = repo.repoGpgCheckIsMandatory();
146 COUT << "\t" << ( willCheckRepo ? ( mandatoryCheck ? "!" : "+" ) : "-" ) << flush;
148 if ( mandatoryCheck ) // be a subset of willCheckRepo!
149 BOOST_CHECK_EQUAL( willCheckRepo, mandatoryCheck );
153 BOOST_CHECK_EQUAL( willCheckRepo, true );
154 BOOST_CHECK_EQUAL( mandatoryCheck, !bool(!cfgRepoGpgCheck) ); // TriBool: !false = true or indeterminate
158 BOOST_CHECK_EQUAL( willCheckRepo, bool(cfgRepoGpgCheck) );
159 BOOST_CHECK_EQUAL( mandatoryCheck, bool(cfgRepoGpgCheck) );
163 // pkgGpgCheck may depend on the repoGpgCheck result
164 for ( TriBool r_validSignature : tribools ) // indeterminate <==> unsigned repo
166 repo.setValidRepoSignature( r_validSignature );
168 if ( r_validSignature && !willCheckRepo )
169 // RepoInfo must invalidate any valid (old) signature as soon as the repo check
170 // is turned off. This prevents showing 'valid sig' for not yet refreshed repos.
171 // Instead show 'won't be checked' immediately.
172 BOOST_CHECK( bool(!repo.validRepoSignature()) );
174 BOOST_CHECK( sameTriboolState( repo.validRepoSignature(), r_validSignature ) );
176 bool willCheckPkg = repo.pkgGpgCheck();
177 bool mandatoryCheck = repo.pkgGpgCheckIsMandatory();
179 COUT << "\t" << chr(r_validSignature) << ( willCheckPkg ? ( mandatoryCheck ? "!" : "+" ) : "-" ) << flush;
181 if ( mandatoryCheck ) // be a subset of willCheckPkg!
182 BOOST_CHECK_EQUAL( willCheckPkg, mandatoryCheck );
184 if ( cfgPkgGpgCheck )
186 BOOST_CHECK_EQUAL( willCheckPkg, true );
187 BOOST_CHECK_EQUAL( mandatoryCheck, true );
189 else if ( cfgGpgCheck )
191 if ( r_validSignature )
193 BOOST_CHECK_EQUAL( willCheckPkg, false );
194 BOOST_CHECK_EQUAL( mandatoryCheck, false );
196 else // TriBool: !true = false or indeterminate/unsigned
198 BOOST_CHECK_EQUAL( willCheckPkg, true );
199 BOOST_CHECK_EQUAL( mandatoryCheck, !bool(!cfgPkgGpgCheck) ); // TriBool: !false = true or indeterminate/unsigned
204 BOOST_CHECK_EQUAL( willCheckPkg, false );
205 BOOST_CHECK_EQUAL( mandatoryCheck, false );
218 // reset to defaults:
219 zcfg.setGpgCheck ( true );
220 zcfg.setRepoGpgCheck ( indeterminate );
221 zcfg.setPkgGpgCheck ( indeterminate );
224 // RAII: Protect ZConfig value changes from escaping the block scope
228 : _zcfg( ZConfig::instance() )
230 _g = _zcfg.gpgCheck();
231 _r = _zcfg.repoGpgCheck();
232 _p = _zcfg.pkgGpgCheck();
237 _zcfg.setGpgCheck ( _g );
238 _zcfg.setRepoGpgCheck( _r );
239 _zcfg.setPkgGpgCheck ( _p );
242 ZConfig * operator->() { return &_zcfg; }
251 // RAII: Set and reset KeyRingReceiver callback list and response bits for new testcase
254 KeyRingGuard ( KeyRing::DefaultAccept accept_r = KeyRing::ACCEPT_NOTHING )
256 KeyRing::setDefaultAccept( accept_r );
257 krCallback._cblist.clear();
259 COUT << "================================================================================" << endl;
260 KeyRing & keyRing( *getZYpp()->keyRing() );
261 COUT << "K " << keyRing.publicKeys() << endl;
262 COUT << "T " << keyRing.trustedPublicKeys() << endl;
263 COUT << KeyRing::defaultAccept() << endl;
265 ZConfig & zcfg( ZConfig::instance() );
266 COUT << "ZConf " << chr( zcfg.gpgCheck() ) << chr( zcfg.repoGpgCheck() ) << chr( zcfg.pkgGpgCheck() ) << endl;
272 BOOST_CHECK_EQUAL( krCallback._cblist.empty(), true );
273 KeyRing::setDefaultAccept( KeyRing::ACCEPT_NOTHING );
274 krCallback._cblist.clear();
278 void testLoadRepo( bool succeed_r, // whether loadRepos should succeed or fail with RepoException
279 const std::string & repo_r, // name of the test repo to load
280 KeyRing::DefaultAccept accept_r, // Callback response bits to set (mimics user input)
281 KeyRingReceiver::CallbackList cblist_r ) // Callback sequence list expected
283 KeyRingGuard _guard( accept_r );
284 krCallback._cblist = std::move(cblist_r);
286 test.loadRepo( DATADIR/repo_r, repo_r );
288 BOOST_CHECK_THROW( test.loadRepo( DATADIR/repo_r, repo_r ), repo::RepoException );
291 // ACCEPT_NOTHING = 0x0000,
292 // ACCEPT_UNSIGNED_FILE = 0x0001,
293 // ACCEPT_UNKNOWNKEY = 0x0002,
294 // TRUST_KEY_TEMPORARILY = 0x0004,
295 // TRUST_AND_IMPORT_KEY = 0x0008,
296 // ACCEPT_VERIFICATION_FAILED = 0x0010,
298 BOOST_AUTO_TEST_CASE(unsigned_repo)
300 // askUserToAcceptUnsignedFile actually depends on the gpgcheck settings.
301 // Mandatory on 'R' cases. Otherwise an unsigend repo is accepted but 'pkggpg on'
304 zcfg->setRepoGpgCheck( false ); // unsafe
306 std::string repo( "unsigned_repo" );
307 testLoadRepo( true, repo, KeyRing::ACCEPT_NOTHING,
310 zcfg->setRepoGpgCheck( indeterminate ); // the default
312 testLoadRepo( false, repo, KeyRing::ACCEPT_NOTHING,
313 { "reportbegin", "askUserToAcceptUnsignedFile", "reportend" } );
314 testLoadRepo( true, repo, KeyRing::ACCEPT_UNSIGNED_FILE,
315 { "reportbegin", "askUserToAcceptUnsignedFile", "reportend" } );
318 BOOST_AUTO_TEST_CASE(unknownkey_repo)
320 std::string repo( "unknownkey_repo" );
321 testLoadRepo( false, repo, KeyRing::ACCEPT_NOTHING,
322 { "reportbegin", "askUserToAcceptUnknownKey", "reportend" } );
323 testLoadRepo( true, repo, KeyRing::ACCEPT_UNKNOWNKEY,
324 { "reportbegin", "askUserToAcceptUnknownKey", "reportend" } );
328 BOOST_AUTO_TEST_CASE(wrongsig_repo)
330 std::string repo( "wrongsig_repo" );
331 // IMPORTED KEYS WILL STAY IN KEYRING! FIXIT if it disturbs subsequent tests
333 // 1st testcase with a key, so on the fly check askUserToAcceptKey
334 // being called unless the key is imported in the trusted ring
335 testLoadRepo( false, repo, KeyRing::ACCEPT_NOTHING,
336 { "reportbegin", "askUserToAcceptKey", "reportend" } );
337 testLoadRepo( false, repo, KeyRing::TRUST_KEY_TEMPORARILY,
338 { "reportbegin", "askUserToAcceptKey", "infoVerify", "askUserToAcceptVerificationFailed", "reportend" } );
339 testLoadRepo( false, repo, KeyRing::ACCEPT_NOTHING,
340 { "reportbegin", "askUserToAcceptKey", "reportend" } );
341 testLoadRepo( false, repo, KeyRing::TRUST_AND_IMPORT_KEY,
342 { "reportbegin", "askUserToAcceptKey", "infoVerify", "askUserToAcceptVerificationFailed", "reportend" } );
344 // Now the key is in the trusted ring (no more askUserToAcceptKey)
345 testLoadRepo( false, repo, KeyRing::ACCEPT_NOTHING,
346 { "reportbegin", "infoVerify", "askUserToAcceptVerificationFailed", "reportend" } );
347 testLoadRepo( true, repo, KeyRing::KeyRing::ACCEPT_VERIFICATION_FAILED,
348 { "reportbegin", "infoVerify", "askUserToAcceptVerificationFailed", "reportend" } );
351 BOOST_AUTO_TEST_CASE(signed_repo)
353 std::string repo( "signed_repo" );
354 testLoadRepo( true, repo, KeyRing::KeyRing::ACCEPT_NOTHING, // relies on wrongsig_repo having accepted the key! (already in trusted ring)
355 { "reportbegin", "infoVerify", "reportend" } );
359 BOOST_AUTO_TEST_CASE(summary)
362 KeyRing & keyRing( *getZYpp()->keyRing() );
363 BOOST_CHECK_EQUAL( keyRing.publicKeys().size(), 1 );
364 BOOST_CHECK_EQUAL( keyRing.trustedPublicKeys().size(), 1 );
365 BOOST_CHECK_EQUAL( KeyRing::defaultAccept(), KeyRing::ACCEPT_NOTHING );
366 BOOST_CHECK_EQUAL( test.satpool().reposSize(), 5 ); //