Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

console: isSystemRoute / isMetadataRoute 的子串判断把 /apps/未知app/system_log 认成伪路由,静默回退渲染另一个 app #3638

Closed

Description

@yinlianghui

越界发现,记录于 #3610(零应用下 component/metadata/* 白屏)期间。按纪律只报不改,单独立单,未认领,留给 PM 分诊。

实测基线:origin/main @ 8d5418e5(packages/app-shell/src/console/AppContent.tsx)。

现象

三个伪路由开关里有两个是子串判断,而不是路径段判断:

:183  const isCreateAppRoute = location.pathname.endsWith('/create-app');
:184  const isSystemRoute    = location.pathname.includes('/system');
:185  const isMetadataRoute  = location.pathname.includes('/metadata');

includes('/system') 会命中 /system 开头的任意段,不止 system 这一段本身:/apps/x/system_log、/apps/x/system_setting、/apps/x/systems 全为真。isMetadataRoute 同理(metadata_import、metadata_log……)。

后果:恰好绕开「绝不渲染另一个 app」那道守卫

isSpecialRoute 为真会同时改变两处判断(:188、:198、:207):

:198  ((!appName || isSpecialRoute)
:199     ? (launcherApps.find(a => a.isDefault === true) || launcherApps[0])
:200     : undefined);
:207  const requestedAppMissing = !!appName && !matchedApp && !isSpecialRoute;

于是访问 /apps/拼错的app名/system_log:

  1. matchedApp 为 undefined(app 名不存在);
  2. isSystemRoute 被 system_log 误命中 → isSpecialRoute 为真;
  3. requestedAppMissing 因此为 false,:547 的「App not available」守卫不触发;
  4. activeApp 回退成 默认/第一个 app,渲染它的 shell,并把 system_log 当作该 app 下的 :objectName。

:193-200 的注释正是为了防住这件事(原文:"A normal unmatched appName must NOT silently render a DIFFERENT app — the readiness guard below shows loading / not-available instead. (Fixes 'the preview / nav renders the WRONG app right after building a new one'.)")。子串判断在这条路径上把它绕开了 —— 用户看到的是另一个 app 的界面,没有任何提示说所请求的 app 不存在。

为什么不在 #3610 里顺手修

#3610 的裁定是:子串判断把请求引进分支这件事是对的,错在分支服务不了(那已由 PR #3636 补齐路由 + catch-all 修掉)。本单是另一个方向的后果 —— 判断过宽导致 requestedAppMissing 失灵 —— 与 #3610 的白屏无因果关系,单独成立。#3610 的文件面也明确不含这三行。

可能的修法(留给分诊)

改成按路径段判断,而不是子串。例如把 pathname 切段后判断某一段是否 === 'system' / === 'metadata',或用 /\/system(\/|$)/ 这类带边界的正则。

