Merge lp:~james-w/canonical-identity-provider/django-timeline into lp:canonical-identity-provider/release

Proposed by James Westby
Status: Merged
Approved by: James Westby
Approved revision: no longer in the source branch.
Merged at revision: 992
Proposed branch: lp:~james-w/canonical-identity-provider/django-timeline
Merge into: lp:canonical-identity-provider/release
Diff against target: 159 lines (+91/-4)
5 files modified
config-manager.txt (+3/-0)
django_project/wsgi.py (+16/-4)
src/identityprovider/oops_config.py (+10/-0)
src/identityprovider/tests/test_oops.py (+26/-0)
src/identityprovider/timeline_filters.py (+36/-0)
To merge this branch: bzr merge lp:~james-w/canonical-identity-provider/django-timeline
Reviewer Review Type Date Requested Status
Natalia Bidart (community) Approve
Review via email: mp+178791@code.launchpad.net

Commit message

Add timeline-django to record sql queries in oopses.

Description of the change

Hi,

This adds SQL queries to the generated oopses, using django-timeline.

The majority of the change is adding the new dependencies and wiring it up.
The rest is configuring the code to redact queries against the tables that
contain sensitive information.

Thanks,

James

To post a comment you must log in.
Revision history for this message
Ricardo Kirkner (ricardokirkner) wrote :

For tracking dependencies in a way that is auditable we prefer to track branches owned by ~ubuntuone-pqm-team. Please use the following branches instead of trunk:

lp:~ubuntuone-pqm-team/python-oops-timeline/stable
lp:~ubuntuone-pqm-team/python-timeline/stable
lp:~ubuntuone-pqm-team/python-timeline-django/stable

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Looks good!

review: Approve
Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :

The attempt to merge lp:~james-w/canonical-identity-provider/django-timeline into lp:canonical-identity-provider failed. Below is the output from the failed tests.

Updating download cache at dir /mnt/tarmac/cache/canonical-identity-provider/isd-download-cache
Using saved parent location: bzr+ssh://bazaar.launchpad.net/~canonical-isd-hackers/+junk/download-cache/
No revisions or tags to pull.
[localhost] local: which virtualenv
[localhost] local: /usr/bin/python /usr/bin/virtualenv --distribute --clear --system-site-packages .env
Not deleting .env/bin
New python executable in .env/bin/python
Installing distribute.............................................................................................................................................................................................done.
Installing pip...............done.
[localhost] local: dpkg -l libpq-dev 2> /dev/null | grep '^ii' | wc -l
[localhost] local: dpkg -l libxml2-dev 2> /dev/null | grep '^ii' | wc -l
[localhost] local: dpkg -l libxslt1-dev 2> /dev/null | grep '^ii' | wc -l
[localhost] local: dpkg -l memcached 2> /dev/null | grep '^ii' | wc -l
[localhost] local: dpkg -l postgresql-plpython-9.1 2> /dev/null | grep '^ii' | wc -l
[localhost] local: dpkg -l python-dev 2> /dev/null | grep '^ii' | wc -l
[localhost] local: dpkg -l python-m2crypto 2> /dev/null | grep '^ii' | wc -l
[localhost] local: dpkg -l swig 2> /dev/null | grep '^ii' | wc -l
[localhost] local: dpkg -l config-manager 2> /dev/null | grep '^ii' | wc -l
[localhost] local: dpkg -l python-egenix-mx-base-dev 2> /dev/null | grep '^ii' | wc -l
[localhost] local: /usr/lib/config-manager/cm.py update /tmp/tmpO1bi_a
UnknownErrorFromSmartServer(Server sent an unexpected error: ('error', 'GhostRevisionsHaveNoRevno', 'Could not determine revno for {10} because its ancestry shows a ghost at {<email address hidden>}')) Server sent an unexpected error: ('error', 'GhostRevisionsHaveNoRevno', 'Could not determine revno for {10} because its ancestry shows a ghost at {<email address hidden>}')

Traceback (most recent call last):
  File "/usr/lib/config-manager/cm.py", line 30, in <module>
    main(sys.argv)
  File "/usr/lib/pymodules/python2.7/config_manager/__init__.py", line 384, in main
    config.update(os.path.abspath(os.curdir))
  File "/usr/lib/pymodules/python2.7/config_manager/__init__.py", line 91, in update
    entry.update(dir)
  File "/usr/lib/pymodules/python2.7/config_manager/__init__.py", line 306, in update
    return self.build(path)
  File "/usr/lib/pymodules/python2.7/config_manager/__init__.py", line 280, in build
    raise ValueError("unknown url type '%s'" % self.url)
