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!
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.
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.
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:
- https://superuser.com/questions/1565313/git-credential-osxkeychain-get-hangs
- https://docs.github.com/en/get-started/getting-started-with-git/updating-credentials-from-the-macos-keychain#deleting-your-credentials-via-the-command-line
- Dates back to 2011 and has very simple code: https://stackoverflow.com/questions/51294589/why-is-there-no-documentation-anywhere-for-git-credential-osxkeychain
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.
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.
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)