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
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`

## Notes

Confirm that process state, webhook idempotency, reconciliation and settlement outbox behavior remain compatible.
39 changes: 39 additions & 0 deletions .github/workflows/guardian.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: MAVULA Guardian

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

permissions:
contents: read

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

jobs:
guardian:
name: guardian
runs-on: ubuntu-latest
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
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run guardian
run: pnpm guardian:check
- name: Build
run: pnpm build
- name: Test
run: pnpm test
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"description": "MAVULA Settlements - payment adapter and reconciliation foundation.",
"author": "EstandarMustaq <mustaqueestandarjunior@gmail.com>",
"author": "EstandarMustaq <estandarmustaq@mavula.io>",
"license": "AGPL-3.0-only",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -19,6 +19,7 @@
},
"scripts": {
"build": "tsc -p tsconfig.json",
"guardian:check": "node scripts/guardian.mjs",
"test": "tsc -p tsconfig.json && node --test test/*.test.mjs",
"test:ci": "tsc -p tsconfig.json && node --test test/*.test.mjs",
"typecheck": "tsc -p tsconfig.json --noEmit",
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/settlements") fail("package name must be @mavula/settlements");
if (pkg.license !== "AGPL-3.0-only") fail("settlements must remain AGPL-3.0-only");
if (pkg.author !== "EstandarMustaq <estandarmustaq@mavula.io>") {
fail("author must use the MAVULA address");
}
if (!pkg.types) fail("settlements must publish TypeScript declarations");

[
".github/CODEOWNERS",
".github/PULL_REQUEST_TEMPLATE.md",
".github/workflows/guardian.yml",
"LICENSE",
"README.md",
"prisma/schema.prisma",
"tsconfig.json",
].forEach(requireFile);

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

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 settlements guardian failed:");
for (const failure of failures) console.error(`- ${failure}`);
process.exit(1);
}

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