ValueError: unknown url type 'bzr+ssh://bazaar.launchpad.net/~ubuntuone-pqm-team/python-timeline/stable;revno=10'

Fatal error: local() encountered an error (return code 1) while executing '/usr/lib/config-manager/cm.py update /tmp/tmpO1bi_a'

Aborting.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'config-manager.txt'
2--- config-manager.txt 2013-08-05 15:26:51 +0000
3+++ config-manager.txt 2013-08-07 15:56:25 +0000
4@@ -34,6 +34,7 @@
5 canonical-identity-provider/branches/oops-amqp bzr+ssh://bazaar.isd/~ubuntuone-pqm-team/python-oops-amqp/stable;revno=0.0.7
6 canonical-identity-provider/branches/oops-datedir-repo bzr+ssh://bazaar.isd/~ubuntuone-pqm-team/python-oops-datedir-repo/stable;revno=0.0.20
7 canonical-identity-provider/branches/oops-dictconfig bzr+ssh://bazaar.isd/~ubuntuone-pqm-team/python-oops-dictconfig/stable;revno=0.0.4
8+canonical-identity-provider/branches/oops-timeline bzr+ssh://bazaar.isd/~ubuntuone-pqm-team/python-oops-timeline/stable;revno=3
9 canonical-identity-provider/branches/oops-wsgi bzr+ssh://bazaar.isd/~ubuntuone-pqm-team/python-oops-wsgi/stable;revno=36
10 canonical-identity-provider/branches/pystatsd bzr+ssh://bazaar.isd/~ubuntuone-pqm-team/pystatsd/stable;revno=53
11 canonical-identity-provider/branches/python-oath bzr+ssh://bazaar.isd/~ubuntuone-pqm-team/python-oath/stable;revno=53
12@@ -42,4 +43,6 @@
13 canonical-identity-provider/branches/requests bzr+ssh://bazaar.isd/~ubuntuone-pqm-team/requests/stable;revno=v1.1.0
14 canonical-identity-provider/branches/requests-oauthlib bzr+ssh://bazaar.isd/~ubuntuone-pqm-team/requests-oauthlib/stable;revno=16
15 canonical-identity-provider/branches/ssoclient bzr+ssh://bazaar.isd/~canonical-isd-hackers/canonical-identity-provider/ssoclient;revno=7
16+canonical-identity-provider/branches/timeline bzr+ssh://bazaar.isd/~ubuntuone-pqm-team/python-timeline/stable;revno=10
17+canonical-identity-provider/branches/timeline-django bzr+ssh://bazaar.isd/~ubuntuone-pqm-team/python-timeline-django/stable;revno=17
18 canonical-identity-provider/branches/yui-3.10.0 bzr+ssh://bazaar.isd/~ubuntuone-pqm-team/yui/stable;revno=v3.10.0
19
20=== modified file 'django_project/wsgi.py'
21--- django_project/wsgi.py 2013-08-02 16:09:22 +0000
22+++ django_project/wsgi.py 2013-08-07 15:56:25 +0000
23@@ -1,5 +1,4 @@
24 import os
25-import platform
26 import sys
27
28 # before doing anything else, patch stdout to avoid breakage in production
29@@ -16,7 +15,6 @@
30 paths.setup_paths()
31
32 from django.conf import settings
33-from django.core.handlers.wsgi import WSGIHandler
34
35 os.environ['PGCONNECT_TIMEOUT'] = str(settings.PGCONNECT_TIMEOUT)
36 os.environ['PGSSLMODE'] = 'allow'
37@@ -27,13 +25,27 @@
38
39 # Wrap the application in the Oops wsgi app to catch unhandled exceptions
40 # and create oops for them.
41-#
42-# First we create the config that defines what to do with the oopses.
43+
44+from identityprovider.oops_config import install_timeline_hooks
45 import oops_dictconfig
46 from oops_wsgi import make_app, install_hooks
47+from timeline_django import setup as timeline_django_setup
48+from timeline_django.wsgi import make_app as timeline_django_make_app
49+from timeline.wsgi import make_app as timeline_make_app
50
51+# First we create the config that defines what to do with the oopses.
52 config = oops_dictconfig.config_from_dict(settings.OOPSES)
53 install_hooks(config)
54
55+# Install the hooks to record the sql queries
56+timeline_django_setup.setup_for_requests()
57+
58+# Set up the timeline in the django and wsgi envs
59+app = timeline_django_make_app(app)
60+app = timeline_make_app(app)
61+
62+# Add the hooks to collect and sanitise the timeline
63+install_timeline_hooks()
64+
65 # Then we wrap the django app in the oops one
66 application = make_app(app, config, oops_on_status=['500'])
67
68=== added symlink 'lib/oops_timeline'
69=== target is u'../branches/oops-timeline/oops_timeline/'
70=== added symlink 'lib/timeline'
71=== target is u'../branches/timeline/timeline'
72=== added symlink 'lib/timeline_django'
73=== target is u'../branches/timeline-django/timeline_django/'
74=== added file 'src/identityprovider/oops_config.py'
75--- src/identityprovider/oops_config.py 1970-01-01 00:00:00 +0000
76+++ src/identityprovider/oops_config.py 2013-08-07 15:56:25 +0000
77@@ -0,0 +1,10 @@
78+import oops_timeline
79+import timeline_django.filters
80+
81+from identityprovider import timeline_filters
82+
83+
84+def install_timeline_hooks(config):
85+ oops_timeline.install_hooks(config)
86+ timeline_django.filters.install_hooks(config)
87+ timeline_filters.install_hooks(config)
88
89=== added file 'src/identityprovider/tests/test_oops.py'
90--- src/identityprovider/tests/test_oops.py 1970-01-01 00:00:00 +0000
91+++ src/identityprovider/tests/test_oops.py 2013-08-07 15:56:25 +0000
92@@ -0,0 +1,26 @@
93+import oops
94+import timeline as mod_timeline
95+from unittest import TestCase
96+
97+from identityprovider import oops_config
98+
99+
100+class OopsTests(TestCase):
101+
102+ def test_timeline_filters_sensitive(self):
103+ reports = []
104+
105+ def capture(report):
106+ reports.append(report)
107+ return []
108+ config = oops.Config()
109+ oops_config.install_timeline_hooks(config)
110+ config.publisher = capture
111+ timeline = mod_timeline.Timeline()
112+ timeline.start('SQL-master', 'SELECT * from accountpassword').finish()
113+ report = config.create(context=dict(timeline=timeline))
114+ config.publish(report)
115+ self.assertEqual(1, len(reports))
116+ report = reports[0]
117+ self.assertEqual('SELECT <accountpassword query redacted>',
118+ report['timeline'][0][3])
119
120=== added file 'src/identityprovider/timeline_filters.py'
121--- src/identityprovider/timeline_filters.py 1970-01-01 00:00:00 +0000
122+++ src/identityprovider/timeline_filters.py 2013-08-07 15:56:25 +0000
123@@ -0,0 +1,36 @@
124+# Copyright 2013 Canonical Ltd. This software is licensed under the
125+# GNU Affero General Public License version 3 (see the file LICENSE).
126+
127+from timeline_django import filters
128+
129+
130+def filter_table(table_name, reason):
131+ def do_filter(query):
132+ return filters._filter_table(query, table_name, reason)
133+
134+ def filter_query(report, context):
135+ return filters._filter_query(report, do_filter)
136+ return filter_query
137+
138+
139+def install_hooks(config):
140+ # Filter queries for tables that contain sensitive information
141+ config.on_create.append(
142+ filter_table('accountpassword', 'accountpassword'))
143+ config.on_create.append(
144+ filter_table('api_user', 'api_user'))
145+ config.on_create.append(
146+ filter_table('authtoken', 'authtoken'))
147+ config.on_create.append(
148+ filter_table('identityprovider_authenticationdevice',
149+ 'authenticationdevice'))
150+ config.on_create.append(
151+ filter_table('oauth_consumer', 'oauth_consumer'))
152+ config.on_create.append(
153+ filter_table('oauth_token', 'oauth_token'))
154+ config.on_create.append(
155+ filter_table('openidauthorization', 'openidauthorization'))
156+ config.on_create.append(
157+ filter_table('piston_consumer', 'piston_consumer'))
158+ config.on_create.append(
159+ filter_table('piston_token', 'piston_token'))