feat(omnl): settlement terminal, compliance gates, and HYBX integration foundation
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m12s
CI/CD Pipeline / Security Scanning (push) Successful in 2m21s
CI/CD Pipeline / Lint and Format (push) Failing after 36s
CI/CD Pipeline / Terraform Validation (push) Failing after 22s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 25s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 23s
Validation / validate-genesis (push) Successful in 26s
Validation / validate-terraform (push) Failing after 21s
Validation / validate-kubernetes (push) Failing after 9s
Validation / validate-smart-contracts (push) Failing after 8s
Validation / validate-security (push) Failing after 1m15s
Validation / validate-documentation (push) Failing after 15s
OMNL reconcile anchor / Run omnl:reconcile and upload artifacts (push) Failing after 26s
Verify Deployment / Verify Deployment (push) Failing after 56s

Add operator settlement terminal UI/API, swift-listener service, compliance
idempotency gates, GRU reserve dashboards, and @dbis/integration-foundation
for typed HYBX/ISO adapter contracts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-06-07 21:51:32 -07:00
parent b6ddd236e2
commit d717b504a6
182 changed files with 10852 additions and 40 deletions

View File

@@ -1,11 +1,17 @@
import type { Request, Response, NextFunction } from 'express';
import { randomUUID } from 'crypto';
import { createCorrelationContext, CORRELATION_ID_HEADER, REQUEST_ID_HEADER } from '@dbis/integration-foundation';
import { appendOmnlAudit } from '../../services/omnl-audit-log';
/** Attach trace id and log every /omnl request (response status on finish). */
/** Attach trace/correlation ids and log every /omnl request (response status on finish). */
export function omnlAuditMiddleware(req: Request, res: Response, next: NextFunction): void {
const traceId = (req.headers['x-omnl-trace-id'] as string) || randomUUID();
const ctx = createCorrelationContext({
correlationId: String(req.headers[CORRELATION_ID_HEADER] ?? req.headers['x-omnl-trace-id'] ?? ''),
requestId: String(req.headers[REQUEST_ID_HEADER] ?? ''),
});
const traceId = ctx.correlationId;
res.setHeader('X-OMNL-Trace-Id', traceId);
res.setHeader(CORRELATION_ID_HEADER, ctx.correlationId);
res.setHeader(REQUEST_ID_HEADER, ctx.requestId);
const started = Date.now();
res.on('finish', () => {
appendOmnlAudit({

View File

@@ -0,0 +1,79 @@
import type { Request, Response, NextFunction } from 'express';
import { MockComplianceDecisionEngine } from '@dbis/integration-foundation';
const engine = new MockComplianceDecisionEngine();
const FINANCIAL_POST_PATHS = [
'/omnl/iso20022/messages',
];
/**
* Optional compliance decision gate for financial POST routes.
* Enable with OMNL_COMPLIANCE_GATE=1 (uses mock engine until provider integration).
*/
export async function omnlComplianceGateMiddleware(
req: Request,
res: Response,
next: NextFunction
): Promise<void> {
if (process.env.OMNL_COMPLIANCE_GATE !== '1') {
next();
return;
}
if (req.method !== 'POST') {
next();
return;
}
const path = req.path.replace(/^\/api\/v1/, '');
if (!FINANCIAL_POST_PATHS.some((p) => path.endsWith(p))) {
next();
return;
}
const body = req.body as {
messageType?: string;
payload?: string;
entityId?: string;
tenantId?: string;
amount?: string;
currency?: string;
riskHints?: string[];
};
const result = await engine.evaluateTransaction({
entityId: body.entityId ?? 'omnl-default',
tenantId: body.tenantId ?? 'omnl',
amount: body.amount ?? '0',
currency: body.currency ?? 'USD',
transactionType: body.messageType ?? 'iso20022.store',
riskHints: body.riskHints,
});
res.setHeader('X-OMNL-Compliance-Decision', result.decision);
res.setHeader('X-OMNL-Audit-Event-Id', result.audit_event_id);
if (result.decision === 'block' || result.decision === 'reject') {
res.status(403).json({
error: 'compliance_blocked',
decision: result.decision,
reason_codes: result.reason_codes,
audit_event_id: result.audit_event_id,
manual_review_required: result.manual_review_required,
});
return;
}
if (result.decision === 'hold' || result.decision === 'review') {
res.status(202).json({
status: 'pending_review',
decision: result.decision,
reason_codes: result.reason_codes,
audit_event_id: result.audit_event_id,
manual_review_required: true,
});
return;
}
(req as Request & { complianceAuditId?: string }).complianceAuditId = result.audit_event_id;
next();
}

View File

@@ -0,0 +1,91 @@
import type { Request, Response } from 'express';
import { omnlComplianceGateMiddleware } from './omnl-compliance-gate';
import { omnlIdempotencyMiddleware } from './omnl-idempotency';
function mockRes(): Response & { statusCode?: number; body?: unknown; headers: Record<string, string> } {
const headers: Record<string, string> = {};
const res = {
headers,
statusCode: 200,
body: undefined as unknown,
setHeader(name: string, value: string) {
headers[name.toLowerCase()] = value;
},
status(code: number) {
this.statusCode = code;
return this;
},
json(payload: unknown) {
this.body = payload;
return this;
},
};
return res as Response & typeof res;
}
function mockReq(overrides: Partial<Request> & { path?: string; method?: string } = {}): Request {
return {
method: 'POST',
path: '/api/v1/omnl/iso20022/messages',
headers: {},
body: { messageType: 'pacs.008', payload: '<xml/>' },
...overrides,
} as Request;
}
describe('omnlComplianceGateMiddleware', () => {
const oldGate = process.env.OMNL_COMPLIANCE_GATE;
afterEach(() => {
if (oldGate === undefined) delete process.env.OMNL_COMPLIANCE_GATE;
else process.env.OMNL_COMPLIANCE_GATE = oldGate;
});
it('passes through when OMNL_COMPLIANCE_GATE is unset', async () => {
delete process.env.OMNL_COMPLIANCE_GATE;
const next = jest.fn();
await omnlComplianceGateMiddleware(mockReq(), mockRes(), next);
expect(next).toHaveBeenCalled();
});
it('sets compliance headers and passes when gate enabled', async () => {
process.env.OMNL_COMPLIANCE_GATE = '1';
const next = jest.fn();
const res = mockRes();
await omnlComplianceGateMiddleware(mockReq(), res, next);
expect(res.headers['x-omnl-compliance-decision']).toBeDefined();
expect(res.headers['x-omnl-audit-event-id']).toBeDefined();
expect(next).toHaveBeenCalled();
});
it('skips non-POST methods', async () => {
process.env.OMNL_COMPLIANCE_GATE = '1';
const next = jest.fn();
await omnlComplianceGateMiddleware(mockReq({ method: 'GET' }), mockRes(), next);
expect(next).toHaveBeenCalled();
});
});
describe('omnlIdempotencyMiddleware', () => {
it('passes when X-Idempotency-Key is absent', () => {
const next = jest.fn();
omnlIdempotencyMiddleware(mockReq(), mockRes(), next);
expect(next).toHaveBeenCalled();
});
it('returns 409 on duplicate idempotency key', () => {
const req = mockReq({
headers: { 'x-idempotency-key': 'idem-test-duplicate-key' },
});
const next = jest.fn();
omnlIdempotencyMiddleware(req, mockRes(), next);
expect(next).toHaveBeenCalledTimes(1);
const res = mockRes();
const next2 = jest.fn();
omnlIdempotencyMiddleware(req, res, next2);
expect(res.statusCode).toBe(409);
expect(next2).not.toHaveBeenCalled();
expect(res.body).toMatchObject({ error: 'duplicate_idempotency_key' });
});
});

View File

@@ -0,0 +1,41 @@
import type { Request, Response, NextFunction } from 'express';
import { deriveIdempotencyKey, IdempotencyStore } from '@dbis/integration-foundation';
const store = new IdempotencyStore();
const IDEMPOTENT_PATHS = ['/omnl/iso20022/messages'];
/**
* Dedup financial POSTs when X-Idempotency-Key header is present.
*/
export function omnlIdempotencyMiddleware(req: Request, res: Response, next: NextFunction): void {
if (req.method !== 'POST') {
next();
return;
}
const path = req.path.replace(/^\/api\/v1/, '');
if (!IDEMPOTENT_PATHS.some((p) => path.endsWith(p))) {
next();
return;
}
const headerKey = String(req.headers['x-idempotency-key'] ?? '').trim();
if (!headerKey) {
next();
return;
}
const key = deriveIdempotencyKey({
tenantId: String(req.headers['x-tenant-id'] ?? 'omnl'),
entityId: String(req.headers['x-entity-id'] ?? 'default'),
operation: path,
resourceId: headerKey,
});
if (!store.record(key)) {
res.status(409).json({ error: 'duplicate_idempotency_key', idempotencyKey: headerKey });
return;
}
next();
}