Provide fine-grained push access to GitHub from a JupyterHub

Overview

github-app-user-auth

Provide fine-grained push access to GitHub from a JupyterHub.

Goals

  1. Allow users on a JupyterHub to grant push access to only specific repositories rather than all the repositories they have access to.
  2. Do not store long-term credentials (like personal access tokens or ssh-keys) on disk, as they may get archived / fall into the wrong hands in the future.
  3. Allow GitHub organization admins visibility and control over what repos users can push to from remote systems (like JupyterHub or a shared cluster), where other admins of the remote system might be able to access the files of users with push access to repos. This has serious implications for supply chain security, as credentials might be stolen or lost and serious vulnerabilities be pushed to the repo.

These goals are accomplished by:

  1. Creating a GitHub app specific to the remote service (JupyterHub, HPC cluster, etc). Users and GitHub organization admins can then provide fine grained, repo level access to this GitHub app - Users can only push to repos that have the app installed.
  2. A commandline tool (github-app-user-auth) that lets specific users authorize push access to the selected repositories temporarily - a token that expires after 8 hours.

In the future, an optional web app might also be provided to aid in authentication.

Installation

You can install github-app-user-auth from PyPI.

pip install github-app-user-auth

GitHub App configuration

  1. Create a GitHub app for use by the service (JupyterHub, HPC cluster, etc). You can either create it under your personal account, or preferably under a GitHub organization account (Go to Settings -> Developer Settings -> GitHub Apps -> New GitHub app from the organization's GitHub page).

  2. Give it a descriptive name and description, as your users will see this when they authenticate. Provide a link to a descriptive page explaining your service (if you are using a JupyterHub, this could be just your JupyterHub URL).

  3. Disable webhooks (uncheck the 'Active' checkbox under 'Webhooks'). All other textboxes can be left empty.

  4. Under 'Repository permissions', select 'Read & write' for 'Contents'. This will provide users authenticating via the app just enough permissions to push and pull from repositories.

  5. Under 'Where can this GitHub App be installed?', select 'Any account'. This will enable users to push to their own user repositories or other organization repositaries, rather than just the repos of the user or organization owning this GitHub app.

  6. Save the Client ID provided in the information page of the app. You'll need this in the client. Save the Public link as well, as users will need to use this to grant access to particular repositories.

Client configuration

  1. github-app-user-auth uses git-credentials-store to provide appropriate authentication, by writing to a /tmp/github-app-git-credentials file. This makes sure we don't override the default ~/.git-credentials file someone might be using. git will have to be configured to use the new file.

    You can put the following snippet in /etc/gitconfig (for containers) or in ~/.gitconfig:

    [credential]
        helper = store --file=/tmp/github-app-git-credentials

    Or you can run the following command (this puts it in ~/.gitconfig)

    git config --global credential.helper "store --file=/tmp/github-app-git-credentials"
    
  2. github-app-user-auth will need to know the "Client ID" of the created GitHub app to perform authentication. This can be either set with the environment variable GITHUB_APP_CLIENT_ID, or be passed in as a commandline parameter --client-id to the github-app-user-auth script when users use it to authenticate.

Usage

Grant access to the GitHub app

Users will first need to go to the public page of the GitHub app, and 'Install' the app on their account and in organizations with repos they want to push to. We highly recommend allowing access only to selected repositories, and explicitly select the repositories this hosted service (JupyterHub, HPC cluster, etc) should be able to push to. You can modify this list afterwards, to make sure you only grant the required permissions.

Given the common usage pattern where you are only pushing to a limited set of repositories from a particular hosted service, this should hopefully not be too cumborsome.

Authenticate to GitHub

The hosted service must have github-app-user-auth installed.

  1. Open a terminal, and type github-app-user-auth.
  2. It should give you a link to go to, and a code to input into the web page when that link is opened. Open the link, enter the code there.
  3. Grant access to the device in the web page, and you're done!

Authentication is valid for 8 hours, and once it expires, this process will need to be repeated. In the future, we might have a web app or other process to make this less painful. However, keeping the length of this session limited drastically helps with security too.

Alternatives

  1. Create an ssh key specifically for the hosted service (JupyterHub, HPC cluster, etc) and add it to your GitHub account. If the key doesn't have a passphrase, this is very insecure - anyone who can exfiltrate your key once can keep it and use it whenever they wish. Even with a passphrase, the key can still be exfiltrated and passphrase stolen when used. There's also no way to restrict which repositories this can push to, which is a big issue.

  2. Create a Personal Access Token and use that. This is a little more insecure than the ssh key, as it can be used to make requests on your behalf too after being stolen! There is also no way to restrict which repositories you can push to.

  3. Create a GitHub deploy key for each repository you want to push to, for each hosted service you want to push from. While this lets you control which repos this ssh key can access, it is still stored long term at risk and can be exfiltrated.

Comments
  • Blank creds file despite success reported in the UI

    Blank creds file despite success reported in the UI

    This week, since updating to your branch after the merge of my PR, I've seen a few times a failure I'd never encountered before. I run through the standard sequence, it reports success (green box, etc), but the creds file is empty:

    (base) jupyter-fernando-2eperez[~]> cat /tmp/github-app-git-credentials 
    (base) jupyter-fernando-2eperez[~]> d /tmp/github-app-git-credentials 
    /home/jovyan
    -rw------- 1 jovyan 0 Apr 23 06:01 /tmp/github-app-git-credentials
    

    and obviously it doesn't actually work.

    I had to run it again, and interestingly, when I looked, the creds file was actually empty at first, though a few seconds later it appeared with data:

    (base) jupyter-fernando-2eperez[~]> cat /tmp/github-app-git-credentials 
    (base) jupyter-fernando-2eperez[~]> cat /tmp/github-app-git-credentials 
    https://x-access-token:ghu_[==============ELIDED===============]@github.com
    

    Sorry the above aren't timestamped, but both cat cmds were run after having executed the notebook with:

    image

    and within a few seconds of one another. The first cat gave an empty file, then I tried again and it showed content.

    Any ideas of what could be going on?

    opened by fperez 12
  • Add Jupyter support

    Add Jupyter support

    Once installed, then inside a Notebook or Console using the IPython kernel, one can type

    %run -m github_app_user_auth.jupyter
    

    resulting in:

    image

    This doesn't modify the existing usage at the terminal, though it does add support for also calling the CLI entry point as python -m github_app_user_auth if desired.

    This builds on the discussion from #7.

    opened by fperez 12
  • Duplicate configuration on where the credentials file is stored - why?

    Duplicate configuration on where the credentials file is stored - why?

    Do we really need a gitconfig and an explicit declaration of the path name of where to put the credentials? I don't understand why that would be needed.

    image

    As a user of this project I'm a bit extra cautious since its configuration with a significant security impact, not understanding the the notes in the setup instructions fully, even though they may not be related to me at this point, I become a bit cautious.


    Oh, is it because github-app-user-auth both relies on a jupyter_server/notebook extension to respond somehow and that may act as a user that doesn't have read/write permissions to a home folder. While, the user running the github-app-user-auth CLI will have permission to the home folder? Something like that?

    opened by consideRatio 7
  • Works in the notebook/console! Do you want a PR? :)

    Works in the notebook/console! Do you want a PR? :)

    Try running this version in a notebook:

    
    import argparse
    import requests
    import sys
    import time
    import os
    
    from IPython.display import display, Javascript
    import ipywidgets as widgets
    
    def do_authenticate_device_flow(client_id):
        """
        Authenticate user with given GitHub app using GitHub OAuth Device flow
        https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps#device-flow
        describes what happens here.
        Returns an access_code and the number of seconds it expires in.
        access_code will have scopes defined in the GitHub app
        """
        verification_resp = requests.post(
            "https://github.com/login/device/code",
            data={"client_id": client_id, "scope": "repo"},
            headers={"Accept": "application/json"},
        ).json()
    
        url  = verification_resp["verification_uri"]
        code = verification_resp["user_code"]
        
        display(Javascript(f'navigator.clipboard.writeText("{code}");'))
      
        print(f'The code {code} has been copied to your clipboard.')
        print(f'You have 15 minutes to go to this URL and paste it there:')
        print(f'{url}')
    
        ans = input("Hit ENTER to open that page in a new tab (type anything to cancel)>")
        if ans:
            print("Automatic opening canceled!")
        else:
            display(Javascript(f'window.open("{url}", "_blank");'))
        
        print('Waiting...', end='', flush=True)
    
        while True:
            time.sleep(verification_resp["interval"])
            print('.', end='', flush=True)
            access_resp = requests.post(
                "https://github.com/login/oauth/access_token",
                data={
                    "client_id": client_id,
                    "device_code": verification_resp["device_code"],
                    "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
                },
                headers={"Accept": "application/json"},
            ).json()
            if "access_token" in access_resp:
                print()
                return access_resp["access_token"], access_resp["expires_in"]
    
    def main():
        
        client_id = os.environ.get("GITHUB_APP_CLIENT_ID")
        git_credentials_path = "/tmp/github-app-git-credentials" 
    
        access_token, expires_in = do_authenticate_device_flow(client_id)
        expires_in_hours = expires_in / 60 / 60
        print(f"\nSuccess! Authentication will expire in {expires_in_hours:0.1f} hours.")
    
        # Create the file with appropriate permissions (0600) so other users can't read it
        with open(os.open(git_credentials_path, os.O_WRONLY | os.O_CREAT, 0o600), "w") as f:
            f.write(f"https://x-access-token:{access_token}@github.com\n")
    

    and then just call main() either in the notebook or a console attached to it. I think works really nicely!

    image

    Do you want a PR for this? Or you can go ahead and do it :)

    I'd refactor the code a bit to reuse more at the cmd line and Jupyter, and I'd add a magic, say %ghauth, to shorten this. We can then add the magic to __init__ and pre-import it, or even add it to a button/menu on the UI that shows the current GH connection status and lets you refresh the auth by clicking on it...

    But anyway, I think this is now good enough for everyday use, esp. if we add a magic we preload or similar for convenience....

    opened by fperez 6
  • Feedback on README.md instructions

    Feedback on README.md instructions

    1. Step 6 in the GitHub App configuration, part of the README.md includes:

      Save the Public link as well, as users will need to use this to grant access to particular repositories.

      What does this refer to?

    2. Step 1 in the Client configuration, part of the README.md refers to use of git-credentials-store. Since that is a technical reference, I'd expect a link or similar to be able to understand if that was a Python package we depend on, an apt-get package, or something part of what you get when installing git in any way etc.

      Is it correct that git-credentials-store refers to something shipping with git, namely this.

    3. Use of GITHUB_APP_CLIENT_ID, maybe GITHUB_APP_USER_AUTH_CLIENT_ID or GITHUB_APP_USER_AUTH__CLIENT_ID instead? I've seen a lot of confusion stemming from not knowing what environment variables influence what software. By prefixing the environment variable with the related software's full name, there is a lot less confusion about it. To me, that far outweighs the downside of having a longer environment variable name.

      What do you think about renaming this env var?

    opened by consideRatio 6
  • Move into the JupyterHub org

    Move into the JupyterHub org

    I think this is broadly useful enough that this should be inside the JupyterHub org.

    Thoughts, @minrk @manics @consideratio @choldgraf @georgianaelena?

    opened by yuvipanda 3
  • Only Yuvi with permissions in PyPI

    Only Yuvi with permissions in PyPI

    @yuvipanda I'm looking to setup jupyterhub-bot with a PyPI deployment token for this repo for #32, but I also note that we only have you as a sole maintainer of the PyPI package atm. Feel free to add me or another jupyterhub maintainer, but i figure we should be at least 2+ being able to resolve issues and avoid a bus factor of 1.

    opened by consideRatio 2
  • Helpful message on public url to app, configured like _CLIENT_ID

    Helpful message on public url to app, configured like _CLIENT_ID

    I've not gone through the full steps, but wouldn't it be nice to have a standardized UX for how users would go about knowing what app to authorize against etc?

    I figure we would configure the public url (in my case https://github.com/settings/apps/hub-jupytearth-org-github-integ), just like we configure the GITHUB_APP_CLIENT_ID env var. While it isn't crucial, it would allow this software to provide helpful messages to the user if they aren't already setup or similar maybe?

    Another options would perhaps be to let this software lookup the public URL by knowing the APP id by asking some GitHub API?

    opened by consideRatio 1
  • Remove hard-coded credentials file location

    Remove hard-coded credentials file location

    We needed admins to setup .gitconfig to point to the generated credentials file earlier, and so we used a well known location. Now that we set git config automatically, that is unnecessary.

    This makes it secure to use on HPC systems

    opened by yuvipanda 0
  • Automatically tell git where to look for github creds

    Automatically tell git where to look for github creds

    Removes a fiddly client-side config! This was particularly problematic when git was installed via conda, as it does not read the systemwide /etc/gitconfig file (https://github.com/conda-forge/git-feedstock/issues/113)

    Ref #2

    opened by yuvipanda 0
  • Rename to be gh-scoped-creds

    Rename to be gh-scoped-creds

    • Better name for what it actually does
    • Prefix env var we use to pick up client id
    • Rename the IPython Magic too

    Ref https://github.com/yuvipanda/gh-scoped-creds/issues/2

    opened by yuvipanda 0
  • mixing Anaconda with gh-scoped-creds

    mixing Anaconda with gh-scoped-creds

    Proposed change

    had previously been using gh-scoped-creds through Syzygy without any issues. It had served as an excellent way to securely push and pull to and from Github; however, as of this week, my Syzygy has encountered a serious issue and so I am now working through Anaconda. I was wondering if you have any experience dealing with using your package through anaconda as it seems to install easily enough, yet it won't let me push to Github, even when I am supposedly securely authenticated. Is what I am trying to do currently possible, and if no, would it be possible to do it in the near future?

    Who would use this feature?

    I imagine that this feature, if possible, would be helpful to any people who have to work through Anaconda with their data projects.

    enhancement 
    opened by QuonnorGraygar 2
  • A command to stop using the credentials and possibly also clean them up

    A command to stop using the credentials and possibly also clean them up

    Facu with JMTE wrote this.

    Does anyone knows how to deactivate the Github authentication app once it has been activated? I am trying to push to a repository that doesn’t have the app installed and of which I am not owner . I can just wait 8 hours and push with my GH token, but I would like to know if there is another way of doing this. Thank you!

    I concluded he could remove a section from his .gitconfig looking like this accomplish that.

    [credential "https://github.com/"]
    	helper = store --file=/tmp/tmp3z__u6za
    

    That configuration was added by this section.

    https://github.com/jupyterhub/gh-scoped-creds/blob/1f7947d1b34cff5c2544eacd76fa5dcaf0dff06c/gh_scoped_creds/init.py#L97-L106

    Maybe it can make sense to have a command to clean that configuration change and the associated credentials?

    opened by consideRatio 0
  • Missing tags makes it hard to generate a changelog retroactively

    Missing tags makes it hard to generate a changelog retroactively

    I'd like to create a changelog retroactively using github-activity, but that relies on release being git tagged.

    Is it okay if I retroactively create git tags, or maybe @yuvipanda has git tags already made but not pushed that can be pushed retroactively? It would help the use of github-activity to generate the changelog. I see that the setup.py file has been updated reliably with new versions for each release on PyPI even though git tags hasn't been created/pushed reliably.

    Current PyPI releases

    Click to expand

    image

    Current git history

    Click to expand
    *   25a0a5d - (HEAD -> main, origin/main, origin/HEAD, fork/main) Merge pull request #30 from yuvipanda/pre-commit-ci-update-config (2 weeks ago) <Yuvi Panda>
    |\  
    | * 6a0da6b - (origin/pre-commit-ci-update-config, fork/pre-commit-ci-update-config) [pre-commit.ci] pre-commit autoupdate (4 weeks ago) <pre-commit-ci[bot]>
    |/  
    *   a432e5b - Merge pull request #29 from yuvipanda/pre-commit-ci-update-config (5 weeks ago) <Yuvi Panda>
    |\  
    | * 826b0ab - [pre-commit.ci] pre-commit autoupdate (5 weeks ago) <pre-commit-ci[bot]>
    |/  
    *   37e3eab - Merge pull request #28 from yuvipanda/pre-commit-ci-update-config (6 weeks ago) <Yuvi Panda>
    |\  
    | * 2a85e0e - [pre-commit.ci] pre-commit autoupdate (6 weeks ago) <pre-commit-ci[bot]>
    |/  
    *   6eee01f - Merge pull request #27 from yuvipanda/pre-commit-ci-update-config (3 months ago) <Yuvi Panda>
    |\  
    | * af0f649 - [pre-commit.ci] pre-commit autoupdate (3 months ago) <pre-commit-ci[bot]>
    |/  
    *   b90f33a - Merge pull request #26 from yuvipanda/pre-commit-ci-update-config (4 months ago) <Yuvi Panda>
    |\  
    | * 927fdd3 - [pre-commit.ci] pre-commit autoupdate (4 months ago) <pre-commit-ci[bot]>
    |/  
    *   5a86b67 - Merge pull request #23 from GeorgianaElena/patch-2 (5 months ago) <Yuvi Panda>
    |\  
    | * b882300 - Delete settings.json (5 months ago) <Georgiana Elena>
    * |   5f3548c - Merge pull request #24 from yuvipanda/no-ssh (5 months ago) <Yuvi Panda>
    |\ \  
    | |/  
    |/|   
    | * e6f3560 - (origin/no-ssh, fork/no-ssh) [pre-commit.ci] auto fixes from pre-commit.com hooks (5 months ago) <pre-commit-ci[bot]>
    | * 1268c92 - Add a note about using https, not ssh URLs (5 months ago) <YuviPanda>
    |/  
    *   ba42a02 - Merge pull request #20 from yuvipanda/bump (5 months ago) <Yuvi Panda>
    |\  
    | * 03149b1 - (origin/bump, fork/bump) Bump version number (5 months ago) <YuviPanda>
    * |   815b086 - Merge pull request #19 from yuvipanda/no-named-file (5 months ago) <Yuvi Panda>
    |\ \  
    | * | f475ab6 - (origin/no-named-file, fork/no-named-file) [pre-commit.ci] auto fixes from pre-commit.com hooks (5 months ago) <pre-commit-ci[bot]>
    | |/  
    | * f450280 - Remove hard-coded credentials file location (5 months ago) <YuviPanda>
    * | 41a977b - Merge pull request #18 from yuvipanda/fix-typo-2 (5 months ago) <Yuvi Panda>
    |\| 
    | * dc4db68 - (origin/fix-typo-2, fork/fix-typo-2) Update readme to use new IPython magic name (5 months ago) <YuviPanda>
    * |   9fd54ee - Merge pull request #16 from yuvipanda/user-app (5 months ago) <Yuvi Panda>
    |\ \  
    | * | 38d07eb - (origin/user-app, fork/user-app) [pre-commit.ci] auto fixes from pre-commit.com hooks (5 months ago) <pre-commit-ci[bot]>
    | |/  
    | * e0ed54e - Remove timestamp of when auth was performed (5 months ago) <YuviPanda>
    | * 1033c48 - Let users know how to manage github app access (5 months ago) <YuviPanda>
    * | ff1c7fe - Merge pull request #15 from yuvipanda/fix-typo (5 months ago) <Yuvi Panda>
    |\| 
    | * 98d9a4c - (origin/fix-typo, fork/fix-typo) Fix typo (5 months ago) <YuviPanda>
    * | cda47f3 - Merge pull request #14 from yuvipanda/git-config (5 months ago) <Yuvi Panda>
    |\| 
    | * c787d0b - (origin/git-config, fork/git-config) Bump version number (5 months ago) <YuviPanda>
    | * 3aa6e07 - [pre-commit.ci] auto fixes from pre-commit.com hooks (5 months ago) <pre-commit-ci[bot]>
    | * 2029390 - Automatically tell git where to look for github creds (5 months ago) <YuviPanda>
    |/  
    *   441933d - Merge pull request #13 from yuvipanda/rename (5 months ago) <Yuvi Panda>
    |\  
    | * 61d6aab - (origin/rename, fork/rename) Bump version number (5 months ago) <YuviPanda>
    | * ddf703e - Remove textbox based automatic opening of new window (5 months ago) <YuviPanda>
    | * 5cc8fc2 - Fix name of client env var read (5 months ago) <YuviPanda>
    | * 8abb333 - Change path of default creds file (5 months ago) <YuviPanda>
    | * bd22157 - Rename to be gh-scoped-creds (5 months ago) <YuviPanda>
    |/  
    *   120a46b - Merge pull request #12 from yuvipanda/device-flow (5 months ago) <Yuvi Panda>
    |\  
    | * 3e03994 - (origin/device-flow, fork/device-flow) Note that device flow must be manually enabled now (5 months ago) <YuviPanda>
    * | 59f7f63 - Merge pull request #11 from yuvipanda/pre-commit (5 months ago) <Yuvi Panda>
    |\| 
    | * 0272642 - (origin/pre-commit, fork/pre-commit) Steal flake8 config from JupyterHub (5 months ago) <YuviPanda>
    | * ab8e5df - Add pre-commit config (5 months ago) <YuviPanda>
    * | 5a26be0 - Merge pull request #10 from yuvipanda/simplify (5 months ago) <Yuvi Panda>
    |\| 
    | * 6286443 - (origin/simplify, fork/simplify) Note the %ghauth magic in the README (5 months ago) <YuviPanda>
    | * bf4aeee - Run black (5 months ago) <YuviPanda>
    | * 97eecc4 - Register an IPython magic directly (5 months ago) <YuviPanda>
    |/  
    *   feebfe7 - Merge pull request #8 from fperez/main (5 months ago) <Yuvi Panda>
    |\  
    | * b93e8cb - Add info about time of authentication. (6 months ago) <Fernando Perez>
    | * 01cf5dd - Highlight success with color in Jupyter mode. (6 months ago) <Fernando Perez>
    | * 4989f70 - Add Jupyter support (7 months ago) <Fernando Perez>
    | * 46d0bdf - Add dedicated __main__ entry point for python -m (7 months ago) <Fernando Perez>
    |/  
    *   f480c0f - Merge pull request #6 from fperez/patch-1 (7 months ago) <Yuvi Panda>
    |\  
    | * ec33a39 - Mention running in the console/notebook. (7 months ago) <Fernando Perez>
    | * 9442d2d - Fix typo and mention timeout. (7 months ago) <Fernando Perez>
    |/  
    * ba7184f - Make note for HPC users (7 months ago) <YuviPanda>
    * 27b646b - (tag: v1.1) Bump version number (8 months ago) <YuviPanda>
    * 3b2c203 - Tighten permissions on created git-credentials file (8 months ago) <YuviPanda>
    * 6b1f503 - Add notes on alternatives considered (8 months ago) <YuviPanda>
    * 5b33c75 - (tag: v1.0) Add vscode autoformat settings (8 months ago) <YuviPanda>
    * 452d399 - Initial commit (8 months ago) <YuviPanda>
    * c9e5780 - Initial commit (8 months ago) <Yuvi Panda>(base) ~/dev/jupyterhub/gh-scoped-creds (main)$ 
    
    opened by consideRatio 1
  • ci/docs: add release workflow (publish to pypi) and a RELEASE.md file

    ci/docs: add release workflow (publish to pypi) and a RELEASE.md file

    PR Summary

    • The github secret PYPI_PASSWORD is added already, based on a deployment token for our PyPI bot account now with maintainer permissions for the associated PyPI project.
    • Added a copy/pasted/tweaked RELEASE.md based on this workflow of relying on the github CI system to do upload to PyPI.

    Related

    It would be nice to retroactively add tags to the commits associated with the previous releases and push those before merging this to avoid triggering workflows that would try publish to PyPI. If that is done later, they won't override any PyPI release though because the upload command looks like this: twine upload --skip-existing dist/*

    • #35
    ci 
    opened by consideRatio 0
  • Understanding GitHub permissions

    Understanding GitHub permissions

    There are two times that the end user via a GitHub website, and I don't yet understand what roles they have etc. To understand that is quite relevant for anyone being an admin of a hub that provides this if the admin gets questions from users.

    I don't clearly understand the parts here. I've typically been very afraid of whenever I've accepted "act on behalf of you". But, I guess perhaps it's just "act on behalf of me" with restricted permissions based on how the application is installed for various repos.

    Task to complete

    • [ ] Clarify the role of various steps taken somewhere in this project's documentation
    • [ ] BONUS: Include some screenshots
    • [ ] BONUS: Include references to verify what's said in official github documentation

    Overview of procedure to understand better

    Step 1 - An end-user installs the github application

    This can be triggered by visiting https://github.com/apps/hub-jupytearth-org-github-integ.

    image

    Step 2 - An end-user authorize the application as initiated by github-app-auth-user CLI

    This can be triggered by running github-app-auth-user, getting a device code, and opening https://github.com/login/device

    image image image

    opened by consideRatio 6
Owner
Yuvi Panda
Yuvi Panda
A feishu bot daily push arxiv latest articles.

arxiv-feishu-bot We develop A simple feishu bot script daily pushes arxiv latest articles. His effect is as follows: Of course, you can also use other

huchi 6 Apr 6, 2022
Apprise - Push Notifications that work with just about every platform!

ap·prise / verb To inform or tell (someone). To make one aware of something. Apprise allows you to send a notification to almost all of the most popul

Chris Caron 7.2k Jan 7, 2023
A Python wrapper around the Pushbullet API to send different types of push notifications to your phone or/and computer.

pushbullet-python A Python wrapper around the Pushbullet API to send different types of push notifications to your phone or/and computer. Installation

Janu Lingeswaran 1 Jan 14, 2022
A github actions + python code to extract URLs to code repositories to put into standard form, starting with github

A github actions + python code to extract URLs to code repositories to put into standard form, starting with github ---- NOTE: JUS

Justin Gosses 2 Nov 15, 2021
GitHub Activity Generator - A script that helps you instantly generate a beautiful GitHub Contributions Graph for the last year.

GitHub Activity Generator A script that helps you instantly generate a beautiful GitHub Contributions Graph for the last year. Before ?? ?? ?? After ?

null 1 Dec 30, 2021
🤖 Automated follow/unfollow bot for GitHub. Uses GitHub API. Written in python.

GitHub Follow Bot Table of Contents Disclaimer How to Use Install requirements Authenticate Get a GitHub Personal Access Token Add your GitHub usernam

João Correia 37 Dec 27, 2022
Github-Checker - Simple Tool To Check If Github User Available Or Not

Github Checker Simple Tool To Check If Github User Available Or Not Socials: Lan

ميخائيل 7 Jan 30, 2022
An Open-Source Discord bot created to provide basic functionality which should be in every discord guild. We use this same bot with additional configurations for our guilds.

A Discord bot completely written to be taken from the source and built according to your own custom needs. This bot supports some core features and is

Tesseract Coding 14 Jan 11, 2022
Provide discord buttons feature for discord.py

dpy_buttons wrapper library for discord.py, providing discord buttons feature. Future of the library Will be merged into discord interaction api libra

Minjun Kim (Lapis0875) 17 Feb 2, 2022
This is a Discord script that will provide a QR Code to your scholars for Axie Infinity.

DiscordQRCodeBot This is a Discord script that will provide a QR Code to your Axie Infinity scholars. Setup Run Ubuntu on AWS ec2 instance Dowloads al

ZracheSs | xyZ 24 Oct 5, 2022
The Bot provide Hadith API and fetch content via api.hadith.sutanlab.id

Bot Hadith-API on Telegram The Bot provide Hadith API and fetch content via api.hadith.sutanlab.id Built With Python Asynchronous HTTP protocol client

xMan 12 Feb 19, 2022
A Twitch bot to provide information from the WebNowPlayingCompanion extension

WebNowPlayingTwitch A Twitch bot made using TwitchIO which displays information obtained from the WebNowPlaying Compaion browser extension. Image is o

NiceAesth 1 Mar 21, 2022
Telegram bot to provide links of different types of files you send

File To Link Bot - IDN-C-X Telegram bot to provide links of different types of files you send. WHAT CAN THIS BOT DO Is it a nuisance to send huge file

IDNCoderX 3 Oct 26, 2021
Picot - A discord bot made to fetch images from Pexels and unsplash API and provide raw images directly in channels

Picot A discord bot made to fetch images from Pexels and unsplash API and provid

Ayush Chandwani 5 Jan 12, 2022
An API Client package to access the APIs for NBA.com

nba_api An API Client package to access the APIs for NBA.com Development Version: v1.1.9 nba_api is an API Client for www.nba.com. This package is mea

Swar Patel 1.4k Jan 1, 2023
PyMed is a Python library that provides access to PubMed.

IMPORTANT NOTE: I don't have time to maintain this library (as some of you might have noticed). The PubMed API is a little chaotic, without a clear do

Gijs Wobben 143 Dec 21, 2022
PRAW, an acronym for "Python Reddit API Wrapper", is a python package that allows for simple access to Reddit's API.

PRAW: The Python Reddit API Wrapper PRAW, an acronym for "Python Reddit API Wrapper", is a Python package that allows for simple access to Reddit's AP

Python Reddit API Wrapper Development 3k Dec 29, 2022
PRAW, an acronym for "Python Reddit API Wrapper", is a python package that allows for simple access to Reddit's API.

PRAW: The Python Reddit API Wrapper PRAW, an acronym for "Python Reddit API Wrapper", is a Python package that allows for simple access to Reddit's AP

Python Reddit API Wrapper Development 3k Dec 29, 2022