|
238 | 238 | "evidence": "the thrown message / startup log" |
239 | 239 | }, |
240 | 240 | { |
241 | | - "clause": "an unknown/revoked/expired key is rejected up front — never a fall-back to an anonymous-but-serving session. A key that resolves to nobody (unknown, owner-less) is refused with 'OS_MCP_STDIO_API_KEY did not resolve to a valid identity (unknown / revoked / expired / owner-less). Refusing to start stdio (ADR-0101).'; a key its own lifecycle refuses (revoked, expired, inactive) is refused naming its code since #23367: '[MCP] OS_MCP_STDIO_API_KEY is refused (API_KEY_REVOKED): This API key (osk_…) was revoked, … Refusing to start stdio (ADR-0101).'", |
| 241 | + "clause": "an unknown/revoked/expired key is rejected up front — never a fall-back to an anonymous-but-serving session. A key that resolves to nobody (unknown, owner-less) is refused with 'OS_MCP_STDIO_API_KEY did not resolve to a valid identity (unknown / revoked / expired / owner-less). Refusing to start stdio (ADR-0101).'; a key its own lifecycle refuses (revoked, expired, inactive) is refused naming its code since #23367: '[MCP] OS_MCP_STDIO_API_KEY is refused (API_KEY_REVOKED): … Refusing to start stdio (ADR-0101).', the elided middle being the key's own lifecycle message, whose wording this item does not pin", |
242 | 242 | "oracle": "log", |
243 | 243 | "verify": "startup with osk_unknown throws /did not resolve to a valid identity/; startup with the key revoked in the revocation step throws /is refused \\(API_KEY_REVOKED\\)/ (packages/mcp/src/plugin.ts, the initial admission's isApiKeyLifecycleRefusalError arm); neither process serves", |
244 | 244 | "evidence": "the two thrown messages" |
|
268 | 268 | "evidence": "the refusal + a control aggregate over a readable field" |
269 | 269 | }, |
270 | 270 | { |
271 | | - "clause": "revocation is honored on the NEXT read (the identity is re-resolved per call) and fails CLOSED with the key's own lifecycle refusal: the post-revocation call returns no row and is a tool ERROR whose envelope carries code API_KEY_REVOKED and status 403, its message naming the key by its display prefix ('This API key (osk_…) was revoked, and a revoked key never works again. …'). Since #23367 resolvePrincipal raises that branded ADR-0112 envelope (ApiKeyLifecycleRefusalError) instead of the generic 'MCP stdio identity is no longer valid (key revoked or expired)' error, which now answers only an identity that resolves to nobody at all", |
| 271 | + "clause": "revocation is honored on the NEXT read (the identity is re-resolved per call) and fails CLOSED with the key's own lifecycle refusal: the post-revocation call returns no row and is a tool ERROR whose envelope carries code API_KEY_REVOKED and status 403. The envelope's message is the key's own lifecycle refusal and its wording is NOT pinned here: the code is what a client branches on, and the lifecycle owner rewords that text (#23944, now that restore_api_key can bring a revoked key back). Since #23367 resolvePrincipal raises that branded ADR-0112 envelope (ApiKeyLifecycleRefusalError) instead of the generic 'MCP stdio identity is no longer valid (key revoked or expired)' error, which now answers only an identity that resolves to nobody at all", |
272 | 272 | "oracle": "api", |
273 | | - "verify": "on the SAME live stdio session: a query_records before the revoke returns rows (the control that the session was serving); after PATCH /api/v1/data/sys_api_key/<key id> {\"revoked\": true} the next tools/call query_records answers result.isError true, and its content text parses to {error: {code: 'API_KEY_REVOKED', status: 403, message}} with no record in it (packages/mcp/src/plugin.ts resolvePrincipal; the coded tool error is errorResultWithCode in packages/mcp/src/mcp-http-tools.ts). Score the code and the absence of rows, never the prose alone", |
| 273 | + "verify": "on the SAME live stdio session: a query_records before the revoke returns rows (the control that the session was serving); after PATCH /api/v1/data/sys_api_key/<key id> {\"revoked\": true} the next tools/call query_records answers result.isError true, and its content text parses to {error: {code: 'API_KEY_REVOKED', status: 403, message}} with no record in it (packages/mcp/src/plugin.ts resolvePrincipal; the coded tool error is errorResultWithCode in packages/mcp/src/mcp-http-tools.ts). Score the code, the status and the absence of rows, never the message's wording", |
274 | 274 | "evidence": "the pre-revocation rows, the revoke write, and the post-revocation tool result (isError, code, status, no rows)" |
275 | 275 | }, |
276 | 276 | { |
|
313 | 313 | { |
314 | 314 | "revision": 5, |
315 | 315 | "date": "2026-10-16", |
316 | | - "change": "stale clause re-pointed (#23950, from QA run #23915): acceptance[6] pinned the generic text 'MCP stdio identity is no longer valid (key revoked or expired)', but since #23367 (API-key lifecycle) resolvePrincipal raises the key's branded ADR-0112 refusal, so a revoked key's next stdio call is an isError tool result carrying code API_KEY_REVOKED, status 403 and the located 'This API key (osk_…) was revoked' message. The clause now scores that code, no row served after the revoke (the fail-closed property it exists for, unchanged) and a pre-revoke control read on the same session; its oracle is the tool result (api), not a log line. Same ruling, same item: acceptance[1] attributed one message to unknown, revoked and expired keys alike, while the up-front admission now refuses a lifecycle-refused key with '[MCP] OS_MCP_STDIO_API_KEY is refused (API_KEY_REVOKED): …', so it names both messages and gains a leg (a new step starts stdio with the just-revoked key). A negative pins both failure directions", |
| 316 | + "change": "stale clause re-pointed (#23950, from QA run #23915): acceptance[6] pinned the generic text 'MCP stdio identity is no longer valid (key revoked or expired)', but since #23367 (API-key lifecycle) resolvePrincipal raises the key's branded ADR-0112 refusal, so a revoked key's next stdio call is an isError tool result carrying code API_KEY_REVOKED, status 403 and the key's own lifecycle message. The clause now scores that code (and pins none of the message's wording, which the lifecycle owner rewords under #23944), no row served after the revoke (the fail-closed property it exists for, unchanged) and a pre-revoke control read on the same session; its oracle is the tool result (api), not a log line. Same ruling, same item: acceptance[1] attributed one message to unknown, revoked and expired keys alike, while the up-front admission now refuses a lifecycle-refused key with '[MCP] OS_MCP_STDIO_API_KEY is refused (API_KEY_REVOKED): …', so it names both messages and gains a leg (a new step starts stdio with the just-revoked key). A negative pins both failure directions", |
317 | 317 | "ref": "#23950" |
318 | 318 | } |
319 | 319 | ] |
|
0 commit comments