Created
November 9, 2019 02:18
-
-
Save jarrodek/218f0469691ab12b4254db2ff191c9f5 to your computer and use it in GitHub Desktop.
This gist demonstrates how to use nodegit to sign commits using GPG keys.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const nodegit = require('nodegit'); | |
const path = require('path'); | |
const fs = require('fs-extra'); | |
const openpgp = require('openpgp'); | |
const fileName = 'newfile.txt'; | |
const fileContent = 'hello world'; | |
const directoryName = 'salad/toast/strangerinastrangeland/theresnowaythisexists'; | |
/** | |
* This example creates a certain file `newfile.txt`, adds it to the git | |
* index and commits with GOG signaature it to head. Similar to a `git add newfile.txt` | |
* followed by a `git commit -s` | |
* | |
* This example uses `openpgp` library (https://github.com/openpgpjs/openpgpjs) | |
* to read the key and encrypt the commit message. This involves two functions: | |
* - the `decryptGpg` function which is responsible for decrypting the GPG key | |
* - the `onSignature` function which is called during commit operation | |
* | |
* The `onSignature` function is the callback function passed to the | |
* `createCommitWithSignature()` function of Repository instance. | |
* | |
* This example uses dummy GPG key. Learn how to generate a GPG key on HitHub | |
* help pages: https://help.github.com/en/github/authenticating-to-github/generating-a-new-gpg-key | |
**/ | |
/** | |
* Decrypts GPG key to be used to sign commits. | |
* @return {Promise} | |
*/ | |
async function decryptGpg() { | |
const key = path.join(__dirname, 'secret-key-489B1963.asc'); | |
const pass = 'nodegit'; | |
const buff = await fs.readFile(key); | |
const armored = await openpgp.key.readArmored(buff); | |
const keyObj = armored.keys[0]; | |
const decrypted = keyObj.decrypt(pass); | |
if (decrypted) { | |
return keyObj; | |
} | |
} | |
/** | |
* Callback for GPG signature when signing the commit. | |
* @param {String} tosign A string to sign. | |
* @return {Promise} | |
*/ | |
async function onSignature(tosign) { | |
const privateKeyResult = await decryptGpg(); | |
if (!privateKeyResult) { | |
throw new Error('GPG key decoding error.'); | |
} | |
const buf = new Uint8Array(tosign.length); | |
for (let i = 0; i < tosign.length; i++) { | |
buf[i] = tosign.charCodeAt(i); | |
} | |
const options = { | |
message: openpgp.message.fromBinary(buf), | |
privateKeys: [privateKeyResult], | |
detached: true | |
}; | |
const signed = await openpgp.sign(options); | |
return { | |
code: nodegit.Git.Error.CODE.OK, | |
field: 'gpgsig', | |
signedData: signed.signature | |
}; | |
} | |
/** | |
* Creates files in the local filesystem. This files will be added to the | |
* repository. | |
* @param {Repository} repo | |
* @return {Promise} A promise resolved when files are created | |
*/ | |
async function addFiles(repo) { | |
await fs.ensureDir(path.join(repo.workdir(), directoryName)); | |
await fs.writeFile(path.join(repo.workdir(), fileName), fileContent); | |
await fs.writeFile( | |
path.join(repo.workdir(), directoryName, fileName), | |
fileContent | |
); | |
} | |
/** | |
* Adds files by path and writes the state to the index. | |
* @param {Repository} repo | |
* @return {Promise} A promise resolved to an Oid | |
*/ | |
async function addAndWrite(repo) { | |
const index = await repo.refreshIndex(); | |
await index.addByPath(fileName); | |
await index.addByPath(path.posix.join(directoryName, fileName)); | |
await index.write(); | |
return await index.writeTree(); | |
} | |
/** | |
* Commits changes using GPG key. | |
* @param {Repository} repo | |
* @param {Oid} oid Write Oid | |
* @return {Promise} Resolved when the commit is ready. | |
*/ | |
async function commitSigned(repo, oid) { | |
const head = await nodegit.Reference.nameToId(repo, 'HEAD'); | |
const parent = await repo.getCommit(head); | |
const author = nodegit.Signature.now('Pawel Psztyc', '[email protected]'); | |
const committer = nodegit.Signature.now('Pawel Psztyc', '[email protected]'); | |
return await repo.createCommitWithSignature( | |
'HEAD', | |
author, | |
committer, | |
'message', | |
oid, | |
[parent], | |
onSignature | |
); | |
} | |
let repo; | |
nodegit.Repository.open(path.resolve(__dirname, '../.git')) | |
.then((result) => { | |
repo = result; | |
return addFiles(repo); | |
}) | |
.then(() => addAndWrite(repo)) | |
.then((oid) => commitSigned(repo, oid)) | |
.then((commitId) => { | |
console.log(`New commit: ${commitId}`); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-----BEGIN PGP PUBLIC KEY BLOCK----- | |
mQENBF3GGN0BCAC5S10y3xUYccBF/ElgVYPM61CAmf5vKbGvsEuDIAqBIvHddCw1 | |
myaHqrK67/mkavlbLp3HD9jTgkd5sRrzVVSFGxeGRf2ysFamsGH+rLwvqzpyb4ru | |
49ThwMUVsuVExdoQB6Il7cdZLnnEZejr+ud9ZsDP24v5nleqOjAkU8GUiLdOaVgx | |
e6ObEiSQbmzW9mz+DzLrKgbyar4ID+cC4+5y7D2w+eB9Az6EOCJGVxLxUSo9DyFX | |
3x0e67MrwrdFTPeKjS+HirzGdyJI7oTJsdWJD3rUDWwxSw7v52I8xGWxBOu67dUT | |
Ruuhe/JNrAtjnDxZC2qfiFgTB98jGov/FENHABEBAAG0JU5vZGVnaXQgRXhhbXBs | |
ZSA8bm9kZWdpdEBub2RlZ2l0Lm9yZz6JAU4EEwEKADgWIQRQmkqTSsOlqpBdFEs/ | |
lSx6SJsZYwUCXcYY3QIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRA/lSx6 | |
SJsZY9cCB/9uU/Q4GOHAKP5jnD6ZRdV2GM7DIKQKsUHmq/Zmxr6xGnUQoCw8iNcN | |
5bwJusJbl0/BbVI0MO4oHWTNZYc6KHz6E7NnM/c8yOZHpvl8PcvprNwUTOTUERGE | |
noDXr4HEwOUvpkzSnkmy8O0mmmX3gtRs5KZCXJFUsVNII2N04w4wNCITNZvMY8ov | |
A/xRtUuDsljtyrsUq7ZgVLCwC1AvnLqreTOEbu9KaEykgQ8SkfjFmcl9DXtXkKdw | |
uKonTKpOo7aeXETDHzQictsGAW6BPm2Dac+c1SbsAx0oa6eF9tqrjkkSEAC7SEFy | |
Qe5EcuMZfqK8LPzFAWR2ICBnDiuZc71TuQENBF3GGN0BCADYlgAEmX2G2Cdkgh/n | |
4Q8xyqqOw31JClVtMIIV/c7/VY3Od8f3/OTKb3WrKGOsPWs+nVopeJ5fFlIOyDz6 | |
qsujJvP/EltWit6l0SSXufsM7C9HyHS3vEkBW2ltJ/urZXW1bZ/z7ocwn417OnHK | |
3k90HcncYca1HvctbZ8VPlyhVkyLllaBFDRvfi/asjZEY1hL5j0HvAGi9jvq/UXg | |
H+/mskc95SQD5CbrSMkkAogfFkX+g/y7gxSAgY09NWco6+6Uiiq2WAp1MOsPa+Y6 | |
rbfYltIU5UCmcfJ2996y4zgCkDlmITY+T7CvkVs6JeKfYiRMZiNMarFoexjGDzEm | |
EAiLABEBAAGJATYEGAEKACAWIQRQmkqTSsOlqpBdFEs/lSx6SJsZYwUCXcYY3QIb | |
DAAKCRA/lSx6SJsZYy/8B/sFT1snW1ldY7zICkUNi4aHdqXWNdPsdSRzGn0C2/Vh | |
lyPQXWUhcI8a0J9DPOZ9LylMB+MD7Bgt2SNjym711Wce77kPURyNby5/j1kc4LU8 | |
3ArKv9ULiJO2C5NBTgK4uevdOALlMy1AJdt3vi5zO9MQW9QnxnHxBNUxAc/BUPqB | |
en+XpAmxpr0UqU/q7VY8m8Ep8VA5gp2zuib5R1kUl26lctF8Zae1iFVA+KWhK07l | |
HJsp5zG8TVlGdHSRhhb/Z5f3AbJzRmSrIeJoWUdSaSbJk5kq7jPaYXtPw3EDyv2F | |
U/m6Om3LBBsBsIzBadNHTtNdt4PTJByA9dGgqTL46Bjp | |
=7n4W | |
-----END PGP PUBLIC KEY BLOCK----- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment