Skip to content

Commit

Permalink
feat: add health check base checkers
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Feb 26, 2020
1 parent 5436f1f commit 08e8abc
Show file tree
Hide file tree
Showing 6 changed files with 264 additions and 10 deletions.
36 changes: 26 additions & 10 deletions providers/AppProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { ConfigContract } from '@ioc:Adonis/Core/Config'
import { ApplicationContract } from '@ioc:Adonis/Core/Application'

import { HealthCheck } from '../src/HealthCheck'
import envChecker from '../src/HealthCheck/Checkers/Env'
import appKeyChecker from '../src/HealthCheck/Checkers/AppKey'
import { HttpExceptionHandler } from '../src/HttpExceptionHandler'

/**
Expand Down Expand Up @@ -42,27 +44,19 @@ export default class AppProvider {
/**
* Register `HttpExceptionHandler` to the container.
*/
protected $registerHttpExceptionHandler () {
protected registerHttpExceptionHandler () {
this.$container.bind('Adonis/Core/HttpExceptionHandler', () => HttpExceptionHandler)
}

/**
* Registering the health check provider
*/
protected $registerHealthCheck () {
protected registerHealthCheck () {
this.$container.singleton('Adonis/Core/HealthCheck', () => {
return new HealthCheck(this.$container.use('Adonis/Core/Application'))
})
}

/**
* Registering all required bindings to the container
*/
public register () {
this.$registerHttpExceptionHandler()
this.$registerHealthCheck()
}

/**
* Lazy initialize the cors hook, if enabled inside the config
*/
Expand Down Expand Up @@ -108,8 +102,30 @@ export default class AppProvider {
})
}

/**
* Registers base health checkers
*/
protected registerHealthCheckers () {
this.$container.with(['Adonis/Core/HealthCheck'], (healthCheck: HealthCheck) => {
envChecker(healthCheck)
appKeyChecker(healthCheck)
})
}

/**
* Registering all required bindings to the container
*/
public register () {
this.registerHttpExceptionHandler()
this.registerHealthCheck()
}

/**
* Register hooks and health checkers on boot
*/
public boot () {
this.registerCorsHook()
this.registerStaticAssetsHook()
this.registerHealthCheckers()
}
}
57 changes: 57 additions & 0 deletions src/HealthCheck/Checkers/AppKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* @adonisjs/core
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { HealthCheckContract } from '@ioc:Adonis/Core/HealthCheck'

/**
* Message for missing Api Key
*/
const MISSING_APP_KEY_MESSAGE = [
'Missing APP_KEY environment variable.',
'It is required to keep your application secure',
].join(' ')

/**
* Message for insecure Api Key
*/
const INSECURE_APP_KEY_MESSAGE = [
'Insecure APP_KEY.',
'It must be over 32 characters long.',
'Run "node ace generate:key" to generate a secure key',
].join(' ')

/**
*/
export default function addAppKeyChecker (healthCheck: HealthCheckContract) {
healthCheck.addChecker('appKey', async () => {
if (!process.env.APP_KEY) {
return {
health: {
healthy: false,
message: MISSING_APP_KEY_MESSAGE,
},
}
}

if (process.env.APP_KEY && process.env.APP_KEY.length < 32) {
return {
health: {
healthy: false,
message: INSECURE_APP_KEY_MESSAGE,
},
}
}

return {
health: {
healthy: true,
},
}
})
}
37 changes: 37 additions & 0 deletions src/HealthCheck/Checkers/Env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* @adonisjs/core
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { HealthCheckContract } from '@ioc:Adonis/Core/HealthCheck'

/**
* Message for missing app key
*/
const MISSING_APP_KEY_MESSAGE = [
'Missing NODE_ENV environment variable.',
'It can make some parts of the application misbehave',
].join(' ')

/**
* Register the `env` checker to ensure that `NODE_ENV` environment
* variable is defined.
*/
export default function addEnvChecker (healthCheck: HealthCheckContract) {
healthCheck.addChecker('env', async () => {
return process.env.NODE_ENV ? {
health: {
healthy: true,
},
} : {
health: {
healthy: false,
message: MISSING_APP_KEY_MESSAGE,
},
}
})
}
75 changes: 75 additions & 0 deletions test/app-key-checker.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* @adonisjs/core
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import test from 'japa'
import { Ioc } from '@adonisjs/fold'
import { Application } from '@adonisjs/application/build/standalone'

