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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
16 changes: 16 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,22 @@ dist
build
reports
dist
eslint.config.mjs
coverage
helm
tests
reports
README.md
CHANGELOG.md
commitlint.config.js
jest.config.base.js
typedoc.json
node_modules
.git
.next
dist
.turbo
prod
local.json
example
.vscode
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,7 @@ local.json
*.tar.gz*

html

out
prod
.turbo
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,14 +1,4 @@
{
"db": {
"host": "postgres",
"schema": "auth_manager",
"username": "postgres",
"password": "1234",
"database": "postgres",
"ssl": {
"enabled": false
}
},
"cron": {
"np": {
"pattern": "*/30 * * * * *",
Expand Down
File renamed without changes.
5 changes: 5 additions & 0 deletions apps/auth-cron/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { defineConfig, globalIgnores } from 'eslint/config';
import tsBaseConfig from '@map-colonies/eslint-config/ts-base';
import vitestConfig from '@map-colonies/eslint-config/vitest';

export default defineConfig(tsBaseConfig, vitestConfig, globalIgnores(['vitest.config.mts', 'ui/**/*', 'drizzle.config.mts']));
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
29 changes: 18 additions & 11 deletions packages/auth-cron/package.json → apps/auth-cron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
"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": "tsc --noEmit && cross-env CONFIG_OFFLINE_MODE=true jest --config=./tests/configurations/jest.config.js",
"test": "vitest run",
"test:watch": "vitest watch",
"test:ui": "vitest --ui",
"prebuild": "npm run clean",
"build": "tsc --project tsconfig.build.json && tsc-alias -p tsconfig.build.json && npm run assets:copy",
"build:docker": "cross-env DOCKER_BUILDKIT=1 docker build -f Dockerfile -t auth-cron ../.. ",
"build:docker-no-cache": "cross-env DOCKER_BUILDKIT=1 docker build --no-cache -f Dockerfile -t auth-cron ../.. ",
"build:docker": "docker buildx build --build-arg APP_NAME=$npm_package_name -f ../../docker/backend.Dockerfile -t ${DOCKER_REGISTRY:-}${npm_package_name}:${DOCKER_TAG:-latest} ${DOCKER_FLAGS:-} ../..",
"build:docker-no-cache": "cross-env DOCKER_FLAGS=--no-cache pnpm run build:docker",
"start": "npm run build && cd dist && node --enable-source-maps --import ./instrumentation.mjs ./index.js",
"assets:copy": "copyfiles -f ./config/* ./dist/config && copyfiles ./package.json dist && copyfiles ./dataSource.mjs dist && copyfiles -f ./src/wrappers/* ./dist/wrappers",
"clean": "rimraf dist"
Expand All @@ -34,10 +36,10 @@
"dependencies": {
"@aws-sdk/client-s3": "3.317.0",
"@godaddy/terminus": "^4.12.0",
"@map-colonies/auth-bundler": "^1.11.0",
"@map-colonies/auth-core": "^1.8.0",
"@map-colonies/config": "^3.0.1",
"@map-colonies/js-logger": "1.0.1",
"@map-colonies/auth-bundler": "workspace:^",
"@map-colonies/auth-core": "workspace:^",
"@map-colonies/config": "^4.0.1",
"@map-colonies/js-logger": "catalog:",
"@map-colonies/read-pkg": "0.0.1",
"@map-colonies/schemas": "^1.9.0",
"@map-colonies/telemetry": "^10.0.1",
Expand All @@ -55,12 +57,17 @@
"devDependencies": {
"@adobe/jsonschema2md": "^7.1.5",
"@types/config": "^3.3.0",
"@types/jest": "^29.4.0",
"@types/node": "^18.15.5",
"@types/node": "catalog:",
"@types/express": "^4.17.17",
"copyfiles": "^2.4.1",
"jest-extended": "^3.2.4",
"jest-extended": "catalog:",
"rimraf": "^4.4.0",
"ts-node": "^10.9.1",
"typescript": "^5.8.3"
"typescript": "catalog:",
"@types/lodash": "^4.17.24",
"vitest": "catalog:",
"@vitest/coverage-v8": "catalog:",
"@vitest/ui": "catalog:",
"@map-colonies/vitest-utils": "catalog:"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ let configInstance: ConfigType | undefined;
* This should only be called from the instrumentation file.
* @returns A Promise that resolves when the configuration is successfully initialized.
*/
async function initConfig(): Promise<void> {
async function initConfig(offlineMode?: boolean): Promise<void> {
configInstance = await config({
schema: infraOpalaCronV2,
offlineMode,
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { env } from 'node:process';
import { createServer } from 'node:http';
import express from 'express';
import { createTerminus } from '@godaddy/terminus';
import { CatchCallbackFn, Cron } from 'croner';
import { DataSource, Repository } from 'typeorm';
import { Bundle, Environments, initConnection } from '@map-colonies/auth-core';
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 type { commonDbFullV1Type } from '@map-colonies/schemas';
import { BundleDatabase } from '@map-colonies/auth-bundler';
import { collectMetricsExpressMiddleware } from '@map-colonies/telemetry/prom-metrics';
Expand Down Expand Up @@ -66,5 +68,4 @@ const main = async (): Promise<void> => {
});
};

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
main().catch((err) => logger?.error({ msg: 'program terminated with an error', err }));
7 changes: 4 additions & 3 deletions packages/auth-cron/src/job.ts → apps/auth-cron/src/job.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import path from 'node:path';
import { BundleDatabase, createBundle, getVersionCommand } from '@map-colonies/auth-bundler';
import { Bundle, Environments } from '@map-colonies/auth-core';
import { Repository } from 'typeorm';
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 { getS3Client } from './s3';
import { compareVersionsToBundle } from './util';
import { logger } from './telemetry/logger';
Expand Down
2 changes: 1 addition & 1 deletion packages/auth-cron/src/s3.ts → apps/auth-cron/src/s3.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { readFileSync } from 'node:fs';
import { StatusCodes } from 'http-status-codes';
import { HeadBucketCommand, HeadObjectCommand, NotFound, PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { Environments } from '@map-colonies/auth-core';
import type { Environments } from '@map-colonies/auth-core';
import type { infraOpalaCronV1Type } from '@map-colonies/schemas';
import { getConfig } from './config';
import { logger } from './telemetry/logger';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import jsLogger, { Logger } from '@map-colonies/js-logger';
import type { Logger } from '@map-colonies/js-logger';
import { jsLogger } from '@map-colonies/js-logger';
import { setLogger } from '@map-colonies/auth-bundler';
import { getConfig } from '../config';

Expand Down
4 changes: 2 additions & 2 deletions packages/auth-cron/src/util.ts → apps/auth-cron/src/util.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import assert from 'node:assert';
import { readdir, rm } from 'node:fs/promises';
import path from 'node:path';
import { Bundle } from '@map-colonies/auth-core';
import { BundleContentVersions } from '@map-colonies/auth-bundler/dist/types';
import type { Bundle } from '@map-colonies/auth-core';
import type { BundleContentVersions } from '@map-colonies/auth-bundler/dist/types';
import { logger } from './telemetry/logger';

export function compareVersionsToBundle(bundle: Bundle, versions: BundleContentVersions): boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Environments } from '@map-colonies/auth-core';
import type { Environments } from '@map-colonies/auth-core';
import { getS3Client } from './s3';
import { logger } from './telemetry/logger';

Expand Down
43 changes: 43 additions & 0 deletions apps/auth-cron/tests/config.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { vi, describe, it, expect } from 'vitest';
import type * as configType from '@map-colonies/config';
import type { ConfigErrors } from '@map-colonies/config';
import type * as localConfigType from '@src/config';
import { getConfig } from '@src/config';

describe('config.ts', function () {
describe('#getConfig', function () {
it('should throw if the config is not initialized', function () {
expect(() => getConfig()).toThrow();
});

it('should throw if no cron is configured', async function () {
expect.assertions(2);

vi.resetModules();
// await vi.isolateModulesAsync(async () => {
/* eslint-disable @typescript-eslint/no-require-imports */
const { initConfig } = (await import('../src/config.js')) as typeof localConfigType;
const configModule = require('@map-colonies/config') as typeof configType;
/* eslint-enable @typescript-eslint/no-require-imports */

const configSpy = vi.spyOn(configModule, 'config');
configSpy.mockImplementationOnce(async (params) => {
params.localConfigPath = './tests/mocks/bad_test_config';
return configModule.config(params);
});

const action = initConfig(true);

await expect(action).rejects.toThrow('Config validation error');

await action.catch((err) => {
const validationErr = err as ConfigErrors['configValidationError'];

const filtered = validationErr.payload.filter((error) => error.message === "property 'cron' must match a schema in anyOf");

// eslint-disable-next-line vitest/no-conditional-expect
expect(filtered).toHaveLength(1);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { mkdir } from 'node:fs/promises';
import { existsSync } from 'node:fs';
import path from 'node:path';
import { mkdir, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { S3Client, CreateBucketCommand, HeadBucketCommand } from '@aws-sdk/client-s3';
import { initConfig, getConfig } from '../../src/config';
import path from 'node:path';
import { CreateBucketCommand, HeadBucketCommand, S3Client } from '@aws-sdk/client-s3';
import { getConfig, initConfig } from '@src/config';

export default async (): Promise<void> => {
export async function setup(): Promise<void> {
const folder = path.join(tmpdir(), 'authcrontests');
if (!existsSync(folder)) {
await mkdir(folder);
}

await initConfig();
await initConfig(true);
const configInstance = getConfig();
const cronOptions = configInstance.get('cron.np');

Expand All @@ -24,9 +23,15 @@ export default async (): Promise<void> => {
});

try {
// eslint-disable-next-line @typescript-eslint/naming-convention
await s3client.send(new HeadBucketCommand({ Bucket: cronOptions?.s3.bucket as string }));
} catch (err) {
console.error(err);
// eslint-disable-next-line @typescript-eslint/naming-convention
await s3client.send(new CreateBucketCommand({ Bucket: cronOptions?.s3.bucket as string }));
}
};
}

export async function teardown(): Promise<void> {
await rm(path.join(tmpdir(), 'authcrontests'), { force: true, recursive: true });
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { tmpdir } from 'node:os';
import { writeFile } from 'node:fs/promises';
import path from 'node:path';
import { BundleDatabase, createBundle } from '@map-colonies/auth-bundler';
import type { BundleDatabase } from '@map-colonies/auth-bundler';
import { createBundle } from '@map-colonies/auth-bundler';
import * as authBundler from '@map-colonies/auth-bundler';
import { Bundle, Environment } from '@map-colonies/auth-core';
import { Repository } from 'typeorm';
import jsLogger from '@map-colonies/js-logger';
import { infraOpalaCronV1Type } from '@map-colonies/schemas';
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';
import type { infraOpalaCronV1Type } from '@map-colonies/schemas';
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { getJob } from '@src/job';
import { getConfig, initConfig } from '@src/config';

jest.mock('@map-colonies/auth-bundler');
jest.mock('../src/telemetry/logger', () => {
vi.mock('@map-colonies/auth-bundler');
vi.mock('../src/telemetry/logger', () => {
return {
// eslint-disable-next-line @typescript-eslint/naming-convention
__esModule: true,
Expand All @@ -22,24 +26,25 @@ jest.mock('../src/telemetry/logger', () => {

describe('job.ts', function () {
describe('#getJob', function () {
const bundleRepoMock = jest.mocked({ findOne: jest.fn() } as unknown as Repository<Bundle>);
const bundleDbMock = jest.mocked({
getLatestVersions: jest.fn(),
getBundleFromVersions: jest.fn(),
saveBundle: jest.fn(),
} as unknown as BundleDatabase);
const createBundleMock = jest.mocked(createBundle);
const bundleRepoMock = vi.mocked({ findOne: vi.fn() } as unknown as Repository<Bundle>);
const db = {
getLatestVersions: vi.fn(),
getBundleFromVersions: vi.fn(),
saveBundle: vi.fn(),
} as unknown as BundleDatabase;
const bundleDbMock = vi.mocked(db);
const createBundleMock = vi.mocked(createBundle);
let s3client: S3Client;
let cronOptions: Exclude<infraOpalaCronV1Type['cron']['np'], undefined>;
let getVersionCommandSpy: jest.SpyInstance<Promise<string>, []>;
let getVersionCommandSpy: Mock<() => Promise<string>>;

beforeAll(async function () {
await initConfig();
await initConfig(true);
cronOptions = getConfig().get('cron.np') as Exclude<infraOpalaCronV1Type['cron']['np'], undefined>;
createBundleMock.mockImplementation(async (content, workdir, filePath) => {
await writeFile(path.join(workdir, filePath), 'aviavi');
});
getVersionCommandSpy = jest.spyOn(authBundler, 'getVersionCommand');
getVersionCommandSpy = vi.spyOn(authBundler, 'getVersionCommand');

s3client = new S3Client({
credentials: { accessKeyId: cronOptions.s3.accessKeyId, secretAccessKey: cronOptions.s3.secretAccessKey },
Expand All @@ -54,11 +59,11 @@ describe('job.ts', function () {
});

afterEach(function () {
jest.resetAllMocks();
vi.resetAllMocks();
});

afterAll(function () {
jest.restoreAllMocks();
vi.restoreAllMocks();
});

it('should create a bundle if no bundle exists', async function () {
Expand Down
Loading
Loading