fix: close remaining Z39 slug isolation gaps
Bind preview rows and published API base paths to the active module slug so cloned or stale state cannot address another module. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -186,9 +186,8 @@ func (l *PublishLogic) Publish(slug string, req *types.PublishReq) (*types.Publi
|
|||||||
if slug != "" && slug != incoming.Meta.Slug {
|
if slug != "" && slug != incoming.Meta.Slug {
|
||||||
incoming.Meta.Slug = slug
|
incoming.Meta.Slug = slug
|
||||||
}
|
}
|
||||||
if incoming.Apis.BasePath == "" || strings.Contains(incoming.Apis.BasePath, "-") {
|
// Z39:API 地址只由本次发布路径 slug 决定,禁止克隆蓝图沿用旧模块 base_path。
|
||||||
incoming.Apis.BasePath = "/api/v1/apps/" + slug
|
incoming.Apis.BasePath = "/api/v1/apps/" + slug
|
||||||
}
|
|
||||||
|
|
||||||
mode := strings.ToLower(strings.TrimSpace(req.Mode))
|
mode := strings.ToLower(strings.TrimSpace(req.Mode))
|
||||||
if mode == "" {
|
if mode == "" {
|
||||||
@@ -568,9 +567,7 @@ func (l *PublishLogic) publishHostMetaOnly(
|
|||||||
bp := existing.Blueprint
|
bp := existing.Blueprint
|
||||||
bp.Meta.Name = moduleName
|
bp.Meta.Name = moduleName
|
||||||
bp.Meta.Slug = slug
|
bp.Meta.Slug = slug
|
||||||
if bp.Apis.BasePath == "" {
|
bp.Apis.BasePath = "/api/v1/apps/" + slug
|
||||||
bp.Apis.BasePath = "/api/v1/apps/" + slug
|
|
||||||
}
|
|
||||||
|
|
||||||
rec := existing
|
rec := existing
|
||||||
rec.Name = moduleName
|
rec.Name = moduleName
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
2
web/dist/index.html
vendored
2
web/dist/index.html
vendored
@@ -7,7 +7,7 @@
|
|||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,600;9..144,700&family=Manrope:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,600;9..144,700&family=Manrope:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||||||
<script type="module" crossorigin src="/assets/index-Pe8anoMp.js"></script>
|
<script type="module" crossorigin src="/assets/index-D2ZGs_V_.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-CtqUfnO-.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-CtqUfnO-.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -386,7 +386,12 @@ export async function listRows(
|
|||||||
: `${PLATFORM}/api/v1/public/apps/${slug}/${resource}?${qs}`;
|
: `${PLATFORM}/api/v1/public/apps/${slug}/${resource}?${qs}`;
|
||||||
// 草稿预览:优先用预览包内嵌行数据(未发布也可出图)
|
// 草稿预览:优先用预览包内嵌行数据(未发布也可出图)
|
||||||
const prev = getActivePreview();
|
const prev = getActivePreview();
|
||||||
if (prev && (!resource || resource === prev.resource || !prev.resource)) {
|
const previewSlug = String(prev?.blueprint?.meta?.slug || "");
|
||||||
|
if (
|
||||||
|
prev &&
|
||||||
|
previewSlug === slug &&
|
||||||
|
(!resource || resource === prev.resource || !prev.resource)
|
||||||
|
) {
|
||||||
let items = prev.rows || [];
|
let items = prev.rows || [];
|
||||||
if (filters) {
|
if (filters) {
|
||||||
items = items.filter((row) =>
|
items = items.filter((row) =>
|
||||||
|
|||||||
@@ -1285,10 +1285,10 @@ POST /api/v1/agent/sync/channels/{id}/pull
|
|||||||
|
|
||||||
1. **根因修复**:智能体绑定的 `database_name` 是多模块共享库;旧逻辑却强制 `database_per_app/public`,导致不同 slug 的同名实体表复用。现改为共享库内 `schema_per_app`,每个模块使用独立 `app_t{tenant}_{slug}`;旧 `public` 模块重发时升级到独立 Schema,随后由双向同步重新灌入所属数据。
|
1. **根因修复**:智能体绑定的 `database_name` 是多模块共享库;旧逻辑却强制 `database_per_app/public`,导致不同 slug 的同名实体表复用。现改为共享库内 `schema_per_app`,每个模块使用独立 `app_t{tenant}_{slug}`;旧 `public` 模块重发时升级到独立 Schema,随后由双向同步重新灌入所属数据。
|
||||||
2. **标识符防碰撞**:Schema/独立库名超过 48 字符时保留可读前缀并附加 slug 内容哈希,不再直接截断造成长 slug 碰撞。
|
2. **标识符防碰撞**:Schema/独立库名超过 48 字符时保留可读前缀并附加 slug 内容哈希,不再直接截断造成长 slug 碰撞。
|
||||||
3. **页面防串包**:hash 路由加载增加请求序号,快速切换模块时旧请求不得覆盖新蓝图;加载期间卸载旧模块,且校验返回蓝图 `meta.slug` 必须等于 URL slug。蓝图/数据 GET 使用 `no-store`。
|
3. **页面防串包**:hash 路由加载增加请求序号,快速切换模块时旧请求不得覆盖新蓝图;加载期间卸载旧模块,且校验返回蓝图 `meta.slug` 必须等于 URL slug。预览行缓存同时校验 slug+resource;蓝图/数据 GET 使用 `no-store`。
|
||||||
4. **回执与 capsule 可核对**:publish 增加 `blueprint_revision`、`resource_tables`;agent-capsule 增加 `app_slug`、`schema_name`、revision 和各资源物理 table。
|
4. **回执与 capsule 可核对**:publish 增加 `blueprint_revision`、`resource_tables`;agent-capsule 增加 `app_slug`、`schema_name`、revision 和各资源物理 table。
|
||||||
5. **诊断与拒绝回退**:CRUD 解析后强校验 requested slug 与 resolved app 一致、Schema/table 非空;日志记录 tenant、requested slug、resource、resolved Schema/table、revision。现有 Meta 查询仍严格按 `tenant_id + slug`,不存在默认模块回退。
|
5. **诊断与拒绝回退**:CRUD 解析后强校验 requested slug 与 resolved app 一致、Schema/table 非空;日志记录 tenant、requested slug、resource、resolved Schema/table、revision。现有 Meta 查询仍严格按 `tenant_id + slug`,不存在默认模块回退。
|
||||||
6. **缓存说明**:当前仓无按页面结构复用的构建产物缓存;以 tenant+slug 定位元数据并以蓝图 revision 作为诊断/响应标识,HTTP 明确 `no-store`,避免旧运行时配置被复用。
|
6. **缓存与路径说明**:当前仓无按页面结构复用的构建产物缓存;以 tenant+slug 定位元数据并以蓝图 revision 作为诊断/响应标识,HTTP 明确 `no-store`。发布(含仅改 host_meta)无条件把 `apis.base_path` 重写为当前 slug,禁止克隆蓝图沿用旧模块路径。
|
||||||
|
|
||||||
#### 宇恒改(须)
|
#### 宇恒改(须)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user