@openwop/openwop-conformance 1.135.2 → 1.135.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_comment": "Provenance of this vendored schemas/ copy. See conformance/README.md \u00a7\"Resolving the contract\". Compare against the stamp in your installed @openwop/openwop-conformance to detect a stale hand-copied contract.",
|
|
3
|
-
"suiteVersion": "1.135.
|
|
4
|
-
"corpusCommit": "
|
|
3
|
+
"suiteVersion": "1.135.4",
|
|
4
|
+
"corpusCommit": "d8f9be75925e189b56f9f0da7e3352cfee4d8e84"
|
|
5
5
|
}
|
|
@@ -138,11 +138,14 @@ export function signPayload(
|
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
140
|
* Discover a tenant the calling bearer provably OWNS, by creating a probe run
|
|
141
|
-
* and reading `owner.
|
|
141
|
+
* and reading `owner.tenant` off its snapshot (RFC 0048; `run-snapshot.schema.json`
|
|
142
|
+
* §owner — the triple is `{ tenant, workspace, principal }`, and `tenantId` was
|
|
143
|
+
* never the spec name: S29, 2026-08-17, found by the second sibling host, whose
|
|
144
|
+
* schema-correct `owner.tenant` this helper silently ignored). A host that scopes
|
|
142
145
|
* webhook subscriptions by tenant membership (RFC 0093) 403s a `tenantId` the
|
|
143
146
|
* bearer is not a member of — so a hard-coded tenant is wrong; the only portable
|
|
144
147
|
* owned tenant is the one on a run the bearer just created. Returns `undefined`
|
|
145
|
-
* for a single-tenant host (which omits `owner
|
|
148
|
+
* for a single-tenant host (which omits `owner`) or when no probe
|
|
146
149
|
* fixture is available — callers then omit `tenantId`, which single-tenant hosts
|
|
147
150
|
* accept. (RFC 0093 / webhooks.md §Register; suite defect fixed 2026-08-09.)
|
|
148
151
|
*/
|
|
@@ -155,6 +158,8 @@ export async function discoverOwnedTenant(
|
|
|
155
158
|
const runId = (create.json as { runId?: string } | null)?.runId;
|
|
156
159
|
if (typeof runId !== 'string') return undefined;
|
|
157
160
|
const snap = await driver.get(`/v1/runs/${encodeURIComponent(runId)}`);
|
|
158
|
-
const owner = (snap.json as { owner?: { tenantId?: unknown } } | null)?.owner;
|
|
159
|
-
|
|
161
|
+
const owner = (snap.json as { owner?: { tenant?: unknown; tenantId?: unknown } } | null)?.owner;
|
|
162
|
+
if (typeof owner?.tenant === 'string' && owner.tenant.length > 0) return owner.tenant;
|
|
163
|
+
// Pre-S29 hosts that copied the suite's misnamed field: tolerated, never asserted.
|
|
164
|
+
return typeof owner?.tenantId === 'string' && owner.tenantId.length > 0 ? owner.tenantId : undefined;
|
|
160
165
|
}
|
|
@@ -35,6 +35,14 @@ async function disco() {
|
|
|
35
35
|
const REQ = { jsonrpc: '2.0', id: 1, method: 'tools/list', params: { _meta: { [META_V]: '2026-07-28', [META_C]: {} } } };
|
|
36
36
|
const HDR = { 'MCP-Protocol-Version': '2026-07-28', 'Mcp-Method': 'tools/list' };
|
|
37
37
|
|
|
38
|
+
/** Set-Cookie values from a fetch Headers (Node ≥ 19.7 exposes them un-joined via getSetCookie). */
|
|
39
|
+
function setCookies(h: Headers): string[] {
|
|
40
|
+
const g = (h as Headers & { getSetCookie?: () => string[] }).getSetCookie;
|
|
41
|
+
if (typeof g === 'function') return g.call(h);
|
|
42
|
+
const one = h.get('set-cookie');
|
|
43
|
+
return one ? [one] : [];
|
|
44
|
+
}
|
|
45
|
+
|
|
38
46
|
describe.skipIf(!process.env.OPENWOP_BASE_URL)('RFC 0153 §E — mcp-current-auth-boundary (host as server, gated)', () => {
|
|
39
47
|
it('an unauthenticated current-profile request is refused, unless anonymousActor is advertised', async () => {
|
|
40
48
|
const { mcp, anon } = await disco();
|
|
@@ -53,5 +61,23 @@ describe.skipIf(!process.env.OPENWOP_BASE_URL)('RFC 0153 §E — mcp-current-aut
|
|
|
53
61
|
[401, 403],
|
|
54
62
|
driver.describe('mcp-integration.md §E', 'an anonymous MCP principal MUST NOT be the production default for an advertised current profile — refuse (401/403) or advertise anonymousActor'),
|
|
55
63
|
).toContain(anonymous.status);
|
|
64
|
+
|
|
65
|
+
// S30 (2026-08-17, openwop-app H43): a cookie-posture host may MINT an anonymous
|
|
66
|
+
// session for a credential-less caller and then treat "has a principal" as
|
|
67
|
+
// "is authenticated". The bare probe above never carries a cookie, so it can
|
|
68
|
+
// only observe the first request; replay with whatever the host just minted
|
|
69
|
+
// (from this response or from a credential-less discovery GET) and hold the
|
|
70
|
+
// same rule — an anonymous SESSION is still an anonymous principal.
|
|
71
|
+
const minted = [
|
|
72
|
+
...setCookies(anonymous.headers),
|
|
73
|
+
...setCookies((await driver.get('/.well-known/openwop', { authenticated: false })).headers),
|
|
74
|
+
];
|
|
75
|
+
if (minted.length === 0) return; // host mints no anonymous session; the bare probe was the whole observation
|
|
76
|
+
const cookie = minted.map((c) => c.split(';')[0]).join('; ');
|
|
77
|
+
const withSession = await driver.post(await mcpServerMount(), REQ, { headers: { ...HDR, Cookie: cookie }, authenticated: false });
|
|
78
|
+
expect(
|
|
79
|
+
[401, 403],
|
|
80
|
+
driver.describe('mcp-integration.md §E', 'a caller holding only a host-minted anonymous session cookie is still an anonymous principal — refuse (401/403) unless anonymousActor is advertised (S30)'),
|
|
81
|
+
).toContain(withSession.status);
|
|
56
82
|
});
|
|
57
83
|
});
|