Add mainnet checkpoint stack: ISO attestation, participant Etherscan surface, and services.
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m3s
CI/CD Pipeline / Security Scanning (push) Successful in 2m18s
CI/CD Pipeline / Lint and Format (push) Failing after 34s
CI/CD Pipeline / Terraform Validation (push) Failing after 20s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 22s
Deploy ChainID 138 / Deploy ChainID 138 (push) Failing after 40s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 49s
OMNL reconcile anchor / Run omnl:reconcile and upload artifacts (push) Failing after 21s
Validation / validate-genesis (push) Successful in 25s
Validation / validate-terraform (push) Failing after 21s
Validation / validate-kubernetes (push) Failing after 8s
Validation / validate-smart-contracts (push) Failing after 8s
Validation / validate-security (push) Failing after 1m11s
Validation / validate-documentation (push) Failing after 14s
Verify Deployment / Verify Deployment (push) Failing after 45s
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m3s
CI/CD Pipeline / Security Scanning (push) Successful in 2m18s
CI/CD Pipeline / Lint and Format (push) Failing after 34s
CI/CD Pipeline / Terraform Validation (push) Failing after 20s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 22s
Deploy ChainID 138 / Deploy ChainID 138 (push) Failing after 40s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 49s
OMNL reconcile anchor / Run omnl:reconcile and upload artifacts (push) Failing after 21s
Validation / validate-genesis (push) Successful in 25s
Validation / validate-terraform (push) Failing after 21s
Validation / validate-kubernetes (push) Failing after 8s
Validation / validate-smart-contracts (push) Failing after 8s
Validation / validate-security (push) Failing after 1m11s
Validation / validate-documentation (push) Failing after 14s
Verify Deployment / Verify Deployment (push) Failing after 45s
Ship AddressActivityRegistry V1/V2, ISO20022IntakeGateway, Chain138ParticipantSurface, checkpoint hub contracts, checkpoint-core package, aggregator/indexer/sdk services, relay profile guards, M00 diamond bridge facet, and OMNL compliance contracts. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
import { randomUUID } from 'crypto';
|
||||
import { appendOmnlAudit } from '../../services/omnl-audit-log';
|
||||
|
||||
/** Attach trace id 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();
|
||||
res.setHeader('X-OMNL-Trace-Id', traceId);
|
||||
const started = Date.now();
|
||||
res.on('finish', () => {
|
||||
appendOmnlAudit({
|
||||
category: 'api',
|
||||
action: `${req.method} ${req.path}`,
|
||||
actor: req.headers['x-omnl-actor'] as string | undefined,
|
||||
sourceSystem: (req.headers['x-omnl-source'] as string) || 'http',
|
||||
traceId,
|
||||
status: res.statusCode < 400 ? 'ok' : 'error',
|
||||
metadata: {
|
||||
statusCode: res.statusCode,
|
||||
durationMs: Date.now() - started,
|
||||
query: req.query,
|
||||
},
|
||||
});
|
||||
});
|
||||
next();
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
|
||||
function extractBearerOrQuery(req: Request, key: string): boolean {
|
||||
const auth = String(req.headers.authorization || '');
|
||||
const bearer = auth.startsWith('Bearer ') ? auth.slice(7).trim() : '';
|
||||
const q = String(req.query.access_token ?? '').trim();
|
||||
return bearer === key || q === key;
|
||||
}
|
||||
|
||||
/**
|
||||
* When `OMNL_API_KEY` is set, require `Authorization: Bearer <key>` or `?access_token=<key>`.
|
||||
* If unset, all requests pass (backwards compatible).
|
||||
@@ -10,12 +17,47 @@ export function omnlSensitiveRouteGuard(req: Request, res: Response, next: NextF
|
||||
next();
|
||||
return;
|
||||
}
|
||||
const auth = String(req.headers.authorization || '');
|
||||
const bearer = auth.startsWith('Bearer ') ? auth.slice(7).trim() : '';
|
||||
const q = String(req.query.access_token ?? '').trim();
|
||||
if (bearer === key || q === key) {
|
||||
if (extractBearerOrQuery(req, key)) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
res.status(401).json({ error: 'Unauthorized', hint: 'Set Authorization: Bearer or access_token for OMNL_API_KEY' });
|
||||
}
|
||||
|
||||
/** Public discovery endpoints (always unauthenticated). */
|
||||
const OMNL_PUBLIC_PATH_SUFFIXES = ['/omnl/openapi.json', '/omnl/catalog', '/omnl/integration-status'];
|
||||
|
||||
function isPublicOmnlPath(path: string): boolean {
|
||||
return OMNL_PUBLIC_PATH_SUFFIXES.some((s) => path.endsWith(s));
|
||||
}
|
||||
|
||||
/**
|
||||
* When `OMNL_REQUIRE_API_KEY=1` or `NODE_ENV=production`, require OMNL_API_KEY on all /omnl routes
|
||||
* except openapi.json, catalog, and integration-status.
|
||||
*/
|
||||
export function omnlRequireApiKeyInProduction(req: Request, res: Response, next: NextFunction): void {
|
||||
if (!req.path.startsWith('/omnl')) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
const requireKey =
|
||||
process.env.OMNL_REQUIRE_API_KEY === '1' ||
|
||||
(process.env.NODE_ENV || '').toLowerCase() === 'production';
|
||||
if (!requireKey || isPublicOmnlPath(req.path)) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
const key = process.env.OMNL_API_KEY?.trim();
|
||||
if (!key) {
|
||||
res.status(503).json({
|
||||
error: 'OMNL_API_KEY required in production',
|
||||
hint: 'Set OMNL_API_KEY and pass Authorization: Bearer <key>',
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (extractBearerOrQuery(req, key)) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
@@ -1,32 +1,40 @@
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import type { RequestHandler } from 'express';
|
||||
|
||||
/** express-rate-limit handlers are compatible at runtime; Express 5 typings need a narrow cast. */
|
||||
function asRateLimitMiddleware(
|
||||
handler: ReturnType<typeof rateLimit>
|
||||
): RequestHandler {
|
||||
return handler as unknown as RequestHandler;
|
||||
}
|
||||
|
||||
const windowMs = parseInt(process.env.RATE_LIMIT_WINDOW_MS || '60000', 10);
|
||||
const maxRequests = parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '100', 10);
|
||||
|
||||
export const apiRateLimiter = rateLimit({
|
||||
export const apiRateLimiter = asRateLimitMiddleware(rateLimit({
|
||||
windowMs,
|
||||
max: maxRequests,
|
||||
message: 'Too many requests from this IP, please try again later.',
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
}));
|
||||
|
||||
export const strictRateLimiter = rateLimit({
|
||||
export const strictRateLimiter = asRateLimitMiddleware(rateLimit({
|
||||
windowMs: 60 * 1000, // 1 minute
|
||||
max: 10,
|
||||
message: 'Too many requests, please try again later.',
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
}));
|
||||
|
||||
/** Stricter limit for RPC-heavy /api/v1/omnl/* (stacks with apiRateLimiter). */
|
||||
const omnlWindowMs = parseInt(process.env.OMNL_RATE_LIMIT_WINDOW_MS || '60000', 10);
|
||||
const omnlMax = parseInt(process.env.OMNL_RATE_LIMIT_MAX || '30', 10);
|
||||
|
||||
export const omnlRateLimiter = rateLimit({
|
||||
export const omnlRateLimiter = asRateLimitMiddleware(rateLimit({
|
||||
windowMs: omnlWindowMs,
|
||||
max: omnlMax,
|
||||
message: 'Too many OMNL API requests from this IP, please try again later.',
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user