def delete(self, namespace_name, repository_name, manifestref, labelid): """ Deletes an existing label from a manifest. """ repo_ref = registry_model.lookup_repository(namespace_name, repository_name) if repo_ref is None: raise NotFound() manifest = registry_model.lookup_manifest_by_digest(repo_ref, manifestref) if manifest is None: raise NotFound() deleted = registry_model.delete_manifest_label(manifest, labelid) if deleted is None: raise NotFound() metadata = { "id": labelid, "key": deleted.key, "value": deleted.value, "manifest_digest": manifestref, "namespace": namespace_name, "repo": repository_name, } log_action("manifest_label_delete", namespace_name, metadata, repo_name=repository_name) return "", 204
def put(self, orgname, prototypeid): """ Update the role of an existing permission prototype. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): try: org = model.organization.get_organization(orgname) except model.InvalidOrganizationException: raise NotFound() existing = model.permission.get_prototype_permission( org, prototypeid) if not existing: raise NotFound() details = request.get_json() role_name = details["role"] prototype = model.permission.update_prototype_permission( org, prototypeid, role_name) if not prototype: raise NotFound() log_prototype_action("modify_prototype_permission", orgname, prototype, original_role=existing.role.name) users_filter = {prototype.activating_user, prototype.delegate_user} org_members = model.organization.get_organization_member_set( org, users_filter=users_filter) return prototype_view(prototype, org_members) raise Unauthorized()
def delete(self, orgname, teamname, email): """ Delete an invite of an email address to join a team. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): team = None # Find the team. try: team = model.team.get_organization_team(orgname, teamname) except model.InvalidTeamException: raise NotFound() # Delete the invite. if not model.team.delete_team_email_invite(team, email): raise NotFound() log_action( "org_delete_team_member_invite", orgname, { "email": email, "team": teamname, "member": email }, ) return "", 204 raise Unauthorized()
def get(self, namespace, repository, tag, parsed_args): """ List the images for the specified repository tag. """ repo_ref = registry_model.lookup_repository(namespace, repository) if repo_ref is None: raise NotFound() tag_ref = registry_model.get_repo_tag(repo_ref, tag, include_legacy_image=True) if tag_ref is None: raise NotFound() if tag_ref.legacy_image_if_present is None: return {"images": []} image_id = tag_ref.legacy_image.docker_image_id all_images = None if parsed_args["owned"]: # TODO: Remove the `owned` image concept once we are fully on V2_2. all_images = registry_model.get_legacy_images_owned_by_tag(tag_ref) else: image_with_parents = registry_model.get_legacy_image( repo_ref, image_id, include_parents=True) if image_with_parents is None: raise NotFound() all_images = [image_with_parents] + image_with_parents.parents return { "images": [image_dict(image) for image in all_images], }
def put(self, orgname, client_id): """ Updates an application under this organization. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): try: org = model.organization.get_organization(orgname) except model.InvalidOrganizationException: raise NotFound() application = model.oauth.lookup_application(org, client_id) if not application: raise NotFound() app_data = request.get_json() application.name = app_data['name'] application.application_uri = app_data['application_uri'] application.redirect_uri = app_data['redirect_uri'] application.description = app_data.get('description', '') application.avatar_email = app_data.get('avatar_email', None) application.save() app_data.update({ 'application_name': application.name, 'client_id': application.client_id }) log_action('update_application', orgname, app_data) return app_view(application) raise Unauthorized()
def post(self, orgname, client_id): """ Resets the client secret of the application. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): try: org = model.organization.get_organization(orgname) except model.InvalidOrganizationException: raise NotFound() application = model.oauth.lookup_application(org, client_id) if not application: raise NotFound() application = model.oauth.reset_client_secret(application) log_action( "reset_application_client_secret", orgname, { "application_name": application.name, "client_id": client_id }, ) return app_view(application) raise Unauthorized()
def delete(self, orgname, client_id): """ Deletes the application under this organization. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): try: org = model.organization.get_organization(orgname) except model.InvalidOrganizationException: raise NotFound() application = model.oauth.delete_application(org, client_id) if not application: raise NotFound() log_action( "delete_application", orgname, { "application_name": application.name, "client_id": client_id }, ) return "", 204 raise Unauthorized()
def post(self, namespace_name, repo_name, trigger_uuid): """ Analyze the specified build trigger configuration. """ trigger = get_trigger(trigger_uuid) if trigger.repository.namespace_user.username != namespace_name: raise NotFound() if trigger.repository.name != repo_name: raise NotFound() new_config_dict = request.get_json()["config"] handler = BuildTriggerHandler.get_handler(trigger, new_config_dict) server_hostname = app.config["SERVER_HOSTNAME"] try: trigger_analyzer = TriggerAnalyzer( handler, namespace_name, server_hostname, new_config_dict, AdministerOrganizationPermission(namespace_name).can(), ) return trigger_analyzer.analyze_trigger() except TriggerException as rre: return { "status": "error", "message": "Could not analyze the repository: %s" % rre.message, } except NotImplementedError: return { "status": "notimplemented", }
def get(self, namespace_name, repository_name): """ Return the Mirror configuration for a given Repository. """ repo = model.repository.get_repository(namespace_name, repository_name) if not repo: raise NotFound() mirror = model.repo_mirror.get_mirror(repo) if not mirror: raise NotFound() # Transformations rules = mirror.root_rule.rule_value username = self._decrypt_username(mirror.external_registry_username) sync_start_date = self._dt_to_string(mirror.sync_start_date) sync_expiration_date = self._dt_to_string(mirror.sync_expiration_date) robot = mirror.internal_robot.username if mirror.internal_robot is not None else None return { 'is_enabled': mirror.is_enabled, 'mirror_type': mirror.mirror_type.name, 'external_reference': mirror.external_reference, 'external_registry_username': username, 'external_registry_config': mirror.external_registry_config or {}, 'sync_interval': mirror.sync_interval, 'sync_start_date': sync_start_date, 'sync_expiration_date': sync_expiration_date, 'sync_retries_remaining': mirror.sync_retries_remaining, 'sync_status': mirror.sync_status.name, 'root_rule': { 'rule_kind': 'tag_glob_csv', 'rule_value': rules }, 'robot_username': robot, }
def post(self, namespace_name, repository_name, manifestref): """ Adds a new label into the tag manifest. """ label_data = request.get_json() # Check for any reserved prefixes. if label_validator.has_reserved_prefix(label_data['key']): abort(400, message='Label has a reserved prefix') repo_ref = registry_model.lookup_repository(namespace_name, repository_name) if repo_ref is None: raise NotFound() manifest = registry_model.lookup_manifest_by_digest( repo_ref, manifestref) if manifest is None: raise NotFound() label = None try: label = registry_model.create_manifest_label( manifest, label_data['key'], label_data['value'], 'api', label_data['media_type']) except InvalidLabelKeyException: message = ('Label is of an invalid format or missing please ' + 'use %s format for labels' % VALID_LABEL_KEY_REGEX) abort(400, message=message) except InvalidMediaTypeException: message = 'Media type is invalid please use a valid media type: text/plain, application/json' abort(400, message=message) if label is None: raise NotFound() metadata = { 'id': label.uuid, 'key': label.key, 'value': label.value, 'manifest_digest': manifestref, 'media_type': label.media_type_name, 'namespace': namespace_name, 'repo': repository_name, } log_action('manifest_label_add', namespace_name, metadata, repo_name=repository_name) resp = {'label': _label_dict(label)} repo_string = '%s/%s' % (namespace_name, repository_name) headers = { 'Location': api.url_for(ManageRepositoryManifestLabel, repository=repo_string, manifestref=manifestref, labelid=label.uuid), } return resp, 201, headers
def get(self, namespace_name, repository_name, manifestref): repo_ref = registry_model.lookup_repository(namespace_name, repository_name) if repo_ref is None: raise NotFound() manifest = registry_model.lookup_manifest_by_digest(repo_ref, manifestref) if manifest is None: raise NotFound() return _manifest_dict(manifest)
def get(self, namespace, repository, manifestref, parsed_args): repo_ref = registry_model.lookup_repository(namespace, repository) if repo_ref is None: raise NotFound() manifest = registry_model.lookup_manifest_by_digest(repo_ref, manifestref, allow_dead=True) if manifest is None: raise NotFound() return _security_info(manifest, parsed_args.vulnerabilities)
def get(self, namespace, repository, imageid, parsed_args): """ Fetches the features and vulnerabilities (if any) for a repository image. """ repo_ref = registry_model.lookup_repository(namespace, repository) if repo_ref is None: raise NotFound() legacy_image = registry_model.get_legacy_image(repo_ref, imageid) if legacy_image is None: raise NotFound() return _security_info(legacy_image, parsed_args.vulnerabilities)
def get(self, namespace, repository, build_uuid): """ Returns information about a build. """ try: build = model.build.get_repository_build(build_uuid) except model.build.InvalidRepositoryBuildException: raise NotFound() if build.repository.name != repository or build.repository.namespace_user.username != namespace: raise NotFound() return build_status_view(build)
def get(self, orgname, membername): """ Retrieves the details of a member of the organization. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): # Lookup the user. member = model.user.get_user(membername) if not member: raise NotFound() organization = model.user.get_user_or_org(orgname) if not organization: raise NotFound() # Lookup the user's information in the organization. teams = list( model.team.get_user_teams_within_org(membername, organization)) if not teams: # 404 if the user is not a robot under the organization, as that means the referenced # user or robot is not a member of this organization. if not member.robot: raise NotFound() namespace, _ = parse_robot_username(member.username) if namespace != orgname: raise NotFound() repo_permissions = model.permission.list_organization_member_permissions( organization, member) def local_team_view(team): return { "name": team.name, "avatar": avatar.get_data_for_team(team), } return { "name": member.username, "kind": "robot" if member.robot else "user", "avatar": avatar.get_data_for_user(member), "teams": [local_team_view(team) for team in teams], "repositories": [ permission.repository.name for permission in repo_permissions ], } raise Unauthorized()
def post(self, namespace, repository, tag): """ Restores a repository tag back to a previous image in the repository. """ repo_ref = registry_model.lookup_repository(namespace, repository) if repo_ref is None: raise NotFound() # Restore the tag back to the previous image. image_id = request.get_json().get("image", None) manifest_digest = request.get_json().get("manifest_digest", None) if image_id is None and manifest_digest is None: raise InvalidRequest("Missing manifest_digest") # Data for logging the reversion/restoration. username = get_authenticated_user().username log_data = { "username": username, "repo": repository, "tag": tag, "image": image_id, "manifest_digest": manifest_digest, } manifest_or_legacy_image = None if manifest_digest is not None: manifest_or_legacy_image = registry_model.lookup_manifest_by_digest( repo_ref, manifest_digest, allow_dead=True, require_available=True) elif image_id is not None: manifest_or_legacy_image = registry_model.get_legacy_image( repo_ref, image_id) if manifest_or_legacy_image is None: raise NotFound() if not registry_model.retarget_tag( repo_ref, tag, manifest_or_legacy_image, storage, docker_v2_signing_key, is_reversion=True, ): raise InvalidRequest("Could not restore tag") log_action("revert_tag", namespace, log_data, repo_name=repository) return {}
def get(self, namespace, repository, image_id): """ Get the information available for the specified image. """ repo_ref = registry_model.lookup_repository(namespace, repository) if repo_ref is None: raise NotFound() image = registry_model.get_legacy_image(repo_ref, image_id, storage) if image is None: raise NotFound() return image_dict(image)
def get(self, namespace_name, repository_name, manifestref): repo_ref = registry_model.lookup_repository(namespace_name, repository_name) if repo_ref is None: raise NotFound() manifest = registry_model.lookup_manifest_by_digest(repo_ref, manifestref) # sub-manifests created via pull-thru proxy cache as part of a manifest list # pull will not contain the manifest bytes unless individually pulled. # to avoid a parsing error from `_manifest_dict`, we return a 404 either # when the manifest doesn't exist or if the manifest bytes are empty. if manifest is None or manifest.internal_manifest_bytes.as_unicode() == "": raise NotFound() return _manifest_dict(manifest)
def get(self, namespace_name, repository_name, manifestref, parsed_args): repo_ref = registry_model.lookup_repository(namespace_name, repository_name) if repo_ref is None: raise NotFound() manifest = registry_model.lookup_manifest_by_digest(repo_ref, manifestref) if manifest is None: raise NotFound() labels = registry_model.list_manifest_labels(manifest, parsed_args["filter"]) if labels is None: raise NotFound() return {"labels": [_label_dict(label) for label in labels]}
def delete(self, namespace, repository, build_uuid): """ Cancels a repository build. """ try: build = model.build.get_repository_build(build_uuid) except model.build.InvalidRepositoryBuildException: raise NotFound() if build.repository.name != repository or build.repository.namespace_user.username != namespace: raise NotFound() if model.build.cancel_repository_build(build, dockerfile_build_queue): return 'Okay', 201 else: raise InvalidRequest('Build is currently running or has finished')
def post(self, namespace_name, repository_name): """ Update the sync_status for a given Repository's mirroring configuration. """ repo = model.repository.get_repository(namespace_name, repository_name) if not repo: raise NotFound() mirror = model.repo_mirror.get_mirror(repository=repo) if not mirror: raise NotFound() if mirror and model.repo_mirror.update_sync_status_to_cancel(mirror): track_and_log('repo_mirror_config_changed', wrap_repository(repo), changed="sync_status", to="SYNC_CANCEL") return '', 204 raise NotFound()
def post(self, namespace, repository): """ Change the visibility of a repository. """ if not model.repo_exists(namespace, repository): raise NotFound() tags, _ = tuf_metadata_api.get_default_tags_with_expiration( namespace, repository) if tags and not tuf_metadata_api.delete_metadata( namespace, repository): raise DownstreamIssue("Unable to delete downstream trust metadata") values = request.get_json() model.set_trust(namespace, repository, values["trust_enabled"]) log_action( "change_repo_trust", namespace, { "repo": repository, "namespace": namespace, "trust_enabled": values["trust_enabled"] }, repo_name=repository, ) return {"success": True}
def put(self, orgname, teamname, email): """ Invites an email address to an existing team. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): team = None # Find the team. try: team = model.team.get_organization_team(orgname, teamname) except model.InvalidTeamException: raise NotFound() # Invite the email to the team. inviter = get_authenticated_user() invite = handle_addinvite_team(inviter, team, email=email) log_action( "org_invite_team_member", orgname, { "email": email, "team": teamname, "member": email }, ) return invite_view(invite) raise Unauthorized()
def get(self, uuid): note = model.notification.lookup_notification(get_authenticated_user(), uuid) if not note: raise NotFound() return notification_view(note)
def post(self, orgname): """ Creates a new application under this organization. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): try: org = model.organization.get_organization(orgname) except model.InvalidOrganizationException: raise NotFound() app_data = request.get_json() application = model.oauth.create_application( org, app_data["name"], app_data.get("application_uri", ""), app_data.get("redirect_uri", ""), description=app_data.get("description", ""), avatar_email=app_data.get("avatar_email", None), ) app_data.update({ "application_name": application.name, "client_id": application.client_id }) log_action("create_application", orgname, app_data) return app_view(application) raise Unauthorized()
def get(self, access_token_uuid): access_token = model.oauth.lookup_access_token_for_user( get_authenticated_user(), access_token_uuid) if not access_token: raise NotFound() return authorization_view(access_token)
def put(self, namespace, repository): """ Change the state of a repository. """ if not model.repo_exists(namespace, repository): raise NotFound() values = request.get_json() state_name = values['state'] try: state = RepositoryState[state_name] except KeyError: state = None if state == RepositoryState.MIRROR and not features.REPO_MIRROR: return {'detail': 'Unknown Repository State: %s' % state_name}, 400 if state is None: return { 'detail': '%s is not a valid Repository state.' % state_name }, 400 model.set_repository_state(namespace, repository, state) log_action('change_repo_state', namespace, { 'repo': repository, 'namespace': namespace, 'state_changed': state_name }, repo_name=repository) return {'success': True}
def post(self, kid): notes = request.get_json().get("notes", "") try: key = pre_oci_model.approve_service_key( kid, ServiceKeyApprovalType.SUPERUSER, notes=notes ) # Log the approval of the service key. key_log_metadata = { "kid": kid, "service": key.service, "name": key.name, "expiration_date": key.expiration_date, } # Note: this may not actually be the current person modifying the config, but if they're in the config tool, # they have full access to the DB and could pretend to be any user, so pulling any superuser is likely fine super_user = app.config.get("SUPER_USERS", [None])[0] log_action("service_key_approve", super_user, key_log_metadata) except ServiceKeyDoesNotExist: raise NotFound() except ServiceKeyAlreadyApproved: pass return make_response("", 201)
def get(self): """ List the invoices for the current user. """ user = get_authenticated_user() if not user.stripe_id: raise NotFound() return get_invoices(user.stripe_id)
def get(self): """ List the invoice fields for the current user. """ user = get_authenticated_user() if not user.stripe_id: raise NotFound() return {'fields': get_invoice_fields(user)[0]}