修复角色动作迁移分页安全
统一 HTTP 对象与 CLI tuple 的批次哈希字段 拒绝迁移 procedure 返回重复分页游标 补充对象返回和循环游标回归测试
This commit is contained in:
@@ -281,7 +281,7 @@ export async function assertReadableFile(filePath) {
|
||||
|
||||
function normalizeProcedureResult(value, procedureName) {
|
||||
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
||||
return value;
|
||||
return normalizeSatsObject(value, procedureName);
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
@@ -291,6 +291,25 @@ function normalizeProcedureResult(value, procedureName) {
|
||||
throw new Error('procedure 返回值不是对象。');
|
||||
}
|
||||
|
||||
function normalizeSatsObject(value, procedureName) {
|
||||
const normalized = normalizeSatsValue(value);
|
||||
if (
|
||||
procedureName !==
|
||||
'normalize_editor_character_animation_metadata_and_return' ||
|
||||
!normalized ||
|
||||
typeof normalized !== 'object' ||
|
||||
Array.isArray(normalized)
|
||||
) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
const { batch_sha_256: batchSha256, ...result } = normalized;
|
||||
return {
|
||||
...result,
|
||||
batch_sha256: result.batch_sha256 ?? batchSha256,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeSatsProduct(value, procedureName) {
|
||||
if (
|
||||
procedureName === 'normalize_editor_character_animation_metadata_and_return' &&
|
||||
|
||||
@@ -148,4 +148,30 @@ describe('SpacetimeDB CLI SATS option encoding', () => {
|
||||
error_message: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('normalizes object-shaped character action procedure results', () => {
|
||||
const result = parseProcedureResult(
|
||||
JSON.stringify({
|
||||
ok: true,
|
||||
scope: 'asset',
|
||||
dry_run: true,
|
||||
scanned_count: 25,
|
||||
matched_count: 3,
|
||||
updated_count: 0,
|
||||
blocker_count: 0,
|
||||
blocker_ids: [],
|
||||
next_cursor: 'asset-25',
|
||||
has_more: true,
|
||||
batch_sha_256: 'b'.repeat(64),
|
||||
error_message: null,
|
||||
}),
|
||||
'normalize_editor_character_animation_metadata_and_return',
|
||||
);
|
||||
|
||||
expect(result).toMatchObject({
|
||||
batch_sha256: 'b'.repeat(64),
|
||||
next_cursor: 'asset-25',
|
||||
});
|
||||
expect(result).not.toHaveProperty('batch_sha_256');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -140,6 +140,7 @@ export async function scanScopes(
|
||||
const summaries = [];
|
||||
for (const scope of SCOPES) {
|
||||
let cursor = null;
|
||||
const seenCursors = new Set();
|
||||
const summary = {
|
||||
scope,
|
||||
scanned_count: 0,
|
||||
@@ -185,10 +186,17 @@ export async function scanScopes(
|
||||
}
|
||||
summary.updated_count += applied.updated_count;
|
||||
}
|
||||
cursor = dryRun.has_more ? dryRun.next_cursor : null;
|
||||
if (dryRun.has_more && !cursor) {
|
||||
const nextCursor = dryRun.has_more ? dryRun.next_cursor : null;
|
||||
if (dryRun.has_more && !nextCursor) {
|
||||
throw new Error(`${scope} scope 声明 has_more 但未返回 next_cursor。`);
|
||||
}
|
||||
if (nextCursor && seenCursors.has(nextCursor)) {
|
||||
throw new Error(`${scope} scope 返回了重复的 next_cursor: ${nextCursor}。`);
|
||||
}
|
||||
if (nextCursor) {
|
||||
seenCursors.add(nextCursor);
|
||||
}
|
||||
cursor = nextCursor;
|
||||
} while (cursor);
|
||||
summaries.push(summary);
|
||||
}
|
||||
|
||||
@@ -160,4 +160,31 @@ describe('角色动作元数据规范化脚本', () => {
|
||||
}
|
||||
expect(calls.at(-2)?.limit).toBe(5);
|
||||
});
|
||||
|
||||
it('拒绝 procedure 返回已访问过的 cursor', async () => {
|
||||
let callCount = 0;
|
||||
const callProcedure = async () => {
|
||||
callCount += 1;
|
||||
const nextCursor = ['asset-25', 'asset-50', 'asset-25'][callCount - 1];
|
||||
return {
|
||||
ok: true,
|
||||
scope: 'asset',
|
||||
dry_run: true,
|
||||
scanned_count: 1,
|
||||
matched_count: 0,
|
||||
updated_count: 0,
|
||||
blocker_count: 0,
|
||||
blocker_ids: [],
|
||||
next_cursor: nextCursor,
|
||||
has_more: true,
|
||||
batch_sha256: 'a'.repeat(64),
|
||||
error_message: null,
|
||||
};
|
||||
};
|
||||
|
||||
await expect(
|
||||
scanScopes({ chunkSize: 25 }, { callProcedure }),
|
||||
).rejects.toThrow('重复的 next_cursor: asset-25');
|
||||
expect(callCount).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user