V13-FE-011: finalize search list layout slice
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import fs from 'node:fs'
|
||||
const read=p=>JSON.parse(fs.readFileSync(p,'utf8'))
|
||||
const src=read('contracts/providers/kbx.providers.json')
|
||||
const manifest=read('generated/provider-manifest.json')
|
||||
const errors=[]
|
||||
const ids=new Set()
|
||||
const officialHosts=['openapi.krx.co.kr','opendart.fss.or.kr','apiportal.koreainvestment.com','github.com']
|
||||
for(const p of src.providers??[]){
|
||||
if(ids.has(p.id))errors.push(`duplicate provider ${p.id}`);ids.add(p.id)
|
||||
if(p.mutationAllowed)errors.push(`${p.id}: v20 providers must remain read-only`)
|
||||
for(const u of p.officialSources??[]){const host=new URL(u).host;if(!officialHosts.includes(host))errors.push(`${p.id}: non-official source host ${host}`)}
|
||||
}
|
||||
const krx=src.providers.find(x=>x.id==='provider.krx.openapi')
|
||||
if(!krx)errors.push('missing KRX provider')
|
||||
else {if(krx.official.authentication?.headerName!=='AUTH_KEY')errors.push('KRX AUTH_KEY header drift');if(krx.official.numericRateLimit!==null)errors.push('KRX universal numeric rate limit must stay unknown unless officially verified');if(krx.kbxPolicy.allowedHostSuffix!=='.krx.co.kr')errors.push('KRX approved host suffix guard missing')}
|
||||
const dart=src.providers.find(x=>x.id==='provider.opendart')
|
||||
if(!dart)errors.push('missing OPENDART provider')
|
||||
else {if(dart.official.baseUri!=='https://opendart.fss.or.kr/api/')errors.push('OPENDART base URI drift');if(dart.official.authentication?.parameterName!=='crtfc_key'||dart.official.authentication?.length!==40)errors.push('OPENDART auth contract drift');for(const c of ['000','013','020','800','900','901'])if(!dart.official.statusCodes?.[c])errors.push(`OPENDART status missing ${c}`);for(const op of ['list.json','company.json','corpCode.xml'])if(!(dart.operations??[]).some(x=>x.path===op))errors.push(`OPENDART operation missing ${op}`)}
|
||||
const kis=src.providers.find(x=>x.id==='provider.kis.market-data')
|
||||
if(!kis)errors.push('missing KIS provider')
|
||||
else {if(kis.official.authentication?.tokenPath!=='/oauth2/tokenP'||kis.official.authentication?.grantType!=='client_credentials')errors.push('KIS OAuth contract drift');if(kis.official.productionRequestsPerSecond!==18||kis.official.sandboxRequestsPerSecond!==1||kis.official.tokenRequestsPerSecond!==1)errors.push('KIS official rate-limit facts drift');const price=(kis.operations??[]).find(x=>x.id==='kis.domestic-stock.current-price');if(!price||price.method!=='GET'||price.path!=='/uapi/domestic-stock/v1/quotations/inquire-price'||price.trId!=='FHKST01010100')errors.push('KIS current-price official sample contract drift')}
|
||||
if(manifest.providers.length!==src.providers.length)errors.push('provider manifest count drift')
|
||||
const ts=fs.readFileSync('packages/kbx-contracts/src/generated/providerCatalog.ts','utf8'),cs=fs.readFileSync('backend/Shared/Providers/Generated/KbxExternalProviderCatalog.g.cs','utf8')
|
||||
if(!ts.includes(manifest.sourceSha256)||!cs.includes(manifest.sourceSha256))errors.push('provider source SHA parity missing')
|
||||
const krxCode=fs.readFileSync('backend/Shared/Providers/KrxOpenApiAdapter.cs','utf8')
|
||||
for(const token of ['AUTH_KEY','.krx.co.kr','IKbxProviderSecretStore'])if(!krxCode.includes(token))errors.push(`KRX adapter missing ${token}`)
|
||||
const dartCode=fs.readFileSync('backend/Shared/Providers/OpenDartAdapter.cs','utf8')
|
||||
for(const token of ['crtfc_key','"013"','"020"','"800"','"900"'])if(!dartCode.includes(token))errors.push(`OPENDART adapter missing ${token}`)
|
||||
const kisCode=fs.readFileSync('backend/Shared/Providers/KisMarketDataAdapter.cs','utf8')
|
||||
for(const token of ['HttpMethod.Get','FHKST01010100','authorization','appkey','appsecret','tr_id'])if(!kisCode.includes(token))errors.push(`KIS adapter missing ${token}`)
|
||||
if(/HttpMethod\.Post/.test(kisCode))errors.push('KIS market-data adapter must not contain POST trading calls')
|
||||
for(const f of ['KrxOpenApiAdapter.cs','OpenDartAdapter.cs','KisAccessTokenProvider.cs','KisMarketDataAdapter.cs']){
|
||||
const code=fs.readFileSync(`backend/Shared/Providers/${f}`,'utf8')
|
||||
if(/Console\.Write/i.test(code)) errors.push(`${f}: console logging is forbidden in provider adapters`)
|
||||
if(/LogInformation\([^)]*(appsecret|AuthKey|access_token)/i.test(code)) errors.push(`${f}: possible secret logging`)
|
||||
}
|
||||
for(const f of ['tests/fixtures/providers/opendart-no-data.json','tests/fixtures/providers/opendart-rate-limit.json','tests/fixtures/providers/kis-current-price-success.json','backend/tests/Providers/KrxProviderPolicyTests.cs','backend/tests/Providers/OpenDartProviderPolicyTests.cs','backend/tests/Providers/KisProviderPolicyTests.cs'])if(!fs.existsSync(f))errors.push(`missing provider test artifact ${f}`)
|
||||
if(errors.length){console.error('provider governance FAIL');for(const e of errors)console.error(`- ${e}`);process.exit(1)}
|
||||
console.log(`provider governance PASS: providers=${src.providers.length}, official-only sources, read-only boundary, secret isolation`)
|
||||
Reference in New Issue
Block a user