/git-classroom-mass-fix-n-push

A little script to bulk push Github Classroom repos back to origin in one go

Primary LanguageShellGNU General Public License v3.0GPL-3.0

Github Classroom Fix 'n Push

KGF: education/classroom-assistant#103

A little script to automatically push a directory full of Github Classroom feedback back to Github.

Specifically it goes into each repository, changes the remote URL to the original version instead of the token, adds and commits everything, pulls any changes and then pushes all changes back to github, and then moves onto the next repository.

It needs to be executed from the parent directory of all the assessments. ie, in the following directory setup, from project1/ (or assessments/, assuming only subdirectories are valid homework/project subdirs):

assessments/
    project1/
        student1repo/
        student2repo/
        ...
	project2/
		...

You'll want to make sure git, awk and grep work from the commandline before running it (this will certainly be the case on Linux. Not sure if so on macOS). Try running git -v, awk -v, grep -v to test if they're present. Also, perhaps also make sure you're in bash not zsh. (just write bash in the terminal).

It's rough and dirty, contains no checking, use at own risk without warranty!

Access tokens

The HTTPS URL remote generated by Classroom Assistant looks like: https://x-access-token:TOKENID@github.com/mpcs51087/project-1-studentname.git and is a JSON Web Token (JWT) created by the registered GitHub App. The TOKENID is the same for all students, and is tied to my account.

To authenticate as a GitHub App, generate a private key in PEM format and download it to your local machine. You'll use this key to sign a JSON Web Token (JWT) and encode it using the RS256 algorithm. GitHub checks that the request is authenticated by verifying the token with the app's stored public key.

HTTP-based Git access by an installation Installations with permissions on contents of a repository, can use their installation access tokens to authenticate for Git access. Use the installation access token as the HTTP password:

git clone https://x-access-token:<token>@github.com/owner/repo.git

The token generated by CA is revoked instantaneously, so if you try to git pull in the directories downloaded by CA, you get:

remote: The token in this link has expired. Please request another temporary clone link.
fatal: unable to access 'https://github.com/mpcs51087/project-1-ashishmverma1.git/': The requested URL returned error: 403

education/classroom-assistant#103

There are a lot of security issues to take into consideration, and after careful research the path of using temporary cloning tokens was selected as the safest option to also achieve the goals. This was to avoid giving Classroom Assistant access to any repositories outside of the scope of GitHub Classroom.

An alternative design would have been to give Classroom Assistant tokens to access repos that you as the teacher have access to. This was not ideal, because those tokens would have access to any repository on GitHub that you have access to and would include write access.

https://stackoverflow.com/questions/71595598/x-access-token-vs-a-githib-access-token-username-vs-password

I'm not sure what the difference is between the x-access-token and a-github-access-token? I assume the password is generated from "Personal access tokens" in Developer Options in GitHub. But, what/where is the token for my username? (These are setting up credentials to read from a repo)

  [{
    "type" => "git_source",
    "host" => "github.com",
    "username" => "x-access-token",
    "password" => "a-github-access-token"
  }]

When you use a GitHub personal access token for Git access, the token itself is sufficient to identify the user and the access granted. A separate username is not needed, and is ignored. (I can provide the username as x-access-token, token, torvalds, or anything else.)

GitHub allows you to use the token as either the username or the password in Git authentication. I recommend that you always store the token as the password, since generally tooling is much better about obscuring or not printing things it thinks are passwords and usually usernames are not considered sensitive. Therefore, it is less likely you will accidentally leak the token in logs or elsewhere if you store it as the password.

Refresher: HTTPS token on macOS

https://docs.github.com/en/get-started/getting-started-with-git/updating-credentials-from-the-macos-keychain

Recall, Git is setup to use macOS Keychain to cache a GitHub Personal Access Token with no expiration for HTTP/s URLs:

> git config --local credential.helper 
(returns nothing)
> git config --global credential.helper 
(returns nothing)
> git config --system credential.helper 
osxkeychain

The actual standalone binary is not in my $PATH:

> find /usr/local/Cellar/git/2.36.0 -name git-credential-osxkeychain
/usr/local/Cellar/git/2.36.0/libexec/git-core/git-credential-osxkeychain
> git credential-osxkeychain get
(hangs)

The command hangs because it is not meant to be a user-facing tool, but rather used internally by Git itself. Takes subcommands <get|store|erase> and waits for input on stdin. See:

Exactly: any credential helper (osxkeychain or otherwise) would apply only for HTTPS URLs, not SSH. And SSH needs a cache only if the private key is passphrase-protected (in which case an ssh agent is needed).

> git credential-osxkeychain get<ENTER>
host=github.com<ENTER>
protocol=https<ENTER>
<ENTER>

Returns

password=<HIDDEN>
username=felker

https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage

The default is not to cache at all. Every connection will prompt you for your username and password.

If you’re using a Mac, Git comes with an “osxkeychain” mode, which caches credentials in the secure keychain that’s attached to your system account. This method stores the credentials on disk, and they never expire, but they’re encrypted with the same system that stores HTTPS certificates and Safari auto-fills.

Refresher: SSH Agent on macOS

There is no need to manually start or connect to ssh-agent for each shell session in my ~/.zshrc on macOS, since I am using AddKeysToAgent yes in SSH config file. Furthermore, I do not need to manually re-enter the passphrase even after rebooting, since macOS's fork of OpenSSH repurposes -K option of ssh-add to integrate with "Keychain Access.app" for caching the passphrase, and adds config file support for the UseKeychain option for this purpose.

https://developer.apple.com/library/archive/technotes/tn2449/_index.html

Prior to macOS Sierra, ssh would present a dialog asking for your passphrase and would offer the option to store it into the keychain. This UI was deprecated some time ago and has been removed.

Instead, a new UseKeychain option was introduced in macOS Sierra allowing users to specify whether they would like for the passphrase to be stored in the keychain. This option was enabled by default on macOS Sierra, which caused all passphrases to be stored in the keychain.

This was not the intended default behavior, so this has been changed in macOS 10.12.2.

Aside: git clone verbosity

As an aside, this is how you get verbose output from a git clone:

> GIT_CURL_VERBOSE=1 git clone https://github.com/mpcs51087/project-1-studentname.git

(although it doesnt clearly indicate the authentication method or use of credential-osxkyechain. The -vv option of git clone doesnt add much)