a2a-exposed 0.8.23 → 0.8.25
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
package/worker/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Inbox build. Keep this equal to `version` in cli/package.json. */
|
|
2
|
-
export const VERSION = "0.8.
|
|
2
|
+
export const VERSION = "0.8.25";
|
|
@@ -12,6 +12,9 @@ export const WAKE_SECRET_KEYS = [
|
|
|
12
12
|
"WAKE_ACCESS_CLIENT_ID",
|
|
13
13
|
"WAKE_ACCESS_CLIENT_SECRET",
|
|
14
14
|
"EVENT_SECRET",
|
|
15
|
+
"UPSTREAM_TOKEN",
|
|
16
|
+
"UPSTREAM_ACCESS_CLIENT_ID",
|
|
17
|
+
"UPSTREAM_ACCESS_CLIENT_SECRET",
|
|
15
18
|
] as const;
|
|
16
19
|
|
|
17
20
|
export type WakeSecretKey = (typeof WAKE_SECRET_KEYS)[number];
|
|
@@ -929,3 +929,50 @@ test("self-host workerd: human mode owner token approves, the device poll return
|
|
|
929
929
|
const deniedToken = await deniedPoll.json() as { error?: string };
|
|
930
930
|
assert.equal(deniedToken.error, "access_denied");
|
|
931
931
|
});
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
test("sealed upstream and wake Access credentials reach only their tenant context in workerd", async (t) => {
|
|
935
|
+
const received: { origin: string; bearer: string | null; id: string | null; secret: string | null }[] = [];
|
|
936
|
+
const mf = await start({
|
|
937
|
+
bindings: { TENANCY: "host", TENANT_DOMAIN: "example.com", TENANT_SECRETS_KEY: "platform-secret" },
|
|
938
|
+
durableObjects: { TENANT_DO: { className: "TenantStore", useSQLite: true } },
|
|
939
|
+
outboundService: async (request: Request) => {
|
|
940
|
+
received.push({ origin: new URL(request.url).origin, bearer: request.headers.get("authorization"), id: request.headers.get("cf-access-client-id"), secret: request.headers.get("cf-access-client-secret") });
|
|
941
|
+
return Response.json({ protocolVersion: "0.3.0", name: "Example", url: "https://upstream.example.com/a2a", capabilities: {}, skills: [] });
|
|
942
|
+
},
|
|
943
|
+
});
|
|
944
|
+
t.after(() => mf.dispose());
|
|
945
|
+
await mf.ready;
|
|
946
|
+
const ns = await mf.getDurableObjectNamespace("TENANT_DO");
|
|
947
|
+
const stub = ns.get(ns.idFromName("sealed-tenant")) as unknown as {
|
|
948
|
+
pushConfig(body: Record<string, unknown>): Promise<{ applied: boolean }>;
|
|
949
|
+
owner(input: { accountId: string; method: string; path: string }): Promise<{ status: number; body: unknown }>;
|
|
950
|
+
};
|
|
951
|
+
const secrets = { UPSTREAM_TOKEN: "dummy-bearer", UPSTREAM_ACCESS_CLIENT_ID: "dummy-upstream-id", UPSTREAM_ACCESS_CLIENT_SECRET: "dummy-upstream-secret", WAKE_ACCESS_CLIENT_ID: "dummy-wake-id", WAKE_ACCESS_CLIENT_SECRET: "dummy-wake-secret" };
|
|
952
|
+
const sealed = await sealWakeSecrets("platform-secret", "sealed-tenant", secrets);
|
|
953
|
+
assert.ok(sealed);
|
|
954
|
+
const push = async (version: number, secretsEnc: string) => stub.pushConfig({
|
|
955
|
+
version, tenantId: "sealed-tenant", name: "sealed", status: "active", ownerTokenHash: await sha256("dummy-owner-token"), secretsEnc,
|
|
956
|
+
config: { UPSTREAM_URL: "https://upstream.example.com/a2a", UPSTREAM_TOKEN: "plaintext-must-not-win", WAKE_WEBHOOK_URL: "https://hooks.example.com/wake" },
|
|
957
|
+
});
|
|
958
|
+
assert.equal((await push(1, sealed)).applied, true);
|
|
959
|
+
const facade = await stub.owner({ accountId: "dummy-owner", method: "GET", path: "/owner/facade" });
|
|
960
|
+
assert.equal(facade.status, 200);
|
|
961
|
+
assert.equal((facade.body as { hasUpstreamToken: boolean }).hasUpstreamToken, true);
|
|
962
|
+
assert.equal((facade.body as { hasUpstreamAccessServiceToken: boolean }).hasUpstreamAccessServiceToken, true);
|
|
963
|
+
assert.ok(received.length > 0);
|
|
964
|
+
for (const request of received) assert.deepEqual(request, { origin: "https://upstream.example.com", bearer: "Bearer dummy-bearer", id: "dummy-upstream-id", secret: "dummy-upstream-secret" });
|
|
965
|
+
const preview = await stub.owner({ accountId: "dummy-owner", method: "GET", path: "/owner/wake/preview" });
|
|
966
|
+
assert.equal(preview.status, 200);
|
|
967
|
+
assert.equal((preview.body as { hasAccessServiceToken: boolean }).hasAccessServiceToken, true);
|
|
968
|
+
for (const value of Object.values(secrets)) assert.equal(JSON.stringify([facade.body, preview.body]).includes(value), false);
|
|
969
|
+
const otherTenantBlob = await sealWakeSecrets("platform-secret", "another-tenant", secrets);
|
|
970
|
+
assert.ok(otherTenantBlob);
|
|
971
|
+
assert.equal((await push(2, otherTenantBlob)).applied, true);
|
|
972
|
+
const rejected = await stub.owner({ accountId: "dummy-owner", method: "GET", path: "/owner/facade" });
|
|
973
|
+
assert.equal((rejected.body as { hasUpstreamToken: boolean }).hasUpstreamToken, false);
|
|
974
|
+
assert.equal((rejected.body as { hasUpstreamAccessServiceToken: boolean }).hasUpstreamAccessServiceToken, false);
|
|
975
|
+
const emptyPreview = await stub.owner({ accountId: "dummy-owner", method: "GET", path: "/owner/wake/preview" });
|
|
976
|
+
assert.equal((emptyPreview.body as { hasAccessServiceToken: boolean }).hasAccessServiceToken, false);
|
|
977
|
+
assert.equal(received.at(-1)?.bearer, null, "an unreadable blob never falls back to plaintext");
|
|
978
|
+
});
|