fix: harden auth and investment synchronization
Backend security / security (push) Successful in 8s
Backend verify / verify (push) Successful in 11m9s
Conventional commits / commits (pull_request) Successful in 28s
Backend security / security (pull_request) Successful in 7s
Backend verify / verify (pull_request) Successful in 10m38s
Backend security / security (push) Successful in 8s
Backend verify / verify (push) Successful in 11m9s
Conventional commits / commits (pull_request) Successful in 28s
Backend security / security (pull_request) Successful in 7s
Backend verify / verify (pull_request) Successful in 10m38s
Resolve A01-A10 and C01-C07 from the backend audit. Preserve auth failures, forced candle reconciliation and forecast freshness. Validate MOEX responses and nested HTTP errors; remove unused legacy paths. Verified: 209 unit tests, 262 SQLite e2e tests on Linux, OpenAPI and durability. Record the remaining macOS native SQLite abort in the audit.
This commit is contained in:
@@ -14,7 +14,10 @@ describe('HttpExceptionFilter', () => {
|
||||
}),
|
||||
} as unknown as ArgumentsHost;
|
||||
|
||||
filter.catch(new Error('database password: secret'), host);
|
||||
filter.catch(
|
||||
new Error('operation failed\npassword: SYNTHETIC_AUDIT_SECRET'),
|
||||
host,
|
||||
);
|
||||
|
||||
expect(status).toHaveBeenCalledWith(500);
|
||||
expect(type).toHaveBeenCalledWith('application/problem+json');
|
||||
@@ -23,7 +26,6 @@ describe('HttpExceptionFilter', () => {
|
||||
code: 'INTERNAL_SERVER_ERROR',
|
||||
});
|
||||
expect(locals.publicErrorCode).toBe('INTERNAL_SERVER_ERROR');
|
||||
expect(typeof locals.errorStack).toBe('string');
|
||||
expect(locals.errorStack).not.toContain('database password: secret');
|
||||
expect(locals.errorStack).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,14 +27,6 @@ export class HttpExceptionFilter implements ExceptionFilter {
|
||||
? 'VALIDATION_ERROR'
|
||||
: this.codeFor(status, payload);
|
||||
(response.locals ??= {}).publicErrorCode = code;
|
||||
if (
|
||||
status >= Number(HttpStatus.INTERNAL_SERVER_ERROR) &&
|
||||
exception instanceof Error
|
||||
)
|
||||
response.locals.errorStack = exception.stack
|
||||
?.split('\n')
|
||||
.slice(1)
|
||||
.join('\n');
|
||||
response
|
||||
.status(status)
|
||||
.type('application/problem+json')
|
||||
@@ -69,12 +61,18 @@ export class HttpExceptionFilter implements ExceptionFilter {
|
||||
|
||||
private validationErrors(
|
||||
errors: ValidationError[],
|
||||
prefix = '#',
|
||||
): { pointer: string; detail: string }[] {
|
||||
return errors.flatMap((error) =>
|
||||
Object.values(error.constraints ?? {}).map((detail) => ({
|
||||
pointer: `#/${error.property}`,
|
||||
detail,
|
||||
})),
|
||||
);
|
||||
return errors.flatMap((error) => {
|
||||
if (!error || typeof error.property !== 'string') return [];
|
||||
const pointer = `${prefix}/${error.property.replaceAll('~', '~0').replaceAll('/', '~1')}`;
|
||||
return [
|
||||
...Object.values(error.constraints ?? {}).map((detail) => ({
|
||||
pointer,
|
||||
detail,
|
||||
})),
|
||||
...this.validationErrors(error.children ?? [], pointer),
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user