chore(connect): provider-host ratchet in check:guards, drop the dead Arcim gateway client (#2178)
* chore(connect): provider-host ratchet in check:guards, drop the dead Arcim gateway client Two boundary chores from the Connect plan. (1) A per-file ratchet in scripts/checks/no-new-antipatterns.mjs over files under lib/, app/ and extensions/ that name a provider API host (Enable Banking, Skatteverket, Qvalia, Fortnox, Visma, Briox, Bjorn Lunden, Bokio, Bolagsverket, TIC, Meta, Gmail). The 22 files that do so today are grandfathered in the baseline; a new one fails the guard with the connector routing as the remedy, and the set may only shrink as upstreams move behind the connector. (2) The client for the retired Arcim Sync gateway (extensions/general/arcim-migration/lib/ arcim-client.ts) is deleted with its test: provider-client.ts replaced it and nothing else imported it. The --update rewrite also locks in the lower naive-ore-round count (620 to 617) that main already reached. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MMUUom4fUk6zi4xYZSSfat Signed-off-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> * chore(guards): provider-host ratchet is case-insensitive and skips colocated .test.tsx; document the own-credentials exception Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> --------- Signed-off-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
Jakob Wennberg
parent
c0ecf2fa3b
commit
8c8996773f
@@ -7,7 +7,7 @@
|
||||
]
|
||||
},
|
||||
"naiveOreRound": {
|
||||
"count": 620
|
||||
"count": 617
|
||||
},
|
||||
"handRolledInvariants": {
|
||||
"count": 113
|
||||
@@ -36,5 +36,32 @@
|
||||
"rawReferenceFetch": {
|
||||
"count": 0,
|
||||
"files": []
|
||||
},
|
||||
"providerHosts": {
|
||||
"count": 22,
|
||||
"files": [
|
||||
"app/api/connect/bank/[...path]/route.ts",
|
||||
"extensions/general/bolagsverket/lib/client.ts",
|
||||
"extensions/general/enable-banking/index.ts",
|
||||
"extensions/general/enable-banking/lib/api-client.ts",
|
||||
"extensions/general/mail/lib/gmail-client.ts",
|
||||
"extensions/general/skatteverket/index.ts",
|
||||
"extensions/general/skatteverket/lib/connector-mode.ts",
|
||||
"extensions/general/skatteverket/lib/ombud-client.ts",
|
||||
"extensions/general/skatteverket/lib/skattekonto-client.ts",
|
||||
"extensions/general/tic/index.ts",
|
||||
"extensions/general/tic/lib/bankid-client.ts",
|
||||
"extensions/general/tic/lib/bankid-types.ts",
|
||||
"extensions/general/whatsapp-inbox/lib/graph-api.ts",
|
||||
"lib/connect/upstreams/enable-banking-jwt.ts",
|
||||
"lib/invoices/transports/qvalia.ts",
|
||||
"lib/providers/bjornlunden/config.ts",
|
||||
"lib/providers/bjornlunden/oauth.ts",
|
||||
"lib/providers/bokio/client.ts",
|
||||
"lib/providers/bokio/config.ts",
|
||||
"lib/providers/briox/config.ts",
|
||||
"lib/providers/fortnox/config.ts",
|
||||
"lib/providers/visma/config.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,6 +390,34 @@ function countNaiveRound() {
|
||||
return count
|
||||
}
|
||||
|
||||
/**
|
||||
* 9. provider-host: files that talk to an external provider API directly.
|
||||
* Provider integration logic is moving behind the connector (hosted
|
||||
* `app/api/connect/*` today, the Accounted Connect service later): the open
|
||||
* repo keeps the ledger, the contract and the manual file paths, and a
|
||||
* self-hosted instance reaches every provider through its connector key.
|
||||
* Per-file ratchet: the grandfathered set may only shrink. A NEW file naming a
|
||||
* provider API host is a boundary violation unless it is the connector's own
|
||||
* hosted adapter side.
|
||||
*/
|
||||
const PROVIDER_HOST_RE =
|
||||
/api\.enablebanking\.com|api\.tilisy\.com|api\.skatteverket\.se|peroauth2\.skatteverket\.se|sso\.skatteverket\.se|api\.qvalia\.com|api-test\.qvalia\.com|api\.fortnox\.se|apps\.fortnox\.se|vismaonline\.com|briox\.services|apigateway\.blinfo\.se|api\.bokio\.se|api\.bolagsverket\.se|api-accept2\.bolagsverket\.se|id\.tic\.io|graph\.facebook\.com|gmail\.googleapis\.com/i
|
||||
|
||||
function findProviderHostFiles() {
|
||||
const files = [
|
||||
...walk(path.join(ROOT, 'lib'), ['.ts', '.tsx']),
|
||||
...walk(path.join(ROOT, 'app'), ['.ts', '.tsx']),
|
||||
...walk(path.join(ROOT, 'extensions'), ['.ts', '.tsx']),
|
||||
]
|
||||
const found = []
|
||||
for (const f of files) {
|
||||
const r = rel(f)
|
||||
if (r.includes('__tests__/') || r.endsWith('.test.ts') || r.endsWith('.test.tsx')) continue
|
||||
if (PROVIDER_HOST_RE.test(fs.readFileSync(f, 'utf8'))) found.push(r)
|
||||
}
|
||||
return found.sort()
|
||||
}
|
||||
|
||||
/**
|
||||
* Occurrences of a shared format rule written out by hand instead of imported
|
||||
* from lib/invariants/. Counted, not file-setted: the campaign lowers the
|
||||
@@ -1025,6 +1053,7 @@ const current = {
|
||||
rawRouteAuth: findRawRouteAuth(),
|
||||
naiveOreRound: countNaiveRound(),
|
||||
handRolledInvariants: countHandRolledInvariants(),
|
||||
providerHosts: findProviderHostFiles(),
|
||||
ledgerScanningReports: findLedgerScanningReports(),
|
||||
directJelInsert: findDirectJelInserts(),
|
||||
leakySupabaseClients: findLeakySupabaseClients(),
|
||||
@@ -1064,6 +1093,10 @@ if (isUpdate) {
|
||||
count: current.rawReferenceFetch.length,
|
||||
files: current.rawReferenceFetch,
|
||||
},
|
||||
providerHosts: {
|
||||
count: current.providerHosts.length,
|
||||
files: current.providerHosts,
|
||||
},
|
||||
}
|
||||
fs.writeFileSync(BASELINE_PATH, JSON.stringify(baseline, null, 2) + '\n')
|
||||
console.log(
|
||||
@@ -1344,6 +1377,26 @@ if (newLedgerScans.length) {
|
||||
)
|
||||
}
|
||||
|
||||
// 1c2. provider-host: a file naming a provider API host outside the
|
||||
// grandfathered set is a NEW direct integration in the open repo.
|
||||
const providerHostBaseline = new Set(baseline.providerHosts?.files ?? [])
|
||||
const newProviderHosts = current.providerHosts.filter((f) => !providerHostBaseline.has(f))
|
||||
const fixedProviderHosts = (baseline.providerHosts?.files ?? []).filter((f) => !current.providerHosts.includes(f))
|
||||
if (baseline.providerHosts && newProviderHosts.length) {
|
||||
failed = true
|
||||
console.error(
|
||||
`\n✗ provider-host: ${newProviderHosts.length} new file(s) call a provider API host directly:`,
|
||||
)
|
||||
newProviderHosts.forEach((f) => console.error(` ${f}`))
|
||||
console.error(
|
||||
' → provider integration logic lives behind the connector, not in the open ledger:\n' +
|
||||
' route the call through the hosted connector (app/api/connect/*) and the\n' +
|
||||
' instance-side connector-mode seam (lib/connect/instance/upstreams.ts), or\n' +
|
||||
' keep the manual file path. If this file IS the connector\'s own hosted adapter\n' +
|
||||
' side, re-baseline with --update and say so in the PR.',
|
||||
)
|
||||
}
|
||||
|
||||
// 1d. raw-reference-fetch: per-file ratchet. A file outside the baseline set
|
||||
// that fetches reference data raw (see raw-reference-fetch.mjs) is a NEW
|
||||
// violation; grandfathered files stay until they move to the hooks. Once the
|
||||
@@ -1410,6 +1463,7 @@ if (
|
||||
fixedLedgerScans.length ||
|
||||
fixedDialogOverflow.length ||
|
||||
fixedRawRefs.length ||
|
||||
fixedProviderHosts.length ||
|
||||
current.naiveOreRound < baseline.naiveOreRound.count
|
||||
) {
|
||||
console.log('\n✓ Progress since baseline:')
|
||||
@@ -1422,6 +1476,8 @@ if (
|
||||
console.log(` raw-reference-fetch: -${fixedRawRefs.length} file(s)`)
|
||||
if (current.naiveOreRound < baseline.naiveOreRound.count)
|
||||
console.log(` naive-ore-round: -${baseline.naiveOreRound.count - current.naiveOreRound} occurrence(s)`)
|
||||
if (fixedProviderHosts.length)
|
||||
console.log(` provider-host: -${fixedProviderHosts.length} file(s) no longer call a provider directly`)
|
||||
console.log(' Run with --update to ratchet the baseline down and lock in the gains.')
|
||||
}
|
||||
if (migratedDirectAi.length) {
|
||||
@@ -1444,5 +1500,5 @@ if (failed) {
|
||||
process.exit(1)
|
||||
}
|
||||
console.log(
|
||||
`\n✓ Antipattern guard passed (raw-route-auth: ${current.rawRouteAuth.length}, naive-ore-round: ${current.naiveOreRound}, hand-rolled-invariant: ${current.handRolledInvariants}, ledger-scanning-report: ${current.ledgerScanningReports.length}, direct-jel-insert: 0, leaky-supabase-client: 0, pinned-dep: 0, raw-user-error: 0, sek-labelled-amount: 0, off-ladder-radius: 0, folded-public-flag: 0, cross-extension-import: 0, ungated-extension-route: ${current.extensionRoutes.ungated.length}/${UNGATED_EXTENSION_ROUTES.size} allowlisted, dialog-overflow-risk: ${dialogOverflowFiles.length} file(s), raw-reference-fetch: ${current.rawReferenceFetch.length} file(s), client-node-builtin: ${current.clientNodeBuiltins.length}, ambiguous-embed: ${current.ambiguousEmbeds.length}, direct-ai-client: ${current.directAiClients.length}/${DIRECT_AI_CLIENT_ALLOWED.size} allowlisted).`,
|
||||
`\n✓ Antipattern guard passed (raw-route-auth: ${current.rawRouteAuth.length}, naive-ore-round: ${current.naiveOreRound}, hand-rolled-invariant: ${current.handRolledInvariants}, ledger-scanning-report: ${current.ledgerScanningReports.length}, direct-jel-insert: 0, leaky-supabase-client: 0, pinned-dep: 0, raw-user-error: 0, sek-labelled-amount: 0, off-ladder-radius: 0, folded-public-flag: 0, cross-extension-import: 0, ungated-extension-route: ${current.extensionRoutes.ungated.length}/${UNGATED_EXTENSION_ROUTES.size} allowlisted, dialog-overflow-risk: ${dialogOverflowFiles.length} file(s), raw-reference-fetch: ${current.rawReferenceFetch.length} file(s), client-node-builtin: ${current.clientNodeBuiltins.length}, ambiguous-embed: ${current.ambiguousEmbeds.length}, provider-host: ${current.providerHosts.length} file(s), direct-ai-client: ${current.directAiClients.length}/${DIRECT_AI_CLIENT_ALLOWED.size} allowlisted).`,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user