fix(mcp): ограничить очередь NetFlow и защитить чтение истории
This commit is contained in:
1 parent
c90a6ca3b8
commit
b4d2d4bc20
6 files changed
+134
-10
No files matched your search
@@ -1,6 +1,9 @@
|
||||
import assert from "node:assert/strict"
|
||||
import { createHash, randomUUID } from "node:crypto"
|
||||
import { createDiagnosticCancellationSourceForTests, createReadServerProbeExecutionSourceForTests } from "./diagnostic-cancellation-source.js"
|
||||
import { mkdtemp, readdir, rm, rmdir } from "node:fs/promises"
|
||||
import { tmpdir } from "node:os"
|
||||
import { join } from "node:path"
|
||||
import { createDiagnosticCancellationSourceForTests, createReadServerProbeExecutionSourceForTests, readServerProbeExecutionSource } from "./diagnostic-cancellation-source.js"
|
||||
import { fingerprint, redact } from "./security.js"
|
||||
|
||||
const proof = async (value: unknown) => createHash("sha256").update(fingerprint(value)).digest("hex")
|
||||
@@ -25,6 +28,7 @@ function fixture() {
|
||||
return { rows }
|
||||
} }
|
||||
return { load: () => load(client, operationId, owner), read: () => read(snapshot, operationId, owner), readSql,
|
||||
readWithExistingKey: () => readServerProbeExecutionSource(snapshot, operationId, owner),
|
||||
refresh, binding, input, evidence, row, sealed, setRows: (value: typeof rows) => { rows=value }, calls: () => calls, operationId, credentialId }
|
||||
}
|
||||
{
|
||||
@@ -100,4 +104,22 @@ for (const mutate of mutations) {
|
||||
assert.equal(source.originalContext.tool, "bandwidth"); assert.equal(source.stageBudget, 1)
|
||||
assert.equal(source.originalContext.identity.credentialId, f.credentialId)
|
||||
}
|
||||
console.log(`diagnostic-cancellation-source: locked/read-only source, expired original contexts and ${mutations.length} shared tamper checks passed`)
|
||||
{
|
||||
const state = await mkdtemp(join(tmpdir(), "mm-legacy-source-test-"))
|
||||
const previousState = process.env.MCP_STATE_DIR
|
||||
process.env.MCP_STATE_DIR = state
|
||||
try {
|
||||
const f = fixture()
|
||||
await f.refresh()
|
||||
f.row.evidence = { sealed: Buffer.alloc(32).toString("base64") }
|
||||
await assert.rejects(f.readWithExistingKey, { code: "STATE_CONFLICT" })
|
||||
assert.equal(f.readSql.length, 1)
|
||||
assert.deepEqual(await readdir(state), [], "Historical source reads must leave missing encryption state untouched")
|
||||
} finally {
|
||||
if (previousState === undefined) delete process.env.MCP_STATE_DIR
|
||||
else process.env.MCP_STATE_DIR = previousState
|
||||
await rm(join(state, "encryption-key"), { force: true })
|
||||
await rmdir(state)
|
||||
}
|
||||
}
|
||||
console.log(`diagnostic-cancellation-source: locked/read-only source, missing key, expired original contexts and ${mutations.length} shared tamper checks passed`)
|
||||
@@ -3,7 +3,7 @@ import type { ProbeStorageScope, ProbeStorageSql } from "../../services/server-p
|
||||
import type { ServerProbeJournalContext } from "../../services/server-probe-journal.js"
|
||||
import { SERVER_PROBE_OPERATION } from "../../services/server-probe-authority.js"
|
||||
import { openServerProbeMcpBinding } from "./server-probe-actions.js"
|
||||
import { decryptSecret, fingerprint, privateSecretFingerprint, redact, McpError } from "./security.js"
|
||||
import { decryptSecret, decryptSecretExisting, fingerprint, privateFingerprinterExisting, privateSecretFingerprint, redact, McpError } from "./security.js"
|
||||
|
||||
const MAX_BYTES = 2097152
|
||||
const uuid = z.string().uuid()
|
||||
@@ -113,7 +113,10 @@ export const loadDiagnosticCancellationSource = sourceLoader(productionCrypto)
|
||||
/** Test-only crypto seam. Never accept these dependencies from tool JSON. */
|
||||
export const createDiagnosticCancellationSourceForTests = sourceLoader
|
||||
/** Historical authentication only; confers no execution/cancellation grant. */
|
||||
export const readServerProbeExecutionSource = readSourceLoader(productionCrypto)
|
||||
export const readServerProbeExecutionSource = readSourceLoader({
|
||||
open: decryptSecretExisting,
|
||||
proof: async value => (await privateFingerprinterExisting("server-probe-mcp-binding-v1"))(fingerprint(value)),
|
||||
})
|
||||
export const createReadServerProbeExecutionSourceForTests = readSourceLoader
|
||||
/** Exact previously locked source projection for private history conversion. */
|
||||
export function authenticateServerProbeExecutionSourceRow(row: Record<string, unknown>, operationId: string,
|
||||
|
||||
Reference in new issue
Block a user