Skip to content
Open
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
7 changes: 3 additions & 4 deletions apps/auth-cron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"migration:run": "npm run typeorm migration:run -- ",
"migration:revert": "npm run typeorm migration:revert -- ",
"typeorm": "node ../../node_modules/typeorm/cli.js -d ./dataSource.mjs",
"test": "vitest run",
"test:watch": "vitest watch",
"test:ui": "vitest --ui",
Expand All @@ -43,20 +40,22 @@
"@map-colonies/schemas": "catalog:",
"@map-colonies/prometheus": "catalog:",
"@map-colonies/tracing": "catalog:",
"@map-colonies/drizzle-utils": "catalog:",
"@opentelemetry/api": "catalog:",
"croner": "6.0.3",
"express": "catalog:",
"http-status-codes": "^2.2.0",
"pg": "catalog:",
"prom-client": "catalog:",
"typeorm": "catalog:"
"drizzle-orm": "catalog:"
},
"devDependencies": {
"@types/node": "catalog:",
"@types/express": "catalog:",
"jest-extended": "catalog:",
"test-utils": "workspace:^",
"ts-node": "^10.9.1",
"@types/pg": "catalog:",
"typescript": "catalog:",
"@types/lodash": "catalog:",
"vitest": "catalog:",
Expand Down
23 changes: 13 additions & 10 deletions apps/auth-cron/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { mkdtempSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { env } from 'node:process';
import { createServer } from 'node:http';
import type { Pool } from 'pg';
import express from 'express';
import { createTerminus } from '@godaddy/terminus';
import type { CatchCallbackFn } from 'croner';
import { Cron } from 'croner';
import type { DataSource, Repository } from 'typeorm';
import type { Environments } from '@map-colonies/auth-core';
import { Bundle, initConnection } from '@map-colonies/auth-core';
import { healthCheck, initConnection } from '@map-colonies/drizzle-utils';
import type { commonDbFullV1Type } from '@map-colonies/schemas';
import { BundleDatabase } from '@map-colonies/auth-bundler';
import { collectMetricsExpressMiddleware } from '@map-colonies/prometheus';
Expand All @@ -22,10 +22,10 @@ import { metricsRegistry } from './telemetry/metrics';
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
const SERVER_PORT = env['SERVER_PORT'] ?? 8080;

async function initDb(dbConfig: commonDbFullV1Type): Promise<[DataSource, BundleDatabase, Repository<Bundle>]> {
async function initDb(dbConfig: commonDbFullV1Type): Promise<[Pool, BundleDatabase]> {
logger.debug('initializing database connection');
const dataSource = await initConnection(dbConfig);
return [dataSource, new BundleDatabase(dataSource), dataSource.getRepository(Bundle)];
const pool = await initConnection(dbConfig);
return [pool, new BundleDatabase(pool)];
}

const errorHandler: CatchCallbackFn = (err, job) => {
Expand All @@ -36,13 +36,13 @@ const main = async (): Promise<void> => {
const config = getConfig();
const cronConfig = config.get('cron');
const dbConfig = config.get('db');
const [dataSource, bundleDatabase, bundleRepository] = await initDb(dbConfig);
const [pool, bundleDatabase] = await initDb(dbConfig);

Object.entries(cronConfig).map(([env, value]) => {
logger.info({ msg: 'initializing new update bundle job', bundleEnv: env });

const workdir = mkdtempSync(path.join(tmpdir(), `authbundler-${env}-`));
const job = getJob(bundleRepository, bundleDatabase, env as Environments, workdir);
const job = getJob(bundleDatabase, env as Environments, workdir);

return Cron(value.pattern, { unref: false, protect: true, catch: errorHandler, name: env }, async () => {
logger.info({ msg: 'running new update job', bundleEnv: env });
Expand All @@ -56,10 +56,13 @@ const main = async (): Promise<void> => {
app.use(collectMetricsExpressMiddleware({ registry: metricsRegistry }));

const server = createTerminus(createServer(app), {
onSignal: async () => {
logger.info('server is starting cleanup');
await pool.end();
logger.info('database connection closed');
},
healthChecks: {
'/liveness': async () => {
await dataSource.query('SELECT 1');
},
'/liveness': healthCheck(pool),
},
});

Expand Down
12 changes: 3 additions & 9 deletions apps/auth-cron/src/job.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import path from 'node:path';
import type { BundleDatabase } from '@map-colonies/auth-bundler';
import { createBundle, getVersionCommand } from '@map-colonies/auth-bundler';
import type { Bundle, Environments } from '@map-colonies/auth-core';
import type { Repository } from 'typeorm';
import type { Environments } from '@map-colonies/auth-core';
import { getS3Client } from './s3';
import { compareVersionsToBundle } from './util';
import { logger } from './telemetry/logger';

export function getJob(
bundleRepository: Repository<Bundle>,
bundleDatabase: BundleDatabase,
environment: Environments,
workdir: string
): () => Promise<void> {
export function getJob(bundleDatabase: BundleDatabase, environment: Environments, workdir: string): () => Promise<void> {
return async () => {
logger.debug({ msg: 'fetching bundle information from the database', bundleEnv: environment });
const latestBundle = await bundleRepository.findOne({ where: { environment }, order: { id: 'DESC' } });
const latestBundle = await bundleDatabase.getLatestBundleByEnv(environment);
const latestVersions = await bundleDatabase.getLatestVersions(environment);
const currentOpaVersion = await getVersionCommand();

Expand Down
1 change: 0 additions & 1 deletion apps/auth-cron/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export function compareVersionsToBundle(bundle: Bundle, versions: BundleContentV
// Added the check because keyVersion can be null in the database
// and we want a new bundle to be created in that case
// the bigger fix should be to not allow null keyVersion in the database
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
return bundle.environment === versions.environment && bundle.keyVersion !== null && bundle.keyVersion === versions.keyVersion;
} catch {
return false;
Expand Down
37 changes: 22 additions & 15 deletions apps/auth-cron/tests/job.spec.mts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import path from 'node:path';
import type { BundleDatabase } from '@map-colonies/auth-bundler';
import { createBundle } from '@map-colonies/auth-bundler';
import * as authBundler from '@map-colonies/auth-bundler';
import type { Bundle } from '@map-colonies/auth-core';
import { Environment } from '@map-colonies/auth-core';
import type { Repository } from 'typeorm';
import type { Mock } from 'vitest';
import { vi, describe, beforeEach, afterEach, afterAll, it, expect, beforeAll } from 'vitest';
import { jsLogger } from '@map-colonies/js-logger';
Expand All @@ -26,10 +24,10 @@ vi.mock('../src/telemetry/logger', async () => {

describe('job.ts', function () {
describe('#getJob', function () {
const bundleRepoMock = vi.mocked({ findOne: vi.fn() } as unknown as Repository<Bundle>);
const db = {
getLatestVersions: vi.fn(),
getBundleFromVersions: vi.fn(),
getLatestBundleByEnv: vi.fn(),
saveBundle: vi.fn(),
} as unknown as BundleDatabase;
const bundleDbMock = vi.mocked(db);
Expand Down Expand Up @@ -67,29 +65,32 @@ describe('job.ts', function () {
});

it('should create a bundle if no bundle exists', async function () {
bundleRepoMock.findOne.mockResolvedValueOnce(null);
bundleDbMock.getLatestBundleByEnv.mockResolvedValueOnce(null);
bundleDbMock.getLatestVersions.mockResolvedValue({
assets: [{ name: 'avi', version: 1 }],
environment: Environment.NP,
connections: [{ name: 'avi', version: 1 }],
keyVersion: 1,
});

const promise = getJob(bundleRepoMock, bundleDbMock, Environment.NP, path.join(tmpdir(), 'authcrontests'))();
const promise = getJob(bundleDbMock, Environment.NP, path.join(tmpdir(), 'authcrontests'))();

await expect(promise).resolves.not.toThrow();
// eslint-disable-next-line @typescript-eslint/unbound-method
expect(bundleDbMock.saveBundle).toHaveBeenCalledTimes(1);
});

it('should create a bundle if the data versions changed', async function () {
bundleRepoMock.findOne.mockResolvedValueOnce({
bundleDbMock.getLatestBundleByEnv.mockResolvedValueOnce({
id: 1,
assets: [{ name: 'avi', version: 1 }],
environment: Environment.NP,
connections: [{ name: 'avi', version: 1 }],
keyVersion: 2,
opaVersion: '0.52.0',
createdAt: new Date(),
hash: 'avi',
metadata: null,
});
bundleDbMock.getLatestVersions.mockResolvedValue({
assets: [{ name: 'avi', version: 1 }],
Expand All @@ -98,22 +99,24 @@ describe('job.ts', function () {
keyVersion: 1,
});

const promise = getJob(bundleRepoMock, bundleDbMock, Environment.NP, path.join(tmpdir(), 'authcrontests'))();
const promise = getJob(bundleDbMock, Environment.NP, path.join(tmpdir(), 'authcrontests'))();

await expect(promise).resolves.not.toThrow();
// eslint-disable-next-line @typescript-eslint/unbound-method
expect(bundleDbMock.saveBundle).toHaveBeenCalledTimes(1);
});

it('should create a bundle and not save the metadata to the db if there is a mismatch between s3 and the db', async function () {
bundleRepoMock.findOne.mockResolvedValueOnce({
bundleDbMock.getLatestBundleByEnv.mockResolvedValueOnce({
id: 1,
assets: [{ name: 'avi', version: 1 }],
environment: Environment.NP,
connections: [{ name: 'avi', version: 1 }],
keyVersion: 1,
hash: 'avi',
opaVersion: '0.52.0',
createdAt: new Date(),
metadata: null,
});
bundleDbMock.getLatestVersions.mockResolvedValue({
assets: [{ name: 'avi', version: 1 }],
Expand All @@ -122,7 +125,7 @@ describe('job.ts', function () {
keyVersion: 1,
});

const promise = getJob(bundleRepoMock, bundleDbMock, Environment.NP, path.join(tmpdir(), 'authcrontests'))();
const promise = getJob(bundleDbMock, Environment.NP, path.join(tmpdir(), 'authcrontests'))();

await expect(promise).resolves.not.toThrow();
expect(createBundle).toHaveBeenCalled();
Expand All @@ -133,14 +136,16 @@ describe('job.ts', function () {
it('should not create a bundle if the bundle in s3 is up to date', async function () {
// eslint-disable-next-line @typescript-eslint/naming-convention
const res = await s3client.send(new PutObjectCommand({ Bucket: cronOptions.s3.bucket, Key: cronOptions.s3.key }));
bundleRepoMock.findOne.mockResolvedValueOnce({
bundleDbMock.getLatestBundleByEnv.mockResolvedValueOnce({
id: 1,
assets: [{ name: 'avi', version: 1 }],
environment: Environment.NP,
connections: [{ name: 'avi', version: 1 }],
keyVersion: 1,
hash: res.ETag,
hash: res.ETag as string,
opaVersion: '0.52.0',
createdAt: new Date(),
metadata: null,
});
bundleDbMock.getLatestVersions.mockResolvedValue({
assets: [{ name: 'avi', version: 1 }],
Expand All @@ -149,7 +154,7 @@ describe('job.ts', function () {
keyVersion: 1,
});

const promise = getJob(bundleRepoMock, bundleDbMock, Environment.NP, path.join(tmpdir(), 'authcrontests'))();
const promise = getJob(bundleDbMock, Environment.NP, path.join(tmpdir(), 'authcrontests'))();

await expect(promise).resolves.not.toThrow();
// eslint-disable-next-line @typescript-eslint/unbound-method
Expand All @@ -159,14 +164,16 @@ describe('job.ts', function () {
it('should create a bundle if the opa version is different than the one in the db', async function () {
// eslint-disable-next-line @typescript-eslint/naming-convention
const res = await s3client.send(new PutObjectCommand({ Bucket: cronOptions.s3.bucket, Key: cronOptions.s3.key }));
bundleRepoMock.findOne.mockResolvedValueOnce({
bundleDbMock.getLatestBundleByEnv.mockResolvedValueOnce({
id: 1,
assets: [{ name: 'avi', version: 1 }],
environment: Environment.NP,
connections: [{ name: 'avi', version: 1 }],
keyVersion: 1,
hash: res.ETag,
hash: res.ETag as string,
opaVersion: '0.51.0',
createdAt: new Date(),
metadata: null,
});
bundleDbMock.getLatestVersions.mockResolvedValue({
assets: [{ name: 'avi', version: 1 }],
Expand All @@ -175,7 +182,7 @@ describe('job.ts', function () {
keyVersion: 1,
});

const promise = getJob(bundleRepoMock, bundleDbMock, Environment.NP, path.join(tmpdir(), 'authcrontests'))();
const promise = getJob(bundleDbMock, Environment.NP, path.join(tmpdir(), 'authcrontests'))();

await expect(promise).resolves.not.toThrow();
// eslint-disable-next-line @typescript-eslint/unbound-method
Expand Down
4 changes: 2 additions & 2 deletions apps/auth-cron/tests/s3.spec.mts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ describe('s3.ts', function () {
});

it('should return undefined if the object does not exists', async function () {
const hash = await getS3Client(Environment.PRODUCTION).getObjectHash();
const hash = await getS3Client(Environment.PROD).getObjectHash();

expect(hash).toBeUndefined();
});
Expand All @@ -100,7 +100,7 @@ describe('s3.ts', function () {
});

it('should return false if the bucket does not exist', async function () {
const res = await getS3Client(Environment.PRODUCTION).doesBucketExist();
const res = await getS3Client(Environment.PROD).doesBucketExist();

expect(res).toBe(false);
});
Expand Down
2 changes: 1 addition & 1 deletion apps/auth-cron/tests/validators.spec.mts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('validators.ts', function () {
});

it('should throw if the bucket does not exists', async function () {
const promise = validateS3([Environment.PRODUCTION]);
const promise = validateS3([Environment.PROD]);

await expect(promise).rejects.toThrow();
});
Expand Down
31 changes: 0 additions & 31 deletions apps/auth-manager/dataSource.mjs

This file was deleted.

9 changes: 2 additions & 7 deletions apps/auth-manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@
"test": "vitest run",
"test:watch": "vitest watch",
"test:ui": "vitest --ui",
"typeorm": "node ../../node_modules/typeorm/cli.js -d ./dataSource.mjs",
"migration:create": "npm run typeorm migration:generate --",
"migration:run": "npm run typeorm migration:run -- ",
"migration:revert": "npm run typeorm migration:revert -- ",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"prebuild": "npm run clean",
Expand Down Expand Up @@ -51,6 +47,7 @@
"@map-colonies/prometheus": "catalog:",
"@map-colonies/tracing": "catalog:",
"@map-colonies/tracing-utils": "catalog:",
"@map-colonies/drizzle-utils": "catalog:",
"@opentelemetry/api": "catalog:",
"auth-openapi": "workspace:^",
"body-parser": "catalog:",
Expand All @@ -65,7 +62,7 @@
"prom-client": "catalog:",
"reflect-metadata": "catalog:",
"tsyringe": "catalog:",
"typeorm": "catalog:"
"drizzle-orm": "catalog:"
},
"devDependencies": {
"@map-colonies/openapi-helpers": "catalog:",
Expand All @@ -84,8 +81,6 @@
"jest-extended": "catalog:",
"jest-openapi": "catalog:",
"supertest": "catalog:",
"ts-node": "^10.9.1",
"type-fest": "^4.40.0",
"typescript": "catalog:",
"vitest": "catalog:",
"@map-colonies/vitest-utils": "catalog:",
Expand Down
Loading
Loading