def delete(self, project_id, user_id): ''' Remove collaborator from project ''' collaborator = g.db.execute_one( """ SELECT role FROM collaborator WHERE user_id = %s AND project_id = %s LIMIT 1 """, [str(user_id), project_id]) # Give some warning if the specified user has been already removed # from the collaborators or has been never added there before if not collaborator: return OK('Specified user is not in collaborators list.') if collaborator[0] == 'Owner': abort(400, "It's not allowed to delete the owner of the project.") g.db.execute( """ DELETE FROM collaborator WHERE user_id = %s AND project_id = %s """, [str(user_id), project_id]) g.db.commit() opa_push_collaborator_data(g.db) return OK('Successfully removed user.')
def post(self, project_id): ''' Add a collaborator ''' b = request.get_json() username = b['username'] userrole = b['role'] if 'role' in b else 'Developer' # Prevent for now a project owner change # (Because with GitHub Integration the project owner's GitHub Token will be used) if userrole == 'Owner': abort(403, "A project is limited to one owner.") user = g.db.execute_one_dict( """ SELECT * FROM "user" WHERE username = %s """, [username]) if not user: abort(400, "User not found.") roles = g.db.execute_many(""" SELECT unnest(enum_range(NULL::user_role)) """) if [userrole] not in roles: abort(400, "Role unknown.") num_collaborators = g.db.execute_one( """ SELECT COUNT(*) FROM collaborator WHERE user_id = %s AND project_id = %s """, [user['id'], project_id])[0] if num_collaborators != 0: return OK('Specified user is already a collaborator.') g.db.execute( """ INSERT INTO collaborator (project_id, user_id, role) VALUES(%s, %s, %s) ON CONFLICT DO NOTHING """, [project_id, user['id'], userrole]) g.db.commit() opa_push_collaborator_data(g.db) return OK('Successfully added user.')
def put(self, project_id, user_id): collaborator = g.db.execute_one( """ SELECT role FROM collaborator WHERE user_id = %s AND project_id = %s LIMIT 1 """, [str(user_id), project_id]) if not collaborator: abort(400, 'Specified user is not in collaborators list.') if collaborator[0] == 'Owner': if count_owner(project_id) <= 1: abort(400, 'The project must have an owner.') if not is_valid_admin(project_id, g.token['user']['id']): abort(400, 'Not authorized to change owner') b = request.get_json() userrole = b['role'] # Ensure that role is valid roles = g.db.execute_many(""" SELECT unnest(enum_range(NULL::user_role)) """) if [userrole] not in roles: abort(400, "Role unknown.") # Do update g.db.execute( """ UPDATE collaborator SET role = %s WHERE user_id = %s AND project_id = %s """, [userrole, str(user_id), project_id]) g.db.commit() opa_push_collaborator_data(g.db) return OK('Successfully changed user role.')
def post(self): ''' Create new project ''' user_id = g.token['user']['id'] b = request.get_json() name = b['name'] typ = b['type'] private = b['private'] projects = g.db.execute_one_dict( ''' SELECT COUNT(*) as cnt FROM project p INNER JOIN collaborator co ON p.id = co.project_id AND co.user_id = %s ''', [user_id]) if projects['cnt'] > 50: abort(400, 'too many projects') project = g.db.execute_one_dict( ''' SELECT * FROM project WHERE name = %s ''', [name]) if project: abort(400, 'A project with this name already exists') if typ == 'github': github_repo_name = b.get('github_repo_name', None) if not github_repo_name: abort(400, 'github_repo_name not set') split = github_repo_name.split('/') owner = split[0] repo_name = split[1] user = g.db.execute_one_dict( ''' SELECT github_api_token FROM "user" WHERE id = %s ''', [user_id]) if not user: abort(404) api_token = user['github_api_token'] headers = { "Authorization": "token " + api_token, "User-Agent": "InfraBox" } url = '%s/repos/%s/%s' % (os.environ['INFRABOX_GITHUB_API_URL'], owner, repo_name) # TODO(ib-steffen): allow custom ca bundles r = requests.get(url, headers=headers, verify=False) if r.status_code != 200: abort(400, 'Failed to get github repo') repo = r.json() if not repo['permissions']['admin']: abort(400, 'You are not allowed to connect this repo') r = g.db.execute_one_dict( ''' SELECT * FROM repository WHERE github_id = %s ''', [repo['id']]) if r: abort('Repo already connected') project = g.db.execute_one_dict( ''' INSERT INTO project (name, type, public) VALUES (%s, %s, %s) RETURNING id ''', [name, typ, not private]) project_id = project['id'] g.db.execute( ''' INSERT INTO collaborator (user_id, project_id, role) VALUES (%s, %s, 'Owner') ''', [user_id, project_id]) if typ == 'github': split = github_repo_name.split('/') owner = split[0] repo_name = split[1] clone_url = repo['clone_url'] if repo['private']: clone_url = repo['ssh_url'] g.db.execute( ''' INSERT INTO repository (name, html_url, clone_url, github_id, private, project_id, github_owner) VALUES (%s, %s, %s, %s, %s, %s, %s) ''', [ repo['name'], repo['html_url'], clone_url, repo['id'], repo['private'], project_id, repo['owner']['login'] ]) insecure_ssl = "0" if os.environ[ 'INFRABOX_GENERAL_DONT_CHECK_CERTIFICATES'] == 'true': insecure_ssl = "1" webhook_config = { 'name': "web", 'active': True, 'events': ["create", "delete", "public", "pull_request", "push"], 'config': { 'url': get_root_url('global') + '/github/hook', 'content_type': "json", 'secret': os.environ['INFRABOX_GITHUB_WEBHOOK_SECRET'], 'insecure_ssl': insecure_ssl } } headers = { "Authorization": "token " + api_token, "User-Agent": "InfraBox" } url = '%s/repos/%s/%s/hooks' % ( os.environ['INFRABOX_GITHUB_API_URL'], owner, repo_name) # TODO(ib-steffen): allow custom ca bundles r = requests.post(url, headers=headers, json=webhook_config, verify=False) if r.status_code != 201: abort(400, 'Failed to create github webhook') hook = r.json() g.db.execute( ''' UPDATE repository SET github_hook_id = %s WHERE github_id = %s ''', [hook['id'], repo['id']]) # deploy key key = RSA.generate(2048) private_key = key.exportKey('PEM') public_key = key.publickey().exportKey('OpenSSH') deploy_key_config = { 'title': "InfraBox", 'key': public_key, 'read_only': True } url = '%s/repos/%s/%s/keys' % ( os.environ['INFRABOX_GITHUB_API_URL'], owner, repo_name) # TODO(ib-steffen): allow custom ca bundles r = requests.post(url, headers=headers, json=deploy_key_config, verify=False) if r.status_code != 201: abort(400, 'Failed to create deploy key') g.db.execute( ''' UPDATE repository SET private_key = %s WHERE github_id = %s ''', [private_key, repo['id']]) elif typ == 'gerrit': g.db.execute( ''' INSERT INTO repository (name, private, project_id, html_url, clone_url, github_id) VALUES (%s, false, %s, '', '', 0) ''', [name, project_id]) g.db.commit() # Push updated collaborator and project data to Open Policy Agent opa_push_project_data(g.db) opa_push_collaborator_data(g.db) return OK('Project added')