⚠️ 改动前需要先测量清楚当前依赖这层宽松的调用点:/apps/x/system/marketplace/...、/apps/x/component/metadata/resource(段位置不在 :objectName 上)、宿主 extraRoutes 的 developer/*、docs/* 等,都要确认收紧后仍为真。这正是「消费端宽松兜底」的典型代价 —— 收紧是对的,但得先把真实的输入面量出来。

严重度自评不可靠,交分诊

触发前提是「app 名不匹配」+「首段以 system / metadata 开头」。平台内建对象普遍用 sys_ 前缀而非 system_,所以命中率取决于业务对象的命名,我无法从仓内判定。按 objectstack#4949 的纪律原样上报,不预判轻重。

关联

已就关键词(isSystemRoute / isMetadataRoute / isSpecialRoute / requestedAppMissing / 子串 / includes / wrong app)搜过本仓开放 issue 与 PR,无同源单。


Generated by Claude Code

Activity

  1. claude commented on Aug 7, 2026

    @claude
    Contributor

    Triage: pm:queue confirmed, no domain:* (whole-repo seat).

    The pm:queue label the lane applied while this round was in flight matches the triage verdict, so nothing is being changed — recording the rationale so the state is auditable rather than assumed.

    Why queue and not finding. Concrete defect, named landing site, deterministic repro: packages/app-shell/src/console/AppContent.tsx:183-185 — two of the three pseudo-route switches are substring tests (includes('/system'), includes('/metadata')) where the third is a suffix test. The consequence is not cosmetic: isSpecialRoute feeds requestedAppMissing at :207, so a mistyped app name plus any first segment starting with system/metadata makes the "App not available" guard at :547 not fire, and the shell silently renders a different app — precisely what the comment block at :193-200 was written to prevent. A user-visible wrong-app render with no diagnostic is dispatchable as filed.

    No domain:* — objectui is a whole-repo seat; routing there is repo:*, and lane labels are an objectstack-only mechanism. Not transferred to the objectstack backlog either: the fix is objectui-local (one console file), not feature-level, not cross-repo, and does not touch packages/spec, so the One-main-backlog transfer rule does not bite.

    Dedup. Checked this repo and both siblings for isSystemRoute / isMetadataRoute / isSpecialRoute / requestedAppMissing and for the wrong-app-render symptom. The only neighbour is #3610 / PR #3636, which is the other consequence of the same three lines (the branch it steers into had no route to serve) and is already merged; the filer's argument that the two are causally independent holds — #3636 did not touch :183-185.

    One note for the implementer, carried from the body rather than invented here: the widening is load-bearing for real paths today (/apps/x/system/marketplace/..., /apps/x/component/metadata/resource, host extraRoutes). Measure that input surface before tightening; a segment-equality rewrite that is correct in isolation can still black-hole a live route.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. self-assigned this
    on Aug 7, 2026
  3. yinlianghui commented on Aug 7, 2026

    @yinlianghui
    ContributorAuthor

    认领(PM 派发)。

    • Session: session_01GTRjn8xBqp75dk7kFupVRt
    • 分支:claude/issue-3638-segment-route-flags
    • 文件面:packages/app-shell/src/console/AppContent.tsx(:183-185 三个开关中的两个子串判断)+ 同目录测试 + changeset。前置已落:PR fix(app-shell): 零应用分支补 component/metadata 别名路由与 catch-all (#3610) #3636/fix(app-shell): point the remaining four Settings senders at /apps/setup/system (#3611) #3637 已在 main(fa3ba5b),同文件障碍解除。
    • 裁决:改路径段判断(切段 === 'system' / === 'metadata' 或带边界正则),isCreateAppRoute 的 endsWith 不动。先量后收(issue 自己的警告):枚举当前依赖宽松判断的真实输入面(/apps/x/system/marketplace/*、/apps/setup/component/metadata/resource、system/metadata/*、developer/docs 等 extraRoutes 形态),逐条写成收紧后仍为真的回归断言,再收紧。核心逆向验证:/apps/拼错名/system_log 修后须触发 requestedAppMissing → 「App not available」守卫,不再渲染另一个 app(:193 注释的本意)。

    Generated by Claude Code

  4. yinlianghui commented on Aug 7, 2026

    @yinlianghui
    ContributorAuthor

    验收 ACCEPT → PR #3654(session_01GTRjn8xBqp75dk7kFupVRt)。

    已核:先量后收完整落地 — 10 类输入面枚举 + 28 条回归断言在未改动 main 上先行全绿,量出「今天没有任何活路由把 system/metadata 写成段前缀」的结论后才动判断;修前 8 红形态与预测一致(DOM 打出 data-active-app="crm" 的字面证据);app-shell 293 文件全绿。

    裁决记录:

    1. 切段而非正则的取舍接受(相邻 isSetupRoute 已是字面量比较风格,全文件无路由正则先例);不把判断收窄到 app 段之后的克制正确 — 两种写法行为相同处不越界。
    2. 连带变化的诚实记账记入方法库:零应用 /apps/setup/system_log 从「Page not found」改落「No Apps Configured」— 钉成 MEASUREMENT 不粉饰,正确。
    3. 反向哨兵(/apps/crm/system_log 修前修后不变,防段白名单式过度收紧)是本单设计里最容易漏的一条,做了,好。
    4. 新发现 console: 系统导航 / System Hub 的 users / organizations / roles / positions / permissions 五个入口没有对应路由 —— 两个落 "Page not found",三个跳进不存在对象 system 的记录页 #3655 入队(bug):System Hub 五入口无路由,3 个被 looksLikeRecordId 误判进不存在对象的记录页 — 用户可见。⚠️ 修复落在宿主 apps/console 路由声明,与在途 console(apps/console): MetadataRedirect / ObjectRedirect 改写到已废弃的 component/metadata/resource 别名,多绕一跳且 docblock 已过期 #3639 同文件,串行等其 PR 落 main;结论来自静态推导的标注保留,派发时要求浏览器级或路由级实测复核。

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions