Skip to content

Commit 4a912fd

Browse files
authored
Merge pull request #37 from greenkeeperio/feat/nexus
Sonatype Nexus Follower
2 parents 04e2d62 + d98fc48 commit 4a912fd

7 files changed

+427
-4
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ node_modules/
22
.env
33
.nyc_output/
44
*.log
5+
.DS_Store

index.js

+17-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ require('./lib/rollbar')
1111
prefix: 'hooks.',
1212
globalTags: [env.NODE_ENV]
1313
})
14-
const server = new hapi.Server()
14+
const server = new hapi.Server({
15+
debug: {
16+
log: ['error', 'requested'],
17+
request: ['error', 'requested', 'request']
18+
}
19+
})
1520
const conn = await amqp.connect(env.AMQP_URL)
1621
const channel = await conn.createChannel()
1722
await channel.assertQueue(env.QUEUE_NAME, {
@@ -85,11 +90,21 @@ require('./lib/rollbar')
8590
}
8691
}])
8792

93+
if (env.IS_ENTERPRISE) {
94+
await server.register({
95+
register: require('./lib/nexus-event'),
96+
options: {
97+
env,
98+
channel
99+
}
100+
})
101+
}
102+
88103
server.on('response', (request, reply) => {
89104
statsdClient.increment(`status_code.${request.response.statusCode}`)
90105
statsdClient.timing('response_time', Date.now() - request.info.received)
91106
})
92107

93108
await server.start()
94-
console.log('server running')
109+
console.log('server running', server.info.uri)
95110
})()

lib/env.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const envalid = require('envalid')
22
const {str, num, url, bool} = envalid
33

44
module.exports = envalid.cleanEnv(process.env, {
5-
PORT: num({default: 8000}),
5+
PORT: num({default: 5000}),
66
WEBHOOKS_SECRET: str({devDefault: 'YOLO'}),
77
NPMHOOKS_SECRET: str({devDefault: 'SWAG'}),
88
QUEUE_NAME: str({default: 'events'}),
@@ -11,5 +11,9 @@ module.exports = envalid.cleanEnv(process.env, {
1111
ROLLBAR_TOKEN_HOOKS: str({devDefault: ''}),
1212
STATSD_HOST: str({default: '172.17.0.1'}),
1313
BEARER_TOKEN: str({devDefault: 'PIZZA'}),
14-
IS_ENTERPRISE: bool({default: false})
14+
IS_ENTERPRISE: bool({default: false}),
15+
NEXUS_SECRET: str({devDefault: 'test'}),
16+
NEXUS_URL: str({devDefault: 'http://127.0.0.1:8081/repository'}),
17+
NEXUS_REPOSITORY: str({devDefault: 'my-npm'}),
18+
NEXUS_INSTALLATION: str({devDefault: '1'})
1519
})

lib/nexus-event.js

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
const crypto = require('crypto')
2+
3+
const fetch = require('node-fetch')
4+
const _ = require('lodash')
5+
6+
const rollbar = require('./rollbar')
7+
8+
module.exports = nexusEvent
9+
module.exports.attributes = {
10+
name: 'nexus'
11+
}
12+
13+
function nexusEvent (server, {env, channel}, next) {
14+
server.route({
15+
method: 'POST',
16+
path: '/nexus/',
17+
handler,
18+
config: {
19+
payload: {
20+
output: 'data',
21+
parse: false,
22+
maxBytes: 1024 * 1024 * 25 // = 25 MB
23+
}
24+
}
25+
})
26+
27+
async function handler (request, reply) {
28+
const nexusSecret = env.NEXUS_SECRET
29+
const nexusUrl = env.NEXUS_URL
30+
const nexusRepository = env.NEXUS_REPOSITORY
31+
const nexusInstallation = env.NEXUS_INSTALLATION
32+
33+
if (!nexusSecret || !nexusUrl || !nexusRepository || !nexusInstallation) {
34+
return reply({ok: false}).code(503) // Service Unavailable
35+
}
36+
37+
const payload = request.payload.toString()
38+
const signature = request.headers['x-nexus-webhook-signature']
39+
40+
var hmacDigest = crypto.createHmac('sha1', nexusSecret)
41+
.update(payload)
42+
.digest('hex')
43+
44+
if (signature !== hmacDigest) {
45+
return reply({ok: false}).code(403)
46+
}
47+
48+
let update
49+
try {
50+
update = JSON.parse(payload)
51+
// we can only parse out the version on here
52+
if (update.action !== 'CREATED') {
53+
return reply({ok: true}).code(200)
54+
}
55+
} catch (e) {
56+
console.log(e)
57+
return reply({error: true}).code(401)
58+
}
59+
60+
const name = update.asset.name.split('/-/')[0]
61+
// const version = update.asset.name.match(/-(\d+\.\d+\.\d+.*)\.tgz/)[1]
62+
63+
const docUrl = `${nexusUrl}/${nexusRepository}/${name}`
64+
65+
let doc
66+
try {
67+
doc = await (await fetch(docUrl)).json()
68+
} catch (e) {
69+
console.log('doc fetch error', e)
70+
throw (e)
71+
}
72+
73+
const versions = _.mapValues(doc.versions, v => _.pick(v, ['gitHead', 'repository']))
74+
75+
const job = {
76+
name: 'registry-change',
77+
dependency: name,
78+
installation: nexusInstallation,
79+
distTags: doc['dist-tags'],
80+
versions: versions,
81+
registry: nexusUrl
82+
}
83+
84+
try {
85+
await channel.sendToQueue(env.QUEUE_NAME, Buffer.from(JSON.stringify(job)), {priority: 1})
86+
} catch (err) {
87+
console.log('rollbar', err)
88+
rollbar.error(err, _.assign({}, request.raw.req, {
89+
socket: {
90+
encrypted: request.server.info.protocol === 'https'
91+
},
92+
connection: {
93+
remoteAddress: request.info.remoteAddress
94+
}
95+
}))
96+
return reply({error: true}).code(501)
97+
}
98+
99+
reply({ok: true}).code(202)
100+
}
101+
next()
102+
}

package-lock.json

+94
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"rollbar": "^2.4.0"
1616
},
1717
"devDependencies": {
18+
"nock": "^9.6.1",
1819
"standard": "^11.0.0",
1920
"tap": "^12.0.0"
2021
},

0 commit comments

Comments
 (0)