Skip to content

fix: 全量代码审查修复 — 安全/Console/OpenAPI/类型/性能(72 项)#4

Merged
Yuerchu merged 7 commits into
mainfrom
fix/code-review-fixes
Jun 15, 2026
Merged

fix: 全量代码审查修复 — 安全/Console/OpenAPI/类型/性能(72 项)#4
Yuerchu merged 7 commits into
mainfrom
fix/code-review-fixes

Conversation

@Yuerchu

@Yuerchu Yuerchu commented Jun 15, 2026

Copy link
Copy Markdown
Owner

背景

对 apilot 做了 14 维度并行代码审查 + 逐条对抗性验证,确认 72 个真实问题(high 8 / medium 20 / low 34 / info 10)。核心风险是系统性盲区:项目把"加载任意第三方 spec / 分享链接 / URL 参数"当核心功能,却普遍将这些不可信输入当可信数据。本 PR 分 7 批修复,每批可独立 review。

三个产品决策:凭证仅 UI 告知(不加密)· SSRF 同源+内网白名单(保留多文件 spec)· specId 不改主键、改冲突检测。

改动(P0 → P2)

  • 安全 P0 — 不可信 spec 输入加固:SSRF external $ref 同源/内网白名单(新增 url-guard.ts,库自带 safeUrlResolver 在浏览器失效,自行拦截)、spec 体积上限、openapi_url 协议白名单、RandExp 量词 DoS、resolve-schema 原型污染
  • 安全 P0 — 凭证泄露路径:curl 回退分支单引号转义(命令注入)、历史记录四处脱敏(requestBody/params/response/重复 requestBody,含自定义 API-key header)、OAuth2 tokenUrl 校验、auth_token 移出 URL 入站、header CRLF、WS token URL 掩码
  • 安全 P1 — 纵深防御:PWA 不缓存带 Authorization 的 spec 响应、CSP(主应用 build 时注入 + CLI 模板)、凭证明文存储 UI 告知
  • 功能 P1 — Console builder 可用性:详情/编辑/配置/Stats/动作模板的路径参数输入(新增 PathParamFields,消除 id'd 资源静默空白)、fetchJson 错误反馈、schema 推断支持 allOf / OAS 3.1
  • 功能 P1 — OpenAPI 正确性:循环引用生成部分示例(而非 null)、生成器边界钳制、diff/diagnostics 按结构化路径分类、2XX 范围与 $ref 响应处理
  • 类型 P2:exclusiveMinimum/Maximum number|boolean、Reference Object 建模、getTypeStr enum/anyOf/oneOf、FormData 诚实编码、去冗余断言
  • 性能/持久化 P2:context value memo(防全树重渲染)、deleteSpec 原子事务(防孤儿凭证)、specId 冲突检测、clearWsHistory key range、getEnvironmentRuntimes 单事务、收藏乐观更新回滚、JsonSchemaTreeView 行 memo

验证

  • tsc --noEmit:0 错误
  • eslint .:0 错误(28 个 warning 全部为预存的 set-state-in-effect,非本次引入)
  • vitest:213 passed(新增 url-guard / db 脱敏 / schema-inference / generate-example / curl 转义等测试)
  • vite build:成功,确认 CSP meta 注入产物、PWA SW 正确排除带凭证请求

有意保留(low/info,回归风险 > 收益)

db.ts 完整 DBSchema 泛型(牵动 migration 游标)· SchemaForm 的 RHF 动态表单断言 · 完整列表虚拟化与大组件深度 memo(需运行时滚动验证)· use-auth/use-env-vars 卸载守卫(React 18 下为 no-op)

🤖 Generated with Claude Code

Yuerchu and others added 7 commits June 15, 2026 12:12
…tifier/proto guards)

- url-guard: same-origin + private-network blocklist for external $ref; the
  library's safeUrlResolver is a no-op in browsers, so enforce it ourselves
- parser: custom http resolver vets every external $ref, degrades blocked ones
  to empty schema and surfaces a warning; options built per spec source origin
- fetch-utils: cap untrusted response bodies (25MB) via Content-Length + streaming
- use-openapi: openapi_url scheme allowlist (http/https only); capped reads
- generate-example: reject oversized regex quantifiers before RandExp, slice output
- resolve-schema: skip __proto__/constructor/prototype keys when merging

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…edaction, oauth2/url guards)

