Skip to content

Commit c366d94

Browse files
committed
wip the sandbox script is read from HEAD:.hooks/pre-receive.js
1 parent 7220b29 commit c366d94

12 files changed

+113
-41
lines changed

demo.git/index

119 Bytes
Binary file not shown.

demo.git/logs/HEAD

+3
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
0000000000000000000000000000000000000000 71c666705d861b556d73f2badddaca0cfcf5e930 William Hilton <[email protected]> 1574741587 -0500 commit (initial): Initial commit
22
0000000000000000000000000000000000000000 b1f9a9a2689e95d8aaf9d2ed5513fe78f4c53901 William Hilton <[email protected]> 1575084779 -0500 commit (initial): Initial commit
3+
b1f9a9a2689e95d8aaf9d2ed5513fe78f4c53901 d76ea2f1501e44ac5c29a091e17903b6a33fc57f William Hilton <[email protected]> 1575685262 -0500 commit: add pre-receive hook
4+
d76ea2f1501e44ac5c29a091e17903b6a33fc57f ee27a42768a70831127fca08ccc9df7b13f0f81e William Hilton <[email protected]> 1575686304 -0500 commit (amend): add pre-receive hook
5+
ee27a42768a70831127fca08ccc9df7b13f0f81e 59eabecab1988d343a2cc8c054a56d5e6cb3bd89 William Hilton <[email protected]> 1575686347 -0500 commit (amend): add pre-receive hook

demo.git/logs/refs/heads/master

+3
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
0000000000000000000000000000000000000000 71c666705d861b556d73f2badddaca0cfcf5e930 William Hilton <[email protected]> 1574741587 -0500 commit (initial): Initial commit
22
0000000000000000000000000000000000000000 b1f9a9a2689e95d8aaf9d2ed5513fe78f4c53901 William Hilton <[email protected]> 1575084779 -0500 commit (initial): Initial commit
3+
b1f9a9a2689e95d8aaf9d2ed5513fe78f4c53901 d76ea2f1501e44ac5c29a091e17903b6a33fc57f William Hilton <[email protected]> 1575685262 -0500 commit: add pre-receive hook
4+
d76ea2f1501e44ac5c29a091e17903b6a33fc57f ee27a42768a70831127fca08ccc9df7b13f0f81e William Hilton <[email protected]> 1575686304 -0500 commit (amend): add pre-receive hook
5+
ee27a42768a70831127fca08ccc9df7b13f0f81e 59eabecab1988d343a2cc8c054a56d5e6cb3bd89 William Hilton <[email protected]> 1575686347 -0500 commit (amend): add pre-receive hook
Binary file not shown.
Binary file not shown.

demo.git/packed-refs

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# pack-refs with: peeled fully-peeled sorted
2+
59eabecab1988d343a2cc8c054a56d5e6cb3bd89 refs/heads/master

demo.git/refs/heads/master

-1
This file was deleted.

demo/.hooks/pre-receive.js

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
(async () => {
2+
function abbr (oid) {
3+
return oid.slice(0, 7)
4+
}
5+
6+
// Verify objects (ideally we'd do this _before_ moving it into the repo... but I think we'd need a custom 'fs' implementation with overlays)
7+
console.log('\nVerifying objects...\n')
8+
let i = 0
9+
10+
for (const oid of oids) {
11+
i++
12+
console.log(`\rVerifying object ${i}/${oids.length}`)
13+
const { type, object } = await git.readObject({ oid })
14+
if (type === 'commit' || type === 'tag') {
15+
const email = type === 'commit' ? object.author.email : object.tagger.email
16+
console.log(`\nVerifying ${type} ${abbr(oid)} by ${email}: `)
17+
let keys
18+
try {
19+
keys = await pgp.lookup(email)
20+
} catch (e) {
21+
console.log(`no keys found 👎\n`)
22+
console.error(`\nSignature verification failed for ${type} ${abbr(oid)}. Key lookup for ${email} threw an error.\n`)
23+
return
24+
}
25+
if (keys.length === 0) {
26+
console.log(`no keys found 👎\n`)
27+
console.error(`\nSignature verification failed for ${type} ${abbr(oid)}. No PGP keys could be found for ${email}.\n`)
28+
return
29+
}
30+
let ok = false
31+
for (const key of keys) {
32+
let result
33+
try {
34+
result = await git.verify({ ref: oid, publicKeys: key })
35+
} catch (e) {
36+
if (e.code && e.code === git.E.NoSignatureError) {
37+
console.log(`no signature 👎\n`)
38+
console.error(e.message + `
39+
40+
This server's policy is to only accept GPG-signed commits.
41+
Learn how you can create a GPG key and configure git to sign commits here:
42+
https://help.github.com/en/github/authenticating-to-github/managing-commit-signature-verification
43+
`)
44+
return
45+
} else {
46+
console.error(e.message + '\n' + e.stack)
47+
return
48+
}
49+
}
50+
if (result === false) {
51+
pgp.demote(email, key)
52+
} else {
53+
console.log(`signed with ${result[0]} 👍\n`)
54+
ok = true
55+
break
56+
}
57+
}
58+
if (!ok) {
59+
console.log(`no keys matched 👎\n`)
60+
console.error(`\nSignature verification failed for ${type} ${abbr(oid)}. It was not signed with a key publicly associated with the email address "${email}".
61+
62+
Learn how you can associate your GPG key with your email account using GitHub here:
63+
https://help.github.com/en/github/authenticating-to-github/adding-a-new-gpg-key-to-your-github-account
64+
`)
65+
return
66+
}
67+
}
68+
}
69+
70+
console.log(`\nVerification complete`)
71+
done()
72+
})()

