示例#1
0
 def get(self):
     """
     Return a list of GitHub organizations avaiable to the current user.
     """
     user = auth.get_current_user()
     provider = GitHubRepositoryProvider()
     return provider.get_owners(user)
示例#2
0
def sync_github_access(user_id: UUID):
    user = User.query.get(user_id)
    if not user:
        return

    provider = GitHubRepositoryProvider(cache=True)
    owner_list = [o["name"] for o in provider.get_owners(user)]
    # for each owner list, we need to see if there are any matching repos
    if owner_list:
        for owner_name in owner_list:
            sync_repos_for_owner(provider, user, owner_name)
            db.session.commit()
示例#3
0
    def get(self):
        """
        Return a list of GitHub repositories avaiable to the current user.
        """
        no_cache = request.args.get("noCache") in ("1", "true")
        include_private = request.args.get("private") in ("1", "true")
        owner_name = request.args.get("orgName")
        user = auth.get_current_user()
        provider = GitHubRepositoryProvider(cache=not no_cache)
        try:
            repo_list = provider.get_repos_for_owner(
                user=user,
                owner_name=owner_name,
                include_private_repos=include_private)
        except IdentityNeedsUpgrade as exc:
            return self.respond(
                {
                    "provider": "github",
                    "error": "identity_needs_upgrade",
                    "url": exc.get_upgrade_url(),
                },
                401,
            )

        known_repo_ids = {
            r[0]: r[1].name
            for r in db.session.query(
                Repository.external_id, Repository.status).join(
                    RepositoryAccess, RepositoryAccess.repository_id ==
                    Repository.id).filter(
                        Repository.provider == RepositoryProvider.github,
                        RepositoryAccess.user_id == user.id,
                    )
        }

        return [{
            "name": r["config"]["full_name"],
            "permissions": {
                "read": Permission.read in r["permission"],
                "write": Permission.write in r["permission"],
                "admin": Permission.admin in r["permission"],
            },
            "status": known_repo_ids.get(str(r["id"])),
        } for r in repo_list]
示例#4
0
def grant_access_to_existing_repos(user):
    provider = GitHubRepositoryProvider(cache=True)
    owner_list = [o['name'] for o in provider.get_owners(user)]
    if owner_list:
        matching_repos = Repository.query.unrestricted_unsafe().filter(
            Repository.provider == RepositoryProvider.github,
            Repository.owner_name.in_(owner_list), ~Repository.id.in_(
                db.session.query(RepositoryAccess.repository_id, ).filter(
                    RepositoryAccess.user_id == user.id, )))
        for repo in matching_repos:
            if provider.has_access(auth.get_current_user(), repo):
                try:
                    with db.session.begin_nested():
                        db.session.add(
                            RepositoryAccess(
                                repository_id=repo.id,
                                user_id=user.id,
                            ))
                        db.session.flush()
                except IntegrityError:
                    pass
            db.session.commit()
示例#5
0
    def get(self):
        """
        Return a list of GitHub repositories avaiable to the current user.
        """
        no_cache = request.args.get('noCache') in ('1', 'true')
        include_private = request.args.get('private') in ('1', 'true')
        owner_name = request.args.get('orgName')
        user = auth.get_current_user()
        provider = GitHubRepositoryProvider(cache=not no_cache)
        try:
            repo_list = provider.get_repos_for_owner(
                user=user,
                owner_name=owner_name,
                include_private_repos=include_private)
        except IdentityNeedsUpgrade as exc:
            return self.respond(
                {
                    'provider': 'github',
                    'error': 'identity_needs_upgrade',
                    'url': exc.get_upgrade_url(),
                }, 401)

        active_repo_ids = frozenset(
            r[0] for r in db.session.query(Repository.external_id).join(
                RepositoryAccess,
                RepositoryAccess.repository_id == Repository.id,
            ).filter(
                Repository.provider == RepositoryProvider.github,
                RepositoryAccess.user_id == user.id,
            ))

        return [{
            'name': r['name'],
            'admin': r['admin'],
            'active': str(r['id']) in active_repo_ids,
        } for r in repo_list]
示例#6
0
def sync_repos_for_owner(
    provider: GitHubRepositoryProvider, user: User, owner_name: str
):
    repo_permissions = {
        r["name"]: r["permission"]
        for r in provider.get_repos_for_owner(user, owner_name)
    }

    if not repo_permissions:
        remove_access_to_owner_repos(user.id, owner_name)
        return

    # first clear any access to repos which are no longer part of the organization
    remove_access_to_owner_repos(
        user.id, owner_name, ~Repository.name.in_(repo_permissions.keys())
    )

    # now identify any repos which might need access granted or updated
    matches = list(
        Repository.query.unrestricted_unsafe().filter(
            Repository.provider == RepositoryProvider.github,
            Repository.owner_name == owner_name,
            Repository.name.in_(repo_permissions.keys()),
        )
    )

    for repo in matches:
        permission = repo_permissions.get(repo.name)
        if permission:
            create_or_update(
                RepositoryAccess,
                where={"repository_id": repo.id, "user_id": user.id},
                values={"permission": permission},
            )
        else:
            # revoke permissions -- this path shouldnt really get hit
            RepositoryAccess.query.filter(
                RepositoryAccess.repository_id == repo.id,
                RepositoryAccess.user_id == user.id,
            ).delete()
