Mercurial > p > roundup > code
comparison test/test_mailgw.py @ 4781:6e9b9743de89
Implementation for:
http://issues.roundup-tracker.org/issue2550731
Add mechanism for the detectors to be able to tell the source of the
data changes.
Support for tx_Source property on database handle. Can be
used by detectors to find out the source of a change in an auditor to
block changes arriving by unauthenticated mechanisms (e.g. plain email
where headers can be faked). The property db.tx_Source has the
following values:
* None - Default value set to None. May be valid if it's a script
that is created by the user. Otherwise it's an error and indicates
that some code path is not properly setting the tx_Source property.
* "cli" - this string value is set when using roundup-admin and
supplied scripts.
* "web" - this string value is set when using any web based
technique: html interface, xmlrpc ....
* "email" - this string value is set when using an unauthenticated
email based technique.
* "email-sig-openpgp" - this string value is set when email with a
valid pgp signature is used. (*NOTE* the testing for this mode
is incomplete. If you have a pgp infrastructure you should test
and verify that this is properly set.)
This also includes some (possibly incomplete) tests cases for the
modes above and an example of using ts_Source in the customization.txt
document.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Tue, 23 Apr 2013 23:06:09 -0400 |
| parents | 782737d1a2d7 |
| children | a850f8bae536 |
comparison
equal
deleted
inserted
replaced
| 4774:3adff0fb0207 | 4781:6e9b9743de89 |
|---|---|
| 127 res.append('- %s'%l1[i]) | 127 res.append('- %s'%l1[i]) |
| 128 res.append('+ %s'%l2[j]) | 128 res.append('+ %s'%l2[j]) |
| 129 | 129 |
| 130 return res | 130 return res |
| 131 | 131 |
| 132 from roundup.hyperdb import String | |
| 133 | |
| 132 class MailgwTestAbstractBase(unittest.TestCase, DiffHelper): | 134 class MailgwTestAbstractBase(unittest.TestCase, DiffHelper): |
| 133 count = 0 | 135 count = 0 |
| 134 schema = 'classic' | 136 schema = 'classic' |
| 135 def setUp(self): | 137 def setUp(self): |
| 136 self.old_translate_ = mailgw._ | 138 self.old_translate_ = mailgw._ |
| 137 roundupdb._ = mailgw._ = i18n.get_translation(language='C').gettext | 139 roundupdb._ = mailgw._ = i18n.get_translation(language='C').gettext |
| 138 self.__class__.count = self.__class__.count + 1 | 140 self.__class__.count = self.__class__.count + 1 |
| 139 | 141 |
| 140 # and open the database / "instance" | 142 # and open the database / "instance" |
| 141 self.db = memorydb.create('admin') | 143 self.db = memorydb.create('admin') |
| 144 | |
| 145 self.db.issue.addprop(tx_Source=String()) | |
| 146 self.db.msg.addprop(tx_Source=String()) | |
| 147 self.db.post_init() | |
| 148 | |
| 149 self.db.tx_Source = "email" | |
| 150 | |
| 142 self.instance = Tracker() | 151 self.instance = Tracker() |
| 143 self.instance.db = self.db | 152 self.instance.db = self.db |
| 144 self.instance.config = self.db.config | 153 self.instance.config = self.db.config |
| 145 self.instance.MailGW = MailGW | 154 self.instance.MailGW = MailGW |
| 146 | 155 |
| 204 Subject: [issue] Testing... | 213 Subject: [issue] Testing... |
| 205 | 214 |
| 206 ''') | 215 ''') |
| 207 assert not os.path.exists(SENDMAILDEBUG) | 216 assert not os.path.exists(SENDMAILDEBUG) |
| 208 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...') | 217 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...') |
| 218 self.assertEqual(self.db.issue.get(nodeid, 'tx_Source'), 'email') | |
| 209 | 219 |
| 210 | 220 |
| 211 class MailgwTestCase(MailgwTestAbstractBase): | 221 class MailgwTestCase(MailgwTestAbstractBase): |
| 212 | 222 |
| 213 def testMessageWithFromInIt(self): | 223 def testMessageWithFromInIt(self): |
| 318 nodeid = self._handle_mail(self.newmsg) | 328 nodeid = self._handle_mail(self.newmsg) |
| 319 assert not os.path.exists(SENDMAILDEBUG) | 329 assert not os.path.exists(SENDMAILDEBUG) |
| 320 l = self.db.issue.get(nodeid, 'nosy') | 330 l = self.db.issue.get(nodeid, 'nosy') |
| 321 l.sort() | 331 l.sort() |
| 322 self.assertEqual(l, [self.chef_id, self.richard_id]) | 332 self.assertEqual(l, [self.chef_id, self.richard_id]) |
| 333 | |
| 334 # check that the message has the right source code | |
| 335 l = self.db.msg.get('1', 'tx_Source') | |
| 336 self.assertEqual(l, 'email') | |
| 337 | |
| 323 return nodeid | 338 return nodeid |
| 324 | 339 |
| 325 def testNewIssue(self): | 340 def testNewIssue(self): |
| 326 self.doNewIssue() | 341 self.doNewIssue() |
| 327 | 342 |
| 411 assignedto: richard | 426 assignedto: richard |
| 412 messages: 1 | 427 messages: 1 |
| 413 nosy: Chef, mary, richard | 428 nosy: Chef, mary, richard |
| 414 status: unread | 429 status: unread |
| 415 title: Testing... | 430 title: Testing... |
| 431 tx_Source: email | |
| 416 | 432 |
| 417 _______________________________________________________________________ | 433 _______________________________________________________________________ |
| 418 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example> | 434 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example> |
| 419 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1> | 435 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1> |
| 420 _______________________________________________________________________ | 436 _______________________________________________________________________ |
| 453 assignedto: richard | 469 assignedto: richard |
| 454 messages: 1 | 470 messages: 1 |
| 455 nosy: Chef, mary, richard | 471 nosy: Chef, mary, richard |
| 456 status: unread | 472 status: unread |
| 457 title: Testing... | 473 title: Testing... |
| 474 tx_Source: email | |
| 458 | 475 |
| 459 _______________________________________________________________________ | 476 _______________________________________________________________________ |
| 460 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example> | 477 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example> |
| 461 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1> | 478 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1> |
| 462 _______________________________________________________________________ | 479 _______________________________________________________________________ |
| 497 assignedto: richard | 514 assignedto: richard |
| 498 messages: 1 | 515 messages: 1 |
| 499 nosy: Chef, mary, richard | 516 nosy: Chef, mary, richard |
| 500 status: unread | 517 status: unread |
| 501 title: Testing... | 518 title: Testing... |
| 519 tx_Source: email | |
| 502 | 520 |
| 503 _______________________________________________________________________ | 521 _______________________________________________________________________ |
| 504 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example> | 522 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example> |
| 505 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1> | 523 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1> |
| 506 _______________________________________________________________________ | 524 _______________________________________________________________________ |
| 1193 X-Roundup-Name: Roundup issue tracker | 1211 X-Roundup-Name: Roundup issue tracker |
| 1194 X-Roundup-Loop: hello | 1212 X-Roundup-Loop: hello |
| 1195 X-Roundup-Issue-Status: chatting | 1213 X-Roundup-Issue-Status: chatting |
| 1196 Content-Transfer-Encoding: quoted-printable | 1214 Content-Transfer-Encoding: quoted-printable |
| 1197 | 1215 |
| 1198 | |
| 1199 richard <richard@test.test> added the comment: | 1216 richard <richard@test.test> added the comment: |
| 1200 | 1217 |
| 1201 This is a followup | 1218 This is a followup |
| 1202 | 1219 |
| 1203 ---------- | 1220 ---------- |
| 1227 ''') | 1244 ''') |
| 1228 l = self.db.issue.get('1', 'nosy') | 1245 l = self.db.issue.get('1', 'nosy') |
| 1229 l.sort() | 1246 l.sort() |
| 1230 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id, | 1247 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id, |
| 1231 self.john_id]) | 1248 self.john_id]) |
| 1249 | |
| 1250 # check that the message has the right tx_Source | |
| 1251 l = self.db.msg.get('2', 'tx_Source') | |
| 1252 self.assertEqual(l, 'email') | |
| 1232 | 1253 |
| 1233 self.compareMessages(self._get_mail(), | 1254 self.compareMessages(self._get_mail(), |
| 1234 '''FROM: roundup-admin@your.tracker.email.domain.example | 1255 '''FROM: roundup-admin@your.tracker.email.domain.example |
| 1235 TO: chef@bork.bork.bork, john@test.test, mary@test.test | 1256 TO: chef@bork.bork.bork, john@test.test, mary@test.test |
| 1236 Content-Type: text/plain; charset="utf-8" | 1257 Content-Type: text/plain; charset="utf-8" |
| 1245 X-Roundup-Name: Roundup issue tracker | 1266 X-Roundup-Name: Roundup issue tracker |
| 1246 X-Roundup-Loop: hello | 1267 X-Roundup-Loop: hello |
| 1247 X-Roundup-Issue-Status: chatting | 1268 X-Roundup-Issue-Status: chatting |
| 1248 Content-Transfer-Encoding: quoted-printable | 1269 Content-Transfer-Encoding: quoted-printable |
| 1249 | 1270 |
| 1250 | |
| 1251 richard <richard@test.test> added the comment: | 1271 richard <richard@test.test> added the comment: |
| 1252 | 1272 |
| 1253 This is a followup | 1273 This is a followup |
| 1254 | 1274 |
| 1255 ---------- | 1275 ---------- |
| 1263 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1> | 1283 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1> |
| 1264 _______________________________________________________________________ | 1284 _______________________________________________________________________ |
| 1265 ''') | 1285 ''') |
| 1266 | 1286 |
| 1267 def testNosyGeneration(self): | 1287 def testNosyGeneration(self): |
| 1288 self.db.tx_Source = "email" | |
| 1268 self.db.issue.create(title='test') | 1289 self.db.issue.create(title='test') |
| 1269 | 1290 |
| 1270 # create a nosy message | 1291 # create a nosy message |
| 1271 msg = self.db.msg.create(content='This is a test', | 1292 msg = self.db.msg.create(content='This is a test', |
| 1272 author=self.richard_id, messageid='<dummy_test_message_id>') | 1293 author=self.richard_id, messageid='<dummy_test_message_id>') |
| 1273 self.db.journaltag = 'richard' | 1294 self.db.journaltag = 'richard' |
| 1274 l = self.db.issue.create(title='test', messages=[msg], | 1295 l = self.db.issue.create(title='test', messages=[msg], |
| 1275 nosy=[self.chef_id, self.mary_id, self.john_id]) | 1296 nosy=[self.chef_id, self.mary_id, self.john_id]) |
| 1297 | |
| 1298 | |
| 1299 # check that message has right tx_Source | |
| 1300 self.assertEqual(self.db.msg.get('1', 'tx_Source'), 'email') | |
| 1276 | 1301 |
| 1277 self.compareMessages(self._get_mail(), | 1302 self.compareMessages(self._get_mail(), |
| 1278 '''FROM: roundup-admin@your.tracker.email.domain.example | 1303 '''FROM: roundup-admin@your.tracker.email.domain.example |
| 1279 TO: chef@bork.bork.bork, john@test.test, mary@test.test | 1304 TO: chef@bork.bork.bork, john@test.test, mary@test.test |
| 1280 Content-Type: text/plain; charset="utf-8" | 1305 Content-Type: text/plain; charset="utf-8" |
| 1298 ---------- | 1323 ---------- |
| 1299 messages: 1 | 1324 messages: 1 |
| 1300 nosy: Chef, john, mary, richard | 1325 nosy: Chef, john, mary, richard |
| 1301 status: unread | 1326 status: unread |
| 1302 title: test | 1327 title: test |
| 1328 tx_Source: email | |
| 1303 | 1329 |
| 1304 _______________________________________________________________________ | 1330 _______________________________________________________________________ |
| 1305 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example> | 1331 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example> |
| 1306 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2> | 1332 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2> |
| 1307 _______________________________________________________________________ | 1333 _______________________________________________________________________ |
| 1371 Message-Id: <followup_dummy_id> | 1397 Message-Id: <followup_dummy_id> |
| 1372 Subject: Re: Testing... [assignedto=mary; nosy=+john] | 1398 Subject: Re: Testing... [assignedto=mary; nosy=+john] |
| 1373 | 1399 |
| 1374 This is a followup | 1400 This is a followup |
| 1375 ''') | 1401 ''') |
| 1402 | |
| 1403 l = self.db.msg.get('2', 'tx_Source') | |
| 1404 self.assertEqual(l, 'email') | |
| 1405 | |
| 1376 self.compareMessages(self._get_mail(), | 1406 self.compareMessages(self._get_mail(), |
| 1377 '''FROM: roundup-admin@your.tracker.email.domain.example | 1407 '''FROM: roundup-admin@your.tracker.email.domain.example |
| 1378 TO: chef@bork.bork.bork, john@test.test, mary@test.test | 1408 TO: chef@bork.bork.bork, john@test.test, mary@test.test |
| 1379 Content-Type: text/plain; charset="utf-8" | 1409 Content-Type: text/plain; charset="utf-8" |
| 1380 Subject: [issue1] Testing... | 1410 Subject: [issue1] Testing... |
| 3388 def testPGPSignedMessage(self): | 3418 def testPGPSignedMessage(self): |
| 3389 nodeid = self._handle_mail(self.signed_msg) | 3419 nodeid = self._handle_mail(self.signed_msg) |
| 3390 m = self.db.issue.get(nodeid, 'messages')[0] | 3420 m = self.db.issue.get(nodeid, 'messages')[0] |
| 3391 self.assertEqual(self.db.msg.get(m, 'content'), | 3421 self.assertEqual(self.db.msg.get(m, 'content'), |
| 3392 'This is a pgp signed message.') | 3422 'This is a pgp signed message.') |
| 3423 # check that the message has the right source code | |
| 3424 l = self.db.msg.get(m, 'tx_Source') | |
| 3425 self.assertEqual(l, 'email-sig-openpgp') | |
| 3426 | |
| 3393 | 3427 |
| 3394 def testPGPSignedMessageFail(self): | 3428 def testPGPSignedMessageFail(self): |
| 3395 # require both, signing and encryption | 3429 # require both, signing and encryption |
| 3396 self.instance.config['PGP_REQUIRE_INCOMING'] = 'both' | 3430 self.instance.config['PGP_REQUIRE_INCOMING'] = 'both' |
| 3397 self.assertRaises(MailUsageError, self._handle_mail, self.signed_msg) | 3431 self.assertRaises(MailUsageError, self._handle_mail, self.signed_msg) |
| 3439 self.instance.config['PGP_REQUIRE_INCOMING'] = 'encrypted' | 3473 self.instance.config['PGP_REQUIRE_INCOMING'] = 'encrypted' |
| 3440 nodeid = self._handle_mail (self.encrypted_msg) | 3474 nodeid = self._handle_mail (self.encrypted_msg) |
| 3441 m = self.db.issue.get(nodeid, 'messages')[0] | 3475 m = self.db.issue.get(nodeid, 'messages')[0] |
| 3442 self.assertEqual(self.db.msg.get(m, 'content'), | 3476 self.assertEqual(self.db.msg.get(m, 'content'), |
| 3443 'This is the text to be encrypted') | 3477 'This is the text to be encrypted') |
| 3478 # check that the message has the right source code | |
| 3479 l = self.db.msg.get(m, 'tx_Source') | |
| 3480 self.assertEqual(l, 'email') | |
| 3444 | 3481 |
| 3445 def testPGPEncryptedUnsignedMessageFromNonPGPUser(self): | 3482 def testPGPEncryptedUnsignedMessageFromNonPGPUser(self): |
| 3446 msg = self.encrypted_msg.replace('John Doe <john@test.test>', | 3483 msg = self.encrypted_msg.replace('John Doe <john@test.test>', |
| 3447 '"Contrary, Mary" <mary@test.test>') | 3484 '"Contrary, Mary" <mary@test.test>') |
| 3448 nodeid = self._handle_mail (msg) | 3485 nodeid = self._handle_mail (msg) |
| 3449 m = self.db.issue.get(nodeid, 'messages')[0] | 3486 m = self.db.issue.get(nodeid, 'messages')[0] |
| 3450 self.assertEqual(self.db.msg.get(m, 'content'), | 3487 self.assertEqual(self.db.msg.get(m, 'content'), |
| 3451 'This is the text to be encrypted') | 3488 'This is the text to be encrypted') |
| 3452 self.assertEqual(self.db.msg.get(m, 'author'), self.mary_id) | 3489 self.assertEqual(self.db.msg.get(m, 'author'), self.mary_id) |
| 3490 # check that the message has the right source code | |
| 3491 l = self.db.msg.get(m, 'tx_Source') | |
| 3492 self.assertEqual(l, 'email') | |
| 3493 | |
| 3453 | 3494 |
| 3454 # check that a bounce-message that is triggered *after* | 3495 # check that a bounce-message that is triggered *after* |
| 3455 # decrypting is properly encrypted: | 3496 # decrypting is properly encrypted: |
| 3456 def testPGPEncryptedUnsignedMessageCheckBounce(self): | 3497 def testPGPEncryptedUnsignedMessageCheckBounce(self): |
| 3457 # allow non-signed msg | 3498 # allow non-signed msg |
| 3531 --ReaqsoxgOBHFXBhH-- | 3572 --ReaqsoxgOBHFXBhH-- |
| 3532 ''') | 3573 ''') |
| 3533 m = self.db.issue.get(nodeid, 'messages')[0] | 3574 m = self.db.issue.get(nodeid, 'messages')[0] |
| 3534 self.assertEqual(self.db.msg.get(m, 'content'), | 3575 self.assertEqual(self.db.msg.get(m, 'content'), |
| 3535 'This is the text of a signed and encrypted email.') | 3576 'This is the text of a signed and encrypted email.') |
| 3536 | 3577 # check that the message has the right source code |
| 3578 l = self.db.msg.get(m, 'tx_Source') | |
| 3579 self.assertEqual(l, 'email-sig-openpgp') | |
| 3537 | 3580 |
| 3538 def test_suite(): | 3581 def test_suite(): |
| 3539 suite = unittest.TestSuite() | 3582 suite = unittest.TestSuite() |
| 3540 suite.addTest(unittest.makeSuite(MailgwTestCase)) | 3583 suite.addTest(unittest.makeSuite(MailgwTestCase)) |
| 3541 if pyme is not None: | 3584 if pyme is not None: |
