Skip to content
Merged
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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @EstandarMustaq
12 changes: 12 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## Summary

-

## Validation

- [ ] `pnpm guardian:check`
- [ ] `pnpm test:all`

## Notes

Confirm that queue processing, retries, schedules, status and metrics remain compatible.
64 changes: 64 additions & 0 deletions .github/workflows/guardian.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: MAVULA Guardian

on:
pull_request: {}
push:
branches:
- main
workflow_dispatch: {}

permissions:
contents: read

concurrency:
group: workbench-guardian-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
guardian:
name: guardian
runs-on: ubuntu-latest
services:
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=5
env:
REDIS_URL: redis://127.0.0.1:6379
INTERNAL_API_KEY: guardian-internal-api-key
LEDGER_CORE_URL: http://fengine.test
steps:
- uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v6
with:
version: 10.33.0
- name: Use Node.js 22.22.3
uses: actions/setup-node@v6
with:
node-version: 22.22.3
- name: Prepare settlements workspace
run: |
branch="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME}}"
if git ls-remote --exit-code --heads https://github.com/mavulahq/settlements "$branch"; then
git clone --depth 1 --branch "$branch" https://github.com/mavulahq/settlements ../settlements
else
git clone --depth 1 https://github.com/mavulahq/settlements ../settlements
fi
cat > pnpm-workspace.yaml <<'YAML'
packages:
- .
- ../settlements
YAML
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
- name: Run guardian
run: pnpm guardian:check
- name: Build settlements package
run: pnpm --filter @mavula/settlements build
- name: Build
run: pnpm build
- name: Test
run: pnpm test:all
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"main": "dist/main.js",
"scripts": {
"build": "tsc -p tsconfig.json",
"guardian:check": "node scripts/guardian.mjs",
"start": "node dist/main.js",
"start:dev": "ts-node-dev --respawn --transpile-only src/main.ts",
"test": "jest --runInBand",
Expand Down
70 changes: 70 additions & 0 deletions scripts/guardian.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env node

import { existsSync, readFileSync } from "node:fs";
import { spawnSync } from "node:child_process";

const failures = [];

function fail(message) {
failures.push(message);
}

function read(path) {
return readFileSync(path, "utf8");
}

function json(path) {
return JSON.parse(read(path));
}

function requireFile(path) {
if (!existsSync(path)) fail(`${path} is required`);
}

const pkg = json("package.json");

if (pkg.name !== "@mavula/workbench") fail("package name must be @mavula/workbench");
if (pkg.license !== "AGPL-3.0-only") fail("workbench must remain AGPL-3.0-only");
if (pkg.dependencies?.["@mavula/settlements"] !== "workspace:*") {
fail("workbench must depend on @mavula/settlements through the workspace");
}

[
".github/CODEOWNERS",
".github/PULL_REQUEST_TEMPLATE.md",
".github/workflows/guardian.yml",
"LICENSE",
"README.md",
"jest.config.js",
"jest.e2e.config.js",
"tsconfig.json",
].forEach(requireFile);

if (!/SPDX-License-Identifier: AGPL-3\.0-only/.test(read("LICENSE"))) {
fail("LICENSE must declare AGPL SPDX");
}
if (!/@mavula\/workbench/.test(read("README.md"))) {
fail("README must identify @mavula/workbench");
}

const tracked = spawnSync("git", ["ls-files"], { encoding: "utf8" });
if (tracked.status !== 0) fail("git ls-files failed");
for (const file of tracked.stdout.split("\n").filter(Boolean)) {
if (/(^|\/)\.env($|\.(?!example$))/.test(file)) fail(`${file} must not be tracked`);
}

for (const path of ["package.json", "README.md", ".github/CODEOWNERS"]) {
if (path === "scripts/guardian.mjs") continue;
const content = read(path);
if (/getfluxo-io|@getfluxo|packages\/fengine|packages\/fwk|packages\/fpay|packages\/finfra/.test(content)) {
fail(`${path} contains legacy public identifiers`);
}
}

if (failures.length > 0) {
console.error("MAVULA workbench guardian failed:");
for (const failure of failures) console.error(`- ${failure}`);
process.exit(1);
}

console.log("MAVULA workbench guardian passed.");