示例#7
0
    def post(self):
        """
        Activate a GitHub repository.
        """
        repo_name = (request.get_json() or {}).get('name')
        if not repo_name:
            return self.error('missing repo_name parameter')

        owner_name, repo_name = repo_name.split('/', 1)

        user = auth.get_current_user()
        provider = GitHubRepositoryProvider(cache=False)
        try:
            repo_data = provider.get_repo(user=user,
                                          owner_name=owner_name,
                                          repo_name=repo_name)
        except IdentityNeedsUpgrade as exc:
            return self.respond(
                {
                    'provider': 'github',
                    'error': 'identity_needs_upgrade',
                    'url': exc.get_upgrade_url(),
                }, 401)

        if not repo_data['admin']:
            return self.respond(
                {
                    'message':
                    'Insufficient permissions to activate repository',
                }, 403)

        lock_key = 'repo:{provider}/{owner_name}/{repo_name}'.format(
            provider='github',
            owner_name=owner_name,
            repo_name=repo_name,
        )
        with redis.lock(lock_key):
            try:
                with db.session.begin_nested():
                    # bind various github specific attributes
                    repo = Repository(
                        backend=RepositoryBackend.git,
                        provider=RepositoryProvider.github,
                        status=RepositoryStatus.active,
                        external_id=str(repo_data['id']),
                        owner_name=owner_name,
                        name=repo_name,
                        url=repo_data['url'],
                        data=repo_data['config'],
                    )
                    db.session.add(repo)
                    db.session.flush()
            except IntegrityError:
                repo = Repository.query.unrestricted_unsafe().filter(
                    Repository.provider == RepositoryProvider.github,
                    Repository.external_id == str(repo_data['id']),
                ).first()
                # it's possible to get here if the "full name" already exists
                assert repo
                needs_configured = repo.status == RepositoryStatus.inactive
                if needs_configured:
                    repo.status = RepositoryStatus.active
                    db.session.add(repo)
            else:
                needs_configured = True
            if needs_configured:
                # generate a new private key for use on github
                key = ssh.generate_key()
                db.session.add(
                    ItemOption(
                        item_id=repo.id,
                        name='auth.private-key',
                        value=key.private_key,
                    ))

                # register key with github
                provider.add_key(
                    user=user,
                    repo_name=repo_name,
                    owner_name=owner_name,
                    key=key,
                )

                # we need to commit before firing off the task
                db.session.commit()

                import_repo.delay(repo_id=repo.id)

        try:
            with db.session.begin_nested():
                db.session.add(
                    RepositoryAccess(
                        repository_id=repo.id,
                        user_id=user.id,
                    ))
                db.session.flush()
        except IntegrityError:
            pass

        db.session.commit()

        return self.respond_with_schema(repo_schema, repo, 201)
示例#8
0
    def post(self):
        """
        Activate a GitHub repository.
        """
        repo_name = (request.get_json() or {}).get("name")
        if not repo_name:
            return self.error("missing repo_name parameter")

        owner_name, repo_name = repo_name.split("/", 1)

        user = auth.get_current_user()
        provider = GitHubRepositoryProvider(cache=False)
        try:
            repo_data = provider.get_repo(user=user,
                                          owner_name=owner_name,
                                          repo_name=repo_name)
        except IdentityNeedsUpgrade as exc:
            return self.respond(
                {
                    "provider": "github",
                    "error": "identity_needs_upgrade",
                    "url": exc.get_upgrade_url(),
                },
                401,
            )

        if Permission.admin not in repo_data["permission"]:
            return self.respond(
                {"message": "Insufficient permissions to activate repository"},
                403)

        lock_key = Repository.get_lock_key(RepositoryProvider.github,
                                           owner_name, repo_name)
        with redis.lock(lock_key):
            try:
                with db.session.begin_nested():
                    # bind various github specific attributes
                    repo = Repository(
                        backend=RepositoryBackend.git,
                        provider=RepositoryProvider.github,
                        status=RepositoryStatus.active,
                        external_id=str(repo_data["id"]),
                        owner_name=owner_name,
                        name=repo_name,
                        url=repo_data["url"],
                        data=repo_data["config"],
                    )
                    db.session.add(repo)
                    db.session.flush()
            except IntegrityError:
                repo = (Repository.query.unrestricted_unsafe().filter(
                    Repository.provider == RepositoryProvider.github,
                    Repository.external_id == str(repo_data["id"]),
                ).first())
                # it's possible to get here if the "full name" already exists
                assert repo
                needs_configured = repo.status == RepositoryStatus.inactive
                if needs_configured:
                    repo.status = RepositoryStatus.active
                    db.session.add(repo)
            else:
                needs_configured = True
            if needs_configured:
                # generate a new private key for use on github
                key = ssh.generate_key()
                db.session.add(
                    ItemOption(item_id=repo.id,
                               name="auth.private-key",
                               value=key.private_key))

                # register key with github
                # TODO(dcramer): we should store this key reference so we can delete it
                # when the user deactivates the repo
                provider.add_key(user=user,
                                 repo_name=repo_name,
                                 owner_name=owner_name,
                                 key=key)

                db.session.commit()

        try:
            with db.session.begin_nested():
                db.session.add(
                    RepositoryAccess(
                        repository_id=repo.id,
                        user_id=user.id,
                        permission=repo_data["permission"],
                    ))
                db.session.flush()
        except IntegrityError:
            pass

        db.session.commit()

        return self.respond_with_schema(repo_schema, repo, 201)