1"""
2switch to new ACL implementation and add pre-suite NEW
4@contact: Debian FTP Master <ftpmaster@debian.org>
5@copyright: 2012 Ansgar Burchardt <ansgar@debian.org>
6@license: GNU General Public License version 2 or later
7"""
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23################################################################################
25import psycopg2
26from daklib.dak_exceptions import DBUpdateError
27from daklib.config import Config
29statements = [
30"""ALTER TABLE suite ADD COLUMN new_queue_id INT REFERENCES policy_queue(id)""",
32"""CREATE TABLE acl (
33 id SERIAL PRIMARY KEY NOT NULL,
34 name TEXT NOT NULL,
35 is_global BOOLEAN NOT NULL DEFAULT 'f',
37 match_fingerprint BOOLEAN NOT NULL DEFAULT 'f',
38 match_keyring_id INTEGER REFERENCES keyrings(id),
40 allow_new BOOLEAN NOT NULL DEFAULT 'f',
41 allow_source BOOLEAN NOT NULL DEFAULT 'f',
42 allow_binary BOOLEAN NOT NULL DEFAULT 'f',
43 allow_binary_all BOOLEAN NOT NULL DEFAULT 'f',
44 allow_binary_only BOOLEAN NOT NULL DEFAULT 'f',
45 allow_hijack BOOLEAN NOT NULL DEFAULT 'f',
46 allow_per_source BOOLEAN NOT NULL DEFAULT 'f',
47 deny_per_source BOOLEAN NOT NULL DEFAULT 'f'
48 )""",
50"""CREATE TABLE acl_architecture_map (
51 acl_id INTEGER NOT NULL REFERENCES acl(id) ON DELETE CASCADE,
52 architecture_id INTEGER NOT NULL REFERENCES architecture(id) ON DELETE CASCADE,
53 PRIMARY KEY (acl_id, architecture_id)
54 )""",
56"""CREATE TABLE acl_fingerprint_map (
57 acl_id INTEGER NOT NULL REFERENCES acl(id) ON DELETE CASCADE,
58 fingerprint_id INTEGER NOT NULL REFERENCES fingerprint(id) ON DELETE CASCADE,
59 PRIMARY KEY (acl_id, fingerprint_id)
60 )""",
62"""CREATE TABLE acl_per_source (
63 acl_id INTEGER NOT NULL REFERENCES acl(id) ON DELETE CASCADE,
64 fingerprint_id INTEGER NOT NULL REFERENCES fingerprint(id) ON DELETE CASCADE,
65 source TEXT NOT NULL,
66 reason TEXT,
67 PRIMARY KEY (acl_id, fingerprint_id, source)
68 )""",
70"""CREATE TABLE suite_acl_map (
71 suite_id INTEGER NOT NULL REFERENCES suite(id) ON DELETE CASCADE,
72 acl_id INTEGER NOT NULL REFERENCES acl(id),
73 PRIMARY KEY (suite_id, acl_id)
74 )""",
75]
77################################################################################
80def get_buildd_acl_id(c, keyring_id):
81 c.execute("""
82 SELECT 'buildd-' || STRING_AGG(a.arch_string, '+' ORDER BY a.arch_string)
83 FROM keyring_acl_map kam
84 JOIN architecture a ON kam.architecture_id = a.id
85 WHERE kam.keyring_id = %(keyring_id)s
86 """, {'keyring_id': keyring_id})
87 acl_name, = c.fetchone()
89 c.execute('SELECT id FROM acl WHERE name = %(acl_name)s', {'acl_name': acl_name})
90 row = c.fetchone()
91 if row is not None:
92 return row[0]
94 c.execute("""
95 INSERT INTO acl
96 ( name, allow_new, allow_source, allow_binary, allow_binary_all, allow_binary_only, allow_hijack)
97 VALUES (%(acl_name)s, 't', 'f', 't', 'f', 't', 't')
98 RETURNING id""", {'acl_name': acl_name})
99 acl_id, = c.fetchone()
101 c.execute("""INSERT INTO acl_architecture_map (acl_id, architecture_id)
102 SELECT %(acl_id)s, architecture_id
103 FROM keyring_acl_map
104 WHERE keyring_id = %(keyring_id)s""",
105 {'acl_id': acl_id, 'keyring_id': keyring_id})
107 return acl_id
110def get_acl_id(c, acl_dd, acl_dm, keyring_id, source_acl_id, binary_acl_id):
111 c.execute('SELECT access_level FROM source_acl WHERE id = %(source_acl_id)s', {'source_acl_id': source_acl_id})
112 row = c.fetchone()
113 if row is not None: 113 ↛ 116line 113 didn't jump to line 116, because the condition on line 113 was never false
114 source_acl = row[0]
115 else:
116 source_acl = None
118 c.execute('SELECT access_level FROM binary_acl WHERE id = %(binary_acl_id)s', {'binary_acl_id': binary_acl_id})
119 row = c.fetchone()
120 if row is not None: 120 ↛ 123line 120 didn't jump to line 123, because the condition on line 120 was never false
121 binary_acl = row[0]
122 else:
123 binary_acl = None
125 if source_acl == 'full' and binary_acl == 'full': 125 ↛ 127line 125 didn't jump to line 127, because the condition on line 125 was never false
126 return acl_dd
127 elif source_acl == 'dm' and binary_acl == 'full':
128 return acl_dm
129 elif source_acl is None and binary_acl == 'map':
130 return get_buildd_acl_id(c, keyring_id)
132 raise Exception('Cannot convert ACL combination automatically: binary_acl={0}, source_acl={1}'.format(binary_acl, source_acl))
135def do_update(self):
136 print(__doc__)
137 try:
138 cnf = Config()
140 c = self.db.cursor()
142 for stmt in statements:
143 c.execute(stmt)
145 c.execute("""
146 INSERT INTO acl
147 (name, allow_new, allow_source, allow_binary, allow_binary_all, allow_binary_only, allow_hijack)
148 VALUES ('dd', 't', 't', 't', 't', 't', 't')
149 RETURNING id""")
150 acl_dd, = c.fetchone()
152 c.execute("""
153 INSERT INTO acl
154 (name, allow_new, allow_source, allow_binary, allow_binary_all, allow_binary_only, allow_per_source, allow_hijack)
155 VALUES ('dm', 'f', 't', 't', 't', 'f', 't', 'f')
156 RETURNING id""")
157 acl_dm, = c.fetchone()
159 # convert per-fingerprint ACLs
161 c.execute('ALTER TABLE fingerprint ADD COLUMN acl_id INTEGER REFERENCES acl(id)')
162 c.execute("""SELECT id, keyring, source_acl_id, binary_acl_id
163 FROM fingerprint
164 WHERE source_acl_id IS NOT NULL OR binary_acl_id IS NOT NULL""")
165 for fingerprint_id, keyring_id, source_acl_id, binary_acl_id in c.fetchall(): 165 ↛ 166line 165 didn't jump to line 166, because the loop on line 165 never started
166 acl_id = get_acl_id(c, acl_dd, acl_dm, keyring_id, source_acl_id, binary_acl_id)
167 c.execute('UPDATE fingerprint SET acl_id = %(acl_id)s WHERE id = %(fingerprint_id)s',
168 {'acl_id': acl_id, 'fingerprint_id': fingerprint_id})
169 c.execute("""ALTER TABLE fingerprint
170 DROP COLUMN source_acl_id,
171 DROP COLUMN binary_acl_id,
172 DROP COLUMN binary_reject""")
174 # convert per-keyring ACLs
175 c.execute('ALTER TABLE keyrings ADD COLUMN acl_id INTEGER REFERENCES acl(id)')
176 c.execute('SELECT id, default_source_acl_id, default_binary_acl_id FROM keyrings')
177 for keyring_id, source_acl_id, binary_acl_id in c.fetchall():
178 acl_id = get_acl_id(c, acl_dd, acl_dm, keyring_id, source_acl_id, binary_acl_id)
179 c.execute('UPDATE keyrings SET acl_id = %(acl_id)s WHERE id = %(keyring_id)s',
180 {'acl_id': acl_id, 'keyring_id': keyring_id})
181 c.execute("""ALTER TABLE keyrings
182 DROP COLUMN default_source_acl_id,
183 DROP COLUMN default_binary_acl_id,
184 DROP COLUMN default_binary_reject""")
186 c.execute("DROP TABLE keyring_acl_map")
187 c.execute("DROP TABLE binary_acl_map")
188 c.execute("DROP TABLE binary_acl")
189 c.execute("DROP TABLE source_acl")
191 # convert upload blocks
192 c.execute("""
193 INSERT INTO acl
194 ( name, is_global, allow_new, allow_source, allow_binary, allow_binary_all, allow_hijack, allow_binary_only, deny_per_source)
195 VALUES ('blocks', 't', 't', 't', 't', 't', 't', 't', 't')
196 RETURNING id""")
197 acl_block, = c.fetchone()
198 c.execute("SELECT source, fingerprint_id, reason FROM upload_blocks")
199 for source, fingerprint_id, reason in c.fetchall(): 199 ↛ 200line 199 didn't jump to line 200, because the loop on line 199 never started
200 if fingerprint_id is None:
201 raise Exception(
202 "ERROR: upload blocks based on uid are no longer supported\n"
203 "=========================================================\n"
204 "\n"
205 "dak now only supports upload blocks based on fingerprints. Please remove\n"
206 "any uid-specific block by running\n"
207 " DELETE FROM upload_blocks WHERE fingerprint_id IS NULL\n"
208 "and try again.")
210 c.execute('INSERT INTO acl_match_source_map (acl_id, fingerprint_id, source, reason) VALUES (%(acl_id)s, %(fingerprint_id)s, %(source)s, %(reason)s)',
211 {'acl_id': acl_block, 'fingerprint_id': fingerprint_id, 'source': source, 'reason': reason})
212 c.execute("DROP TABLE upload_blocks")
214 c.execute("UPDATE config SET value = '83' WHERE name = 'db_revision'")
215 self.db.commit()
217 except psycopg2.ProgrammingError as msg:
218 self.db.rollback()
219 raise DBUpdateError('Unable to apply sick update 83, rollback issued. Error message: {0}'.format(msg))