http-server.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#!/usr/bin/env node
2-
// Standalone server for use without karma!
32
var http = require('http')
43
var factory = require('./middleware')
54
var cors = require('./cors')
@@ -8,3 +7,5 @@ var config = {}
87

98
var server = http.createServer(cors(factory(config)))
109
server.listen(process.env.GIT_HTTP_MOCK_SERVER_PORT || 8174)
10+
11+
console.log(require('./logo.js'))

logo.js

-24
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,3 @@
11
var figlet = require('figlet');
22

33
module.exports = figlet.textSync('GitServer', { font: 'Cyberlarge' })
4-
5-
if (!module.parent) {
6-
console.log(module.exports)
7-
}
8-
9-
console.log(`
10-
@@@@@@@@@@@@@@@@@@
11-
@@@ @@@
12-
@@ @@ @@
13-
@@ @@ @@
14-
@@@@@@@@@@ @@ @@ @@@@@@@@@
15-
@@ @@@ @@ @@ @@
16-
@@ @@ @@ @@ @@
17-
@@ @@@ @@ @@ @@
18-
@@@@@@@@ @@ @@ @@
19-
@@ @@ @@ @@
20-
@@@@@@@@@ @@ @@ @@
21-
@@ @@@ @@ @@ @@
22-
@@@ @@ @@ @@ @@@
23-
@@@@@@@@@ @@ @@ @@@@
24-
@@@ @@@
25-
@@@@@@@@@@@@@@@@@@
26-
27-
`)

middleware.js

+25-10
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const fp = require('fs').promises
33
const path = require('path')
44
const url = require('url')
55
const EventEmitter = require('events').EventEmitter
6-
const { E, indexPack, plugins, readObject, verify, serveInfoRefs, serveReceivePack, parseReceivePackRequest } = require('isomorphic-git')
6+
const { E, indexPack, plugins, readObject, resolveRef, serveInfoRefs, serveReceivePack, parseReceivePackRequest } = require('isomorphic-git')
77
const { pgp } = require('@isomorphic-git/pgp-plugin')
88

99
let ee = new EventEmitter()
@@ -29,9 +29,15 @@ const sleep = ms => new Promise(cb => setTimeout(cb, ms))
2929

3030
const tick = () => new Promise(cb => process.nextTick(cb))
3131

