Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions __tests__/migrations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const knexInit = require('knex')
const { getConfig } = require('../src/config')

const { dbSettings } = getConfig('test')

const {
resetDatabase
} = require('../__utils__')

let knex

describe('Migrations', () => {
beforeAll(async () => {
knex = knexInit(dbSettings)
await knex.migrate.latest()
})
beforeEach(async () => {
await resetDatabase(knex)
})
afterAll(async () => {
await knex.destroy()
})

it('should run migrations successfully', async () => {
const result = await knex.migrate.latest()
expect(result).not.toBeNull()
const complianceChecksCount = await knex('compliance_checks').count()
expect(Number.parseInt(complianceChecksCount[0].count)).toBe(72)
})

it('should restore compliance_checks table after rolling back', async () => {
const result = await knex.migrate.latest()
expect(result).not.toBeNull()
const complianceChecksCount = await knex('compliance_checks').count()
expect(Number.parseInt(complianceChecksCount[0].count)).toBe(72)

const complianceChecksCountBeforeRollback = await knex('compliance_checks')
.select('*')
.limit(1)
expect(complianceChecksCountBeforeRollback.length).toBe(1)
expect(complianceChecksCountBeforeRollback[0]).not.toHaveProperty('mitre_url')
expect(complianceChecksCountBeforeRollback[0]).not.toHaveProperty('mitre_description')

await knex.migrate.down()

const complianceChecksCountAfterRollback = await knex('compliance_checks')
.select('*')
complianceChecksCountAfterRollback.forEach((item) => {
expect(item).toHaveProperty('mitre_url')
expect(item).toHaveProperty('mitre_description')
})
})
})
2 changes: 2 additions & 0 deletions __utils__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const resetDatabase = async (knex) => {
await knex.raw('TRUNCATE TABLE compliance_checks_results RESTART IDENTITY CASCADE')
await knex.raw('TRUNCATE TABLE compliance_checks_tasks RESTART IDENTITY CASCADE')
await knex.raw('TRUNCATE TABLE compliance_checks_alerts RESTART IDENTITY CASCADE')
await knex.raw('TRUNCATE TABLE compliance_checks_resources RESTART IDENTITY CASCADE')
await knex.raw('TRUNCATE TABLE resources_for_compliance_checks RESTART IDENTITY CASCADE')
await knex.raw('TRUNCATE TABLE github_repositories RESTART IDENTITY CASCADE')
await knex.raw('TRUNCATE TABLE github_organizations RESTART IDENTITY CASCADE')
await knex.raw('TRUNCATE TABLE projects RESTART IDENTITY CASCADE')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
exports.up = async (knex) => {
await knex.schema.createTable('compliance_checks_resources', (table) => {
table.increments('id').primary() // Primary key
table.string('url').notNullable()
table.string('name')
table.text('description')

table.integer('tmp_compliance_check_id')
.unsigned()
.notNullable()

// Timestamps
table.timestamp('created_at').defaultTo(knex.fn.now()).notNullable()
table.timestamp('updated_at').defaultTo(knex.fn.now()).notNullable()
})

await knex.raw(`
CREATE TRIGGER set_updated_at_compliance_checks_resources
BEFORE UPDATE ON compliance_checks_resources
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
`)
}

exports.down = async (knex) => {
// Drop trigger
await knex.raw(`DROP TRIGGER IF EXISTS set_updated_at_compliance_checks_resources
ON compliance_checks_resources;`)
// Drop table
await knex.schema.dropTableIfExists('compliance_checks_resources')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
exports.up = async (knex) => {
await knex.schema.createTable('resources_for_compliance_checks', table => {
table.increments()
table.integer('compliance_check_id')
.unsigned()
.notNullable()
.references('id').inTable('compliance_checks')
table.integer('compliance_check_resource_id')
.unsigned()
.notNullable()
.references('id').inTable('compliance_checks_resources')

table.timestamp('created_at').defaultTo(knex.fn.now()).notNullable()
})
}

exports.down = async (knex) => {
await knex.schema.dropTableIfExists('resources_for_compliance_checks')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
let initialResources = []

exports.up = async (knex) => {
initialResources = await knex('compliance_checks').select(
'id as compliance_check_id',
'mitre_url',
'mitre_description',
'how_to_url',
'how_to_description',
'sources_url',
'sources_description'
)
// TODO Populate compliance_check_resources
const data = initialResources.flatMap((resource) => {
return [
{
tmp_compliance_check_id: resource.compliance_check_id,
url: resource.mitre_url,
description: resource.mitre_description,
name: 'mitre'
},
{
tmp_compliance_check_id: resource.compliance_check_id,
url: resource.how_to_url,
description: resource.how_to_description,
name: 'how_to'
},
{
tmp_compliance_check_id: resource.compliance_check_id,
url: resource.sources_url,
description: resource.sources_description,
name: 'sources'
}
]
})
const complianceCheckResourceIds = await knex('compliance_checks_resources')
.insert(data.filter(d => d.url != null), ['id', 'tmp_compliance_check_id'])

const fkIds = complianceCheckResourceIds.reduce((acc, checkResource, index) => {
acc.push({
compliance_check_id: checkResource.tmp_compliance_check_id,
compliance_check_resource_id: checkResource.id
})
return acc
}, [])
await knex('resources_for_compliance_checks').insert(fkIds)

await knex.schema.alterTable('compliance_checks_resources', (table) => {
table.dropColumn('tmp_compliance_check_id')
})
}

exports.down = async (knex) => {
// await knex('compliance_checks_resources').truncate()
// await knex('resources_for_compliance_checks').truncate()
await knex.raw(
'TRUNCATE compliance_checks_resources, resources_for_compliance_checks RESTART IDENTITY'
)
}
57 changes: 57 additions & 0 deletions src/database/migrations/20250110172056_alter_compliance_checks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
exports.up = async (knex) => {
await knex.schema.alterTable('compliance_checks', (table) => {
// Drop old fields
table.dropColumn('mitre_url')
table.dropColumn('mitre_description')
table.dropColumn('how_to_url')
table.dropColumn('how_to_description')
table.dropColumn('sources_url')
table.dropColumn('sources_description')
})
}

exports.down = async (knex) => {
await knex.schema.alterTable('compliance_checks', (table) => {
table.string('mitre_url').nullable()
table.string('mitre_description').nullable()
table.string('how_to_url').nullable()
table.string('how_to_description').nullable()
table.string('sources_url').nullable()
table.string('sources_description').nullable()
})

const initialResources = await knex.select('*')
.from('compliance_checks_resources')
.join('resources_for_compliance_checks', function () {
this.on('compliance_checks_resources.id', '=', 'resources_for_compliance_checks.compliance_check_resource_id')
})

const groups = Object.groupBy(initialResources,
({ compliance_check_id }) => compliance_check_id // eslint-disable-line
)
const upsertData = Object.keys(groups).map((groupKey) => {
const groupsKey = groups[groupKey]
const payload = {}
const resources = groupsKey.reduce(
(acc, { name, url, description }) => ({
[name]: { url, description },
...acc
}),
{}
)
payload[groupKey] = { id: groupKey, ...resources }
return { id: groupKey, ...resources }
})

const upserts = upsertData.map((doc) => {
return knex('compliance_checks').where({ id: doc.id }).update({
mitre_url: doc?.mitre?.url,
mitre_description: doc?.mitre?.description,
how_to_url: doc?.how_to?.url,
how_to_description: doc?.how_to?.description,
sources_url: doc?.sources?.url,
sources_description: doc?.sources?.description
})
})
await Promise.all(upserts)
}
Loading
Loading