Merge pull request #2561 from pikasTech/fix/2541-unscoped-identity
Pipelines as Code CI / hwlab-nc01-v03-ci-poll- Success
Pipelines as Code CI / hwlab-nc01-v03-ci-poll- Success
修复:过滤观察流缺失身份事件
This commit is contained in:
@@ -41,7 +41,7 @@ test("retention handoff replays once, deduplicates overlap and late pre-barrier
|
||||
"buffered-live:4:hwlab:evt_0_4",
|
||||
"connected:1"
|
||||
]);
|
||||
assert.deepEqual(summary.counts, { matched: 3, filteredNonHwlab: 0, replayed: 3, buffered: 3, bufferedDelivered: 2, liveDelivered: 0, deduplicated: 1, resumeSkipped: 0 });
|
||||
assert.deepEqual(summary.counts, { matched: 3, filteredNonHwlab: 0, filteredMissingIdentity: 0, replayed: 3, buffered: 3, bufferedDelivered: 2, liveDelivered: 0, deduplicated: 1, resumeSkipped: 0 });
|
||||
|
||||
publishLive(record(2).value, transport(2));
|
||||
publishLive(record(5).value, transport(5));
|
||||
@@ -101,7 +101,7 @@ test("retention emits handoff before buffered live flush and connected live", as
|
||||
assert.deepEqual(phases, ["replay:0", "replay:1", "handoff", "buffered-live:2", "live"]);
|
||||
});
|
||||
|
||||
test("unscoped observer filters legacy non-HWLAB records without weakening scoped handoff", async () => {
|
||||
test("unscoped observer filters non-deliverable history without weakening scoped handoff", async () => {
|
||||
let publishLive: any = null;
|
||||
const delivered: string[] = [];
|
||||
const legacy = { ...record(0), value: { schema: "platform-infra.kafka.shadow-produce.v1", eventId: "legacy-smoke" } };
|
||||
@@ -111,16 +111,17 @@ test("unscoped observer filters legacy non-HWLAB records without weakening scope
|
||||
subscribeLive(listener: any) { publishLive = listener; return () => {}; },
|
||||
async queryRetention() {
|
||||
publishLive({ schema: "platform-infra.kafka.shadow-produce.v1", eventId: "legacy-live" }, transport(2));
|
||||
return queryResult([legacy, record(1)], [{ partition: 0, startOffset: "0", endOffset: "2" }]);
|
||||
return queryResult([legacy, { ...record(1), value: { schema: "hwlab.event.v1", eventType: "legacy-without-identity" } }, record(2)], [{ partition: 0, startOffset: "0", endOffset: "3" }]);
|
||||
},
|
||||
async deliverEvent(envelope: any) { delivered.push(envelope.eventId); return true; },
|
||||
async deliverConnected() { return true; }
|
||||
});
|
||||
|
||||
const summary = await handoff.start();
|
||||
assert.deepEqual(delivered, ["hwlab:evt_0_1"]);
|
||||
assert.equal(summary.counts.matched, 2);
|
||||
assert.deepEqual(delivered, ["hwlab:evt_0_2"]);
|
||||
assert.equal(summary.counts.matched, 3);
|
||||
assert.equal(summary.counts.filteredNonHwlab, 2);
|
||||
assert.equal(summary.counts.filteredMissingIdentity, 1);
|
||||
assert.equal(summary.counts.replayed, 1);
|
||||
});
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ export function createWorkbenchKafkaRefreshHandoff(options = {}) {
|
||||
const counts = {
|
||||
matched: 0,
|
||||
filteredNonHwlab: 0,
|
||||
filteredMissingIdentity: 0,
|
||||
replayed: 0,
|
||||
buffered: 0,
|
||||
bufferedDelivered: 0,
|
||||
@@ -101,9 +102,12 @@ export function createWorkbenchKafkaRefreshHandoff(options = {}) {
|
||||
|
||||
function onLiveEnvelope(envelope, transport) {
|
||||
if (phase === "closed" || phase === "failed") return;
|
||||
if (allowUnscoped && envelope?.schema !== "hwlab.event.v1") {
|
||||
counts.filteredNonHwlab += 1;
|
||||
return;
|
||||
if (allowUnscoped) {
|
||||
const filtered = unscopedEnvelopeFilter(envelope);
|
||||
if (filtered) {
|
||||
counts[filtered] += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!envelopeMatchesScope(envelope, sessionId, traceId)) return;
|
||||
if (phase !== "live") {
|
||||
@@ -192,9 +196,12 @@ export function createWorkbenchKafkaRefreshHandoff(options = {}) {
|
||||
const normalized = [];
|
||||
for (const record of records) {
|
||||
const envelope = record?.value;
|
||||
if (allowUnscoped && envelope?.schema !== "hwlab.event.v1") {
|
||||
counts.filteredNonHwlab += 1;
|
||||
continue;
|
||||
if (allowUnscoped) {
|
||||
const filtered = unscopedEnvelopeFilter(envelope);
|
||||
if (filtered) {
|
||||
counts[filtered] += 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!envelopeMatchesScope(envelope, sessionId, traceId) || envelope?.schema !== "hwlab.event.v1") {
|
||||
throw handoffError("workbench_kafka_refresh_scope_mismatch", "Kafka retention query returned an envelope outside the authorized scope.", phase);
|
||||
@@ -450,6 +457,12 @@ function envelopeMatchesScope(envelope, sessionId, traceId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function unscopedEnvelopeFilter(envelope) {
|
||||
if (!envelope || typeof envelope !== "object" || Array.isArray(envelope) || envelope.schema !== "hwlab.event.v1") return "filteredNonHwlab";
|
||||
if (!textValue(envelope.eventId) && !textValue(envelope.sourceEventId)) return "filteredMissingIdentity";
|
||||
return null;
|
||||
}
|
||||
|
||||
function requireTransportIdentity(value, expectedTopic, phase) {
|
||||
const topic = textValue(value?.topic);
|
||||
const partition = partitionValue(value?.partition);
|
||||
|
||||
Reference in New Issue
Block a user