32-
function log(req, res) {
32+
function logIncoming(req, res) {
3333
const color = res.statusCode > 399 ? chalk.red : chalk.green
34-
console.log(color(`[git-server] ${res.statusCode} ${pad(req.method)} ${req.url}`))
34+
console.log(` ${pad(req.method)} ${req.url}`)
35+
return false
36+
}
37+
38+
function logOutgoing(req, res) {
39+
const color = res.statusCode > 399 ? chalk.red : chalk.green
40+
console.log(color(`${res.statusCode} ${pad(req.method)} ${req.url}`))
3541
return false
3642
}
3743

@@ -40,6 +46,8 @@ function factory (config) {
4046
const u = url.parse(req.url, true)
4147
if (!next) next = () => void(0)
4248

49+
logIncoming(req, res)
50+
4351
if (is.preflightInfoRefs(req, u)) {
4452
res.statusCode = 204
4553
res.end('')
@@ -89,7 +97,6 @@ function factory (config) {
8997
await fp.rename(path.join(dir, oldfilepath), path.join(dir, filepath))
9098
}
9199
const core = gitdir + '-' + String(Math.random()).slice(2, 8)
92-
console.log('core', core)
93100
gitdir = path.join(__dirname, gitdir)
94101

95102
// send HTTP response headers
@@ -98,7 +105,6 @@ function factory (config) {
98105

99106
// index packfile
100107
res.write(await serveReceivePack({ type: 'print', message: 'Indexing packfile...' }))
101-
console.log('Indexing packfile...')
102108
await tick()
103109
let currentPhase = null
104110
const listener = async ({ phase, loaded, total, lengthComputable }) => {
@@ -132,10 +138,18 @@ function factory (config) {
132138
await fp.rmdir(path.join(dir))
133139

134140
// Run pre-receive-hook
135-
res.write(await serveReceivePack({ type: 'print', message: '\nRunning pre-receive-hook\n' }))
141+
res.write(await serveReceivePack({ type: 'print', message: '\nRunning pre-receive hook\n' }))
136142
await tick()
137-
const script = fs.readFileSync('./pre-receive-hook.js', 'utf8')
138-
await sandbox({ core, dir, gitdir, res, oids, script })
143+
let script
144+
try {
145+
const oid = await resolveRef({ gitdir, ref: 'HEAD' })
146+
const { object } = await readObject({ gitdir, oid, filepath: '.hooks/pre-receive.js', encoding: 'utf8' })
147+
script = object
148+
} catch (e) {
149+
console.log(e)
150+
script = fs.readFileSync('./pre-receive-hook.js', 'utf8')
151+
}
152+
await sandbox({ name: 'pre-receive.js', core, dir, gitdir, res, oids, updates, script })
139153

140154
// refs
141155
for (const update of updates) {
@@ -148,15 +162,16 @@ function factory (config) {
148162
if (e.message === 'Client is done') {
149163
res.statusCode = 200
150164
} else {
151-
res.write(await serveReceivePack({ type: 'error', message: e.message }))
165+
res.write(await serveReceivePack({ type: 'error', message: `${e.message}\n${e.stack}` }))
152166
}
153167
} finally {
154168
// fin
155169
res.write(await serveReceivePack({ type: 'fin' }))
156170
res.end('')
157171
}
158172
}
159-
log(req, res)
173+
174+
logOutgoing(req, res)
160175
}
161176
}
162177

sandbox.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const { lookup, demote } = require('./lookup.js')
99

1010
const curry = ({ core, dir, gitdir }) => fn => argObject => fn({ ...argObject, core, dir, gitdir })
1111

12-
const sandbox = ({ core, dir, gitdir, res, script, oids }) => {
12+
const sandbox = ({ name, core, dir, gitdir, res, oids, updates, script }) => {
1313
let ee = new EventEmitter()
1414
plugincore = git.cores.create(core)
1515
plugincore.set('emitter', ee)
@@ -46,7 +46,7 @@ const sandbox = ({ core, dir, gitdir, res, script, oids }) => {
4646
log: async (...args) => {
4747
res.write(await git.serveReceivePack({ type: 'print', message: args.join() }))
4848
},
49-
fatal: (...args) => {
49+
error: (...args) => {
5050
reject(new Error(args.join()))
5151
}
5252
}
@@ -55,15 +55,16 @@ const sandbox = ({ core, dir, gitdir, res, script, oids }) => {
5555
eval: false,
5656
wasm: false,
5757
sandbox: {
58+
updates,
59+
oids,
5860
git: $git,
5961
pgp: { lookup, demote },
60-
done: resolve,
62+
done: (err) => err ? reject(err) : resolve(),
6163
console: $console,
62-
oids
6364
}
6465
});
6566
try {
66-
script = new VMScript(script).compile();
67+
script = new VMScript(script, name).compile();
6768
} catch (err) {
6869
reject(err);
6970
}

0 commit comments

Comments
 (0)