1""" 

2switch to new ACL implementation and add pre-suite NEW 

3 

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""" 

8 

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. 

13 

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. 

18 

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 

22 

23################################################################################ 

24 

25import psycopg2 

26from daklib.dak_exceptions import DBUpdateError 

27from daklib.config import Config 

28 

29statements = [ 

30"""ALTER TABLE suite ADD COLUMN new_queue_id INT REFERENCES policy_queue(id)""", 

31 

32"""CREATE TABLE acl ( 

33 id SERIAL PRIMARY KEY NOT NULL, 

34 name TEXT NOT NULL, 

35 is_global BOOLEAN NOT NULL DEFAULT 'f', 

36 

37 match_fingerprint BOOLEAN NOT NULL DEFAULT 'f', 

38 match_keyring_id INTEGER REFERENCES keyrings(id), 

39 

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 )""", 

49 

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 )""", 

55 

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 )""", 

61 

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 )""", 

69 

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] 

76 

77################################################################################ 

78 

79 

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() 

88 

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] 

93 

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() 

100 

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}) 

106 

107 return acl_id 

108 

109 

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 

117 

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 

124 

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) 

131 

132 raise Exception('Cannot convert ACL combination automatically: binary_acl={0}, source_acl={1}'.format(binary_acl, source_acl)) 

133 

134 

135def do_update(self): 

136 print(__doc__) 

137 try: 

138 cnf = Config() 

139 

140 c = self.db.cursor() 

141 

142 for stmt in statements: 

143 c.execute(stmt) 

144 

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() 

151 

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() 

158 

159 # convert per-fingerprint ACLs 

160 

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""") 

173 

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""") 

185 

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") 

190 

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.") 

209 

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") 

213 

214 c.execute("UPDATE config SET value = '83' WHERE name = 'db_revision'") 

215 self.db.commit() 

216 

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))