import { HealthCheck } from '../src/HealthCheck'
import appKeyHealthChecker from '../src/HealthCheck/Checkers/AppKey'

test.group('Env Health Checker', () => {
test('fail when APP_KEY is not defined', async (assert) => {
const application = new Application(__dirname, new Ioc(), {}, {})
const healthCheck = new HealthCheck(application)
appKeyHealthChecker(healthCheck)

const report = await healthCheck.getReport()
assert.deepEqual(report.report, {
appKey: {
health: {
healthy: false,
message: 'Missing APP_KEY environment variable. It is required to keep your application secure',
},
},
})
})

test('fail when APP_KEY is not secure', async (assert) => {
process.env.APP_KEY = '3910200'

const application = new Application(__dirname, new Ioc(), {}, {})
const healthCheck = new HealthCheck(application)
appKeyHealthChecker(healthCheck)

const report = await healthCheck.getReport()
assert.deepEqual(report.report, {
appKey: {
health: {
healthy: false,
// eslint-disable-next-line max-len
message: 'Insecure APP_KEY. It must be over 32 characters long. Run \"node ace generate:key\" to generate a secure key',
},
},
})

delete process.env.APP_KEY
})

test('work fine when APP_KEY is secure', async (assert) => {
process.env.APP_KEY = 'asecureandlongrandomsecret'

const application = new Application(__dirname, new Ioc(), {}, {})
const healthCheck = new HealthCheck(application)
appKeyHealthChecker(healthCheck)

const report = await healthCheck.getReport()
assert.deepEqual(report.report, {
appKey: {
health: {
healthy: false,
// eslint-disable-next-line max-len
message: 'Insecure APP_KEY. It must be over 32 characters long. Run \"node ace generate:key\" to generate a secure key',
},
},
})

delete process.env.APP_KEY
})
})
56 changes: 56 additions & 0 deletions test/env-health-checker.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* @adonisjs/core
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import test from 'japa'
import { Ioc } from '@adonisjs/fold'
import { Application } from '@adonisjs/application/build/standalone'

import { HealthCheck } from '../src/HealthCheck'
import envHealthChecker from '../src/HealthCheck/Checkers/Env'

test.group('Env Health Checker', () => {
test('fail when NODE_ENV is not defined', async (assert) => {
const oldEnvValue = process.env.NODE_ENV
delete process.env.NODE_ENV

const application = new Application(__dirname, new Ioc(), {}, {})
const healthCheck = new HealthCheck(application)
envHealthChecker(healthCheck)

const report = await healthCheck.getReport()
assert.deepEqual(report.report, {
env: {
health: {
healthy: false,
message: 'Missing NODE_ENV environment variable. It can make some parts of the application misbehave',
},
},
})

process.env.NODE_ENV = oldEnvValue
})

test('work fine when NODE_ENV is defined', async (assert) => {
process.env.NODE_ENV = 'development'
const application = new Application(__dirname, new Ioc(), {}, {})
const healthCheck = new HealthCheck(application)
envHealthChecker(healthCheck)

const report = await healthCheck.getReport()
assert.deepEqual(report.report, {
env: {
health: {
healthy: true,
},
},
})

delete process.env.NODE_ENV
})
})
13 changes: 13 additions & 0 deletions test/ignitor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,17 @@ test.group('Ignitor | App Provider', (group) => {
const Server = boostrapper.application.container.use('Adonis/Core/Server')
assert.lengthOf(Server.hooks.hooks.before, 1)
})

test('register base health checkers', async (assert) => {
await setupApplicationFiles(fs)

const boostrapper = new Ignitor(fs.basePath).boostrapper()

boostrapper.setup()
boostrapper.registerProviders(false)
await boostrapper.bootProviders()

const HealthCheck = boostrapper.application.container.use('Adonis/Core/HealthCheck')
assert.deepEqual(HealthCheck.servicesList, ['env', 'appKey'])
})
})

0 comments on commit 08e8abc

Please sign in to comment.