- build-snippet: POSIX single-quote-escape url/header/body in the curl fallback
  (the fallback fires on relative URLs, so it's a real paste-to-shell injection vector)
- db: redact credential fields in stored history — request body, params, response
  body, and the duplicate response.requestBody; dynamic curl redaction now covers
  custom API-key header names; precise normalized key set avoids over-redaction
- use-auth: reject non-http(s) and plaintext-http (non-loopback) OAuth2 tokenUrl
- use-settings: validate auth_type via authTypeValue, stop reading auth_token from
  the URL, strip sensitive query params from the address bar after load
- use-request: strip CR/LF from header values; warn once per host before sending
  credentials to a host not declared in the spec's servers
- channels: mask the WS token in the URL preview (browser API forces query transport)
- i18n: add tokenUrlInvalid/tokenUrlInsecure/credentialCrossHost across all locales

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…l notice

- vite PWA: never cache credentialed spec fetches (Authorization header excluded
  from the api-specs route); only cache 200s
- use-openapi: cache:'no-store' on credentialed spec fetch (HTTP-cache layer)
- vite: inject a build-only CSP meta (object-src 'none', base-uri 'self',
  frame-ancestors 'none', restricted script/style/img origins; connect-src left
  open for the testing tool; 'unsafe-eval' kept for ajv runtime compilation)
- cli/build-template: same CSP injected into generated single/multi templates
- AuthSettings: warn that credentials are stored unencrypted in the browser
- vite: document that the AG Grid Enterprise license is necessarily client-embedded
- i18n: add auth.plaintextWarning across all locales

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… for id'd resources

- PathParamFields: reusable inline editor for a route's path params (+ load action)
- detail/editor/config/stats: render path-param inputs and a Load button when the
  read op needs an id; auto-load only for parameter-less singletons (no more silent
  blank pages); pass path params through to update/mutate
- ConsoleActionButton/ActionForm: collect path params for actions like
  POST /users/{id}/activate; inherit them from the parent detail page when present;
  disable execute until required params are filled
- use-console-fetch: surface validation/baseUrl errors (errorRef) instead of a
  silent {data:null,error:null}; report JSON parse errors
- use-request: expose errorRef (synchronous last-error mirror)
- schema-inference: resolve allOf / OAS 3.1 array types before pagination & list-item
  detection; share PAGINATION_TOTAL_FIELDS with ConsoleListPage (case-insensitive total)
- tests: schema-inference allOf / 3.1 coverage

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cs correctness

- parser: mark residual { $ref } nodes (circular:"ignore" leftovers) with _circular,
  fulfilling the marker contract so display guards become live
- generate-example: prune residual/_circular ref nodes before sampling so circular
  schemas yield a partial example instead of null; clamp inverted exclusive numeric
  bounds; guard the time-format non-null assertion; wrap generateWithVariant in
  try/catch and clamp str-alpha length so minLength>30 no longer throws
- diff: classify request/response changes by structural path position, not a
  substring match anywhere in the path
- diagnostics: recognize the 2XX range shorthand; skip referenced ({$ref}) responses
  instead of falsely reporting missing-response-schema; bail scanSchema on ref nodes
- tests: circular partial example, variant bounds, inverted exclusive bounds

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Data, casts

- types: exclusiveMinimum/Maximum is number|boolean (OAS 3.0 boolean vs 3.1 number);
  Response/RequestBody/Parameter carry an optional $ref so reference nodes in a
  source (non-dereferenced) spec are type-honest
- type-str: render object enum values via JSON.stringify (no [object Object]);
  handle anyOf/oneOf nullable unions incl. OAS 3.1 {type:["null"]}; render OAS 3.0
  boolean exclusive bounds as strict </> instead of "true"
- diagnostics: drop the response $ref cast now that ResponseObject types it
- use-request: encode urlencoded bodies honestly (string fields only) instead of
  casting FormData to Record<string,string>
- use-auth: type the token response instead of reading .access_token off any
- AppSidebar: drop 8 redundant `as MainView` casts (let the union check literals)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…imistic rollback

- OpenAPIContext / useEnvironments / useMultiEnvStatus: memoize the provider value
  so consumers don't re-render on every provider render
- db.deleteSpec: cascade in a single atomic transaction (all-or-nothing) so a
  mid-way failure can't orphan records — notably token-bearing credentials
- db.putSpecFromDocument: warn when a same-id spec has different content (history/
  favorites/credentials may not align); primary key unchanged, no migration
- db.clearWsHistory: bound the cursor to specId (and channel) instead of full scan
- db.getEnvironmentRuntimes: read credentials in one transaction, not per-profile
- use-favorites: optimistic toggle now uses functional updates and rolls back on
  persistence failure
- JsonSchemaTreeView: memoize flattenTree result and React.memo the row
- test mock updated for multi-store transactions

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Yuerchu Yuerchu merged commit b59cce4 into main Jun 15, 2026
3 checks passed
@Yuerchu Yuerchu deleted the fix/code-review-fixes branch June 15, 2026 05:58
Yuerchu added a commit that referenced this pull request Jun 15, 2026
fix(review): 处理 PR #4 review 发现(SSRF 自动加载/ref 上限/PWA cookie/编辑 path 参/共享 schema)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant