1

Our team needed to clone a private GitHub repo within an Azure Function, where you can only run Python code - but there is no access to the shell or pre-installed Git or SSH binaries. At the same time, we can't use PAT token authentication for GitHub's HTTPS API - only SSH authentication (key-based) is allowed.

Note that the repository needed to be cloned for some metadata and config files in it - not for the function code or Python packages, so the requirements.txt is not what we were looking for.

How can this be done?

The GitPython package supports SSH key-based authentication but relies on system SSH binaries to achieve that. We have not found a way to make it work under Azure Functions environment.

P.S> The question is posted with the self-answer (for solution documentation). See the answer below.

1 Answer 1

1

We found the following two projects which are both pure Python based:

https://dulwich.io/ (Python Git package) and https://www.paramiko.org/ (Python SSH package)

There was evidence that they could work together (though authors say they consider this support to be "experimental" and not covered by tests), and an end-to-end code sample was hard to come by.

After some back-end-forth, the following snippet worked:

    from paramiko import  RSAKey
    import os
    import dulwich
    from dulwich import porcelain
    from dulwich.contrib.paramiko_vendor import ParamikoSSHVendor
    
    #Constants
    private_key_path = "~.ssh/id_rsa_githubrepo"
    repo_url = "[email protected]:myorg/myrepo.git"
    local_path = "/tmp/repo"
    
    # Load private key for SSH
    private_key = RSAKey(filename=private_key_path)
    ssh_kwargs = {"pkey": private_key}
    
    def get_dulwich_ssh_vendor():
        vendor = ParamikoSSHVendor(**ssh_kwargs)
        return vendor
    
    # overriding another module's method: gross! But there does not seem to be another way
    dulwich.client.get_ssh_vendor = get_dulwich_ssh_vendor

    # cloning
    repo = porcelain.clone(repo_url, target=local_path, checkout=True)

    #validation
    with open(os.path.join(local_path, "README.md"), "r") as f:
        print(f.read())
    ```
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.