fix(C3): validate screener sector filters

Reject unsupported /api/screener sector values before building the FMP query so only known sector labels reach the upstream stock screener.

Refs: docs/AUDIT_REDESIGN.md item C3.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
This commit is contained in:
Saravana Achu Mac 2026-05-04 16:44:33 -07:00
parent 222d101a7e
commit c173aeb87a
2 changed files with 29 additions and 1 deletions

View File

@ -97,6 +97,20 @@ interface RuntimeHealth {
canonicalLifecycleOrderRows?: number;
}
const ALLOWED_SCREENER_SECTORS = new Set([
'Technology',
'Financial Services',
'Healthcare',
'Consumer Cyclical',
'Consumer Defensive',
'Industrials',
'Energy',
'Utilities',
'Real Estate',
'Communication Services',
'Basic Materials',
]);
interface TradeAuditEvent {
event: string;
userId?: string;
@ -2818,7 +2832,13 @@ RULES:
try {
const apiKey = process.env.FMP_API_KEY || 'demo';
const qs = new URLSearchParams();
if (req.query.sector) qs.set('sector', String(req.query.sector));
const sector = String(req.query.sector || '').trim();
if (sector && sector !== 'All') {
if (!ALLOWED_SCREENER_SECTORS.has(sector)) {
return res.status(400).json({ error: 'Unsupported sector filter' });
}
qs.set('sector', sector);
}
if (req.query.marketCapMoreThan) qs.set('marketCapMoreThan', String(req.query.marketCapMoreThan));
if (req.query.marketCapLessThan) qs.set('marketCapLessThan', String(req.query.marketCapLessThan));
if (req.query.betaMoreThan) qs.set('betaMoreThan', String(req.query.betaMoreThan));

View File

@ -168,6 +168,14 @@ function testFmpProxyContracts() {
'https://financialmodelingprep.com/api/v3/stock-screener?${qs.toString()}',
'/api/screener must call FMP stock-screener',
);
assertSourceIncludes(
'const ALLOWED_SCREENER_SECTORS = new Set([',
'/api/screener must keep an explicit sector allow-list',
);
assertSourceMatches(
/if \(sector && sector !== 'All'\)[\s\S]*!ALLOWED_SCREENER_SECTORS\.has\(sector\)[\s\S]*status\(400\)\.json\(\{ error: 'Unsupported sector filter' \}\)[\s\S]*qs\.set\('sector', sector\)/,
'/api/screener must reject unsupported sector values before building the FMP query',
);
assertSourceIncludes(
"qs.set('isEtf', 'false')",
'/api/screener must exclude ETFs by default',