add build body schema validation with Joi

Signed-off-by: Jakub Sokołowski <jakub@status.im>
This commit is contained in:
Jakub Sokołowski 2018-12-13 00:06:13 +01:00
parent bf824f90ec
commit 1aa0ae46d5
No known key found for this signature in database
GPG Key ID: 4EF064D0E6D63020
6 changed files with 55 additions and 16 deletions

View File

@ -6,11 +6,13 @@
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@octokit/rest": "^16.2.0", "@octokit/rest": "^16.2.0",
"joi": "^14.3.0",
"joy": "^0.1.1",
"koa": "^2.5.3", "koa": "^2.5.3",
"koa-bodyparser": "^4.2.1", "koa-bodyparser": "^4.2.1",
"koa-joi-router": "^5.1.0",
"koa-json": "^2.0.2", "koa-json": "^2.0.2",
"koa-logger": "^3.2.0", "koa-logger": "^3.2.0",
"koa-router": "^7.4.0",
"lokijs": "^1.5.5", "lokijs": "^1.5.5",
"nunjucks": "^3.1.4" "nunjucks": "^3.1.4"
}, },

View File

@ -1,17 +1,16 @@
import Koa from 'koa' import Koa from 'koa'
import Router from 'koa-router'
import JSON from 'koa-json' import JSON from 'koa-json'
import JoiRouter from 'koa-joi-router'
import BodyParser from 'koa-bodyparser' import BodyParser from 'koa-bodyparser'
const App = (ghc) => { const App = (ghc) => {
const app = new Koa() const app = new Koa()
const router = new Router() const router = new JoiRouter()
app.use(BodyParser({onerror:console.error})) app.use(router.middleware())
.use(router.routes()) .use(BodyParser({onerror:console.error}))
.use(router.allowedMethods())
.use(JSON({pretty: true})) .use(JSON({pretty: true}))
app.on('error', (err, ctx) => { app.on('error', (err, ctx) => {
console.error('server error', err, ctx) console.error('server error', err, ctx)
}) })
@ -20,11 +19,19 @@ const App = (ghc) => {
ctx.body = 'OK' ctx.body = 'OK'
}) })
router.post('/builds/:pr', async (ctx) => { router.route({
/* TODO add validation of received JSON body */ method: 'post',
await ghc.db.addBuild(ctx.params.pr, ctx.request.body) path: '/builds/:pr',
await ghc.update(ctx.params.pr) validate: {
ctx.body = {status:'ok'} type: 'json',
body: ghc.db.schema,
},
handler: async (ctx) => {
/* TODO add validation of received JSON body */
await ghc.db.addBuild(ctx.params.pr, ctx.request.body)
await ghc.update(ctx.params.pr)
ctx.body = {status:'ok'}
}
}) })
router.get('/builds/:pr', async (ctx) => { router.get('/builds/:pr', async (ctx) => {

View File

@ -1,7 +1,10 @@
import Joi from 'joi'
import Loki from 'lokijs' import Loki from 'lokijs'
import schema from './schema'
class Builds { class Builds {
constructor(path, interval) { constructor(path, interval) {
this.schema = schema
this.db = new Loki(path, { this.db = new Loki(path, {
autoload: true, autoload: true,
autosave: true, autosave: true,
@ -23,6 +26,10 @@ class Builds {
this.db.on('close', () => this.save()) this.db.on('close', () => this.save())
} }
validate (build) {
return Joi.validate(build, this.schema)
}
async save () { async save () {
this.db.saveDatabase((err) => { this.db.saveDatabase((err) => {
if (err) { console.error('error saving', err) } if (err) { console.error('error saving', err) }

13
src/schema.js Normal file
View File

@ -0,0 +1,13 @@
import Joi from 'joi'
const schema = Joi.object().keys({
id: Joi.number().positive().required(),
commit: Joi.string().regex(/^[a-zA-Z0-9]{6,40}$/).required(),
success: Joi.boolean().required(),
platform: Joi.string().max(20).required(),
duration: Joi.string().max(20).required(),
url: Joi.string().uri().required(),
pkg_url: Joi.string().uri().required(),
})
module.exports = schema

View File

@ -1,12 +1,12 @@
module.exports = ` module.exports = `
### Jenkins Builds ### Jenkins Builds
| :grey_question: | Commit | Platform | Build | Duration | Result | | :grey_question: | Commit | When | Platform | Build | Duration | Result |
|-|-|-|-|-|-| |-|-|-|-|-|-|-|
{% for b in builds -%} {% for b in builds -%}
{% if b.success -%} {% if b.success -%}
| :heavy_check_mark: | {{ b.commit }} | \`{{ b.platform }}\` | [{{ b.pr }}#{{ b.id }}]({{ b.url }}) | {{ b.duration }} | [:package: {{ b.platform }} package]({{ b.url }}) | | :heavy_check_mark: | {{ b.commit }} | {{ b.when }} | \`{{ b.platform }}\` | [{{ b.pr }}#{{ b.id }}]({{ b.url }}) | {{ b.duration }} | [:package: {{ b.platform }}]({{ b.pkg_url }}) |
{% else -%} {% else -%}
| :x: | {{ b.commit }} | \`{{ b.platform }}\` | [{{ b.pr }}#{{ b.id }}]({{ b.url }}) | {{ b.duration }} | [:page_facing_up: build log]({{ b.url }}consoleText) | | :x: | {{ b.commit }} | {{ b.when }} | \`{{ b.platform }}\` | [{{ b.pr }}#{{ b.id }}]({{ b.url }}) | {{ b.duration }} | [:page_facing_up: build log]({{ b.pkg_url }}consoleText) |
{%- endif %} {%- endif %}
{%- endfor %} {%- endfor %}
` `

10
src/validator.js Normal file
View File

@ -0,0 +1,10 @@
const Joi = require('joi');
const schema = Joi.object().keys({
username: Joi.string().alphanum().min(3).max(30).required(),
password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
access_token: [Joi.string(), Joi.number()],
birthyear: Joi.number().integer().min(1900).max(2013),
email: Joi.string().email({ minDomainAtoms: 2 })
}).with('username', 'birthyear').without('password', 'access_token');