@mycadet/gateway 0.12.7 → 0.12.9
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/README.md +3 -3
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/package.json +2 -2
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/{platform-credential.ts → cloud-credential.ts} +9 -9
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
- package/node_modules/@mycadet/ces-client/package.json +1 -1
- package/node_modules/@mycadet/ces-client/src/__tests__/ces-client.test.ts +14 -14
- package/node_modules/@mycadet/ces-client/src/rpc-client.ts +1 -1
- package/node_modules/@mycadet/environments/src/seeds.ts +6 -6
- package/node_modules/@mycadet/environments/src/shell.test.ts +1 -1
- package/node_modules/@mycadet/environments/src/types.ts +6 -6
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/package.json +2 -2
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/{platform-credential.ts → cloud-credential.ts} +9 -9
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
- package/node_modules/@mycadet/gateway-client/src/binding-strength-contract.ts +5 -5
- package/node_modules/@mycadet/gateway-client/src/gateway-ipc-contracts.ts +1 -1
- package/node_modules/@mycadet/gateway-client/src/inbound-contract.ts +2 -2
- package/node_modules/@mycadet/gateway-client/src/outbound-contract.ts +1 -1
- package/node_modules/@mycadet/service-contracts/package.json +2 -2
- package/node_modules/@mycadet/service-contracts/src/{platform-credential.ts → cloud-credential.ts} +9 -9
- package/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
- package/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
- package/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
- package/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
- package/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
- package/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
- package/openapi.json +17 -17
- package/package.json +1 -1
- package/scripts/generate-openapi.ts +1 -1
- package/src/__tests__/actor-token-revocation.test.ts +0 -1
- package/src/__tests__/{backup-worker-platform-mode.test.ts → backup-worker-cloud-mode.test.ts} +4 -4
- package/src/__tests__/channel-verification-session-proxy.test.ts +0 -1
- package/src/__tests__/{platform-identity.test.ts → cloud-identity.test.ts} +72 -86
- package/src/__tests__/config.test.ts +0 -24
- package/src/__tests__/contacts-control-plane-proxy.test.ts +0 -1
- package/src/__tests__/credential-requests.test.ts +6 -6
- package/src/__tests__/{credential-watcher-managed-bootstrap.test.ts → credential-watcher-cloud-bootstrap.test.ts} +1 -1
- package/src/__tests__/edge-auth.test.ts +18 -18
- package/src/__tests__/edge-guardian-auth.test.ts +10 -10
- package/src/__tests__/guardian-init-lockfile.test.ts +6 -8
- package/src/__tests__/guardian-pin.test.ts +8 -8
- package/src/__tests__/handle-inbound-admission.test.ts +0 -1
- package/src/__tests__/handle-inbound-app-context.test.ts +0 -1
- package/src/__tests__/handle-inbound-invite-intercept.test.ts +0 -1
- package/src/__tests__/handle-inbound-trust-verdict.test.ts +0 -1
- package/src/__tests__/inbound-contact-seed.test.ts +1 -1
- package/src/__tests__/live-voice-websocket.test.ts +12 -12
- package/src/__tests__/load-guards.test.ts +0 -1
- package/src/__tests__/migration-teleport-gcs-proxy.test.ts +0 -1
- package/src/__tests__/oauth-callback.test.ts +0 -1
- package/src/__tests__/remote-feature-flag-sync.test.ts +35 -45
- package/src/__tests__/resolve-assistant.test.ts +0 -1
- package/src/__tests__/route-schema-guard.test.ts +4 -1
- package/src/__tests__/runtime-client.test.ts +1 -2
- package/src/__tests__/runtime-health-proxy.test.ts +0 -1
- package/src/__tests__/runtime-proxy-auth.test.ts +3 -2
- package/src/__tests__/runtime-proxy-device-stamp.test.ts +0 -1
- package/src/__tests__/runtime-proxy-error-body.test.ts +0 -1
- package/src/__tests__/runtime-proxy.test.ts +0 -1
- package/src/__tests__/runtime-stream-test-utils.ts +0 -1
- package/src/__tests__/shared-invite-registration.test.ts +15 -32
- package/src/__tests__/slack-control-plane-proxy.test.ts +0 -1
- package/src/__tests__/slack-display-name.test.ts +0 -1
- package/src/__tests__/slack-normalize.test.ts +0 -1
- package/src/__tests__/slack-reaction-normalize.test.ts +0 -1
- package/src/__tests__/slack-socket-mode-catchup.test.ts +0 -1
- package/src/__tests__/slack-socket-mode-group-dm.test.ts +0 -1
- package/src/__tests__/slack-socket-mode-liveness.test.ts +0 -1
- package/src/__tests__/slack-socket-mode-outbound-root.test.ts +0 -1
- package/src/__tests__/slack-socket-mode-thread-tracking.test.ts +0 -1
- package/src/__tests__/speech-relay-websocket.test.ts +16 -14
- package/src/__tests__/stt-stream-websocket.test.ts +5 -5
- package/src/__tests__/telegram-control-plane-proxy.test.ts +0 -1
- package/src/__tests__/telegram-webhook-drop-visibility.test.ts +0 -1
- package/src/__tests__/telegram-webhook-handler.test.ts +0 -1
- package/src/__tests__/telegram-webhook-manager.test.ts +79 -80
- package/src/__tests__/twilio-media-websocket.test.ts +0 -1
- package/src/__tests__/twilio-webhooks.test.ts +6 -7
- package/src/__tests__/whatsapp-download.test.ts +0 -1
- package/src/__tests__/whatsapp-webhook.test.ts +0 -1
- package/src/attachments/ingest.test.ts +0 -1
- package/src/auth/guardian-bootstrap.ts +16 -15
- package/src/auth/scopes.ts +1 -1
- package/src/auth-fallback-reporter.ts +1 -1
- package/src/backup/backup-worker.ts +2 -2
- package/src/channels/inbound-event.ts +3 -3
- package/src/channels/ingress-inbound-vendors.test.ts +2 -2
- package/src/channels/ingress-inbound.ts +1 -1
- package/src/channels/ingress-verification.test.ts +2 -2
- package/src/channels/ingress-verification.ts +4 -4
- package/src/channels/plugin-ingress-approvals.test.ts +1 -1
- package/src/channels/plugin-ingress-approvals.ts +1 -1
- package/src/channels/plugin-ingress.test.ts +3 -3
- package/src/channels/plugin-ingress.ts +3 -3
- package/src/channels/room-admission.ts +2 -2
- package/src/cli/contacts.ts +3 -1
- package/src/cli/index.ts +1 -1
- package/src/{platform-identity.ts → cloud-identity.ts} +60 -68
- package/src/cloud-url.ts +25 -0
- package/src/{platform-user-id.ts → cloud-user-id.ts} +4 -4
- package/src/config.ts +2 -4
- package/src/credential-reader.ts +2 -2
- package/src/db/assistant-db-proxy.ts +1 -1
- package/src/discord/forward.ts +1 -1
- package/src/email/normalize.ts +4 -4
- package/src/email/register-callback.test.ts +27 -34
- package/src/email/register-callback.ts +21 -26
- package/src/feature-flag-registry.json +5 -5
- package/src/feature-flag-remote-store.ts +2 -2
- package/src/feature-flag-resolver.ts +5 -5
- package/src/http/cadet-signature.ts +1 -1
- package/src/http/edge-forwarded-header.ts +1 -1
- package/src/http/loopback-guard.ts +1 -1
- package/src/http/middleware/auth.ts +22 -22
- package/src/http/router.ts +1 -1
- package/src/http/routes/auto-approve-thresholds-routes.ts +1 -1
- package/src/http/routes/cadet-identity.ts +2 -2
- package/src/http/routes/channel-admission-policy-routes.ts +2 -2
- package/src/http/routes/channel-ingress-routes.ts +3 -3
- package/src/http/routes/channel-ingress.test.ts +13 -2
- package/src/http/routes/channel-permission-overrides-routes.ts +3 -3
- package/src/http/routes/channel-verification-session-proxy.ts +8 -22
- package/src/http/routes/{platform-push-proxy.test.ts → cloud-push-proxy.test.ts} +21 -22
- package/src/http/routes/{platform-push-proxy.ts → cloud-push-proxy.ts} +13 -14
- package/src/http/routes/contacts-control-plane-proxy.ts +3 -3
- package/src/http/routes/contacts-control-plane-routes.ts +5 -5
- package/src/http/routes/email-webhook.test.ts +2 -3
- package/src/http/routes/email-webhook.ts +4 -4
- package/src/http/routes/feature-flags.ts +1 -1
- package/src/http/routes/guardian-channel-create.ts +3 -3
- package/src/http/routes/guardian-pin.ts +9 -9
- package/src/http/routes/inbound-register.ts +2 -2
- package/src/http/routes/ingress-domains.test.ts +129 -0
- package/src/http/routes/ingress-domains.ts +73 -0
- package/src/http/routes/live-voice-websocket.ts +2 -2
- package/src/http/routes/log-export.test.ts +0 -1
- package/src/http/routes/log-tail.test.ts +0 -1
- package/src/http/routes/migration-proxy.ts +1 -1
- package/src/http/routes/plugin-webhook-websocket.test.ts +3 -3
- package/src/http/routes/plugin-webhook.test.ts +9 -8
- package/src/http/routes/plugin-webhook.ts +1 -1
- package/src/http/routes/speech-relay-websocket.ts +8 -11
- package/src/http/routes/stt-stream-websocket.ts +1 -1
- package/src/http/routes/telegram-webhook.test.ts +0 -1
- package/src/http/routes/trust-rules-routes.ts +2 -2
- package/src/http/routes/twilio-voice-verify-callback.ts +3 -3
- package/src/http/routes/twilio-voice-webhook.test.ts +3 -4
- package/src/http/routes/twilio-voice-webhook.ts +3 -3
- package/src/http/routes/whatsapp-webhook.test.ts +0 -1
- package/src/index.ts +57 -56
- package/src/ipc/credential-request-handlers.ts +4 -4
- package/src/ipc/debug-export-handlers.test.ts +0 -1
- package/src/ipc/log-tail-handlers.test.ts +0 -1
- package/src/ipc/risk-classification-handlers.test.ts +4 -4
- package/src/ipc/risk-classification-handlers.ts +2 -2
- package/src/remote-feature-flag-sync.ts +17 -19
- package/src/risk/command-registry/commands/assistant.ts +2 -2
- package/src/risk/skill-risk-classifier.test.ts +24 -24
- package/src/risk/skill-risk-classifier.ts +10 -10
- package/src/runtime/client.ts +17 -17
- package/src/schema.ts +29 -29
- package/src/telegram/send.test.ts +0 -1
- package/src/telegram/webhook-manager.ts +33 -38
- package/src/tunnel/allowed-paths.test.ts +3 -3
- package/src/tunnel/allowed-paths.ts +1 -1
- package/src/tunnel/client.test.ts +20 -21
- package/src/tunnel/client.ts +16 -17
- package/src/verification/shared-invite-registration.ts +22 -17
- package/src/version.ts +1 -1
- package/src/platform-url.ts +0 -24
|
@@ -37,30 +37,23 @@ mock.module("../fetch.js", () => ({
|
|
|
37
37
|
}));
|
|
38
38
|
|
|
39
39
|
const {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
} = await import("../
|
|
40
|
+
_resetCloudIdentityForTests,
|
|
41
|
+
applyCloudIdentityIds,
|
|
42
|
+
fetchCloudIdentityIds,
|
|
43
|
+
CLOUD_IDENTITY_VALIDATE_PATH,
|
|
44
|
+
readStoredCloudUserId,
|
|
45
|
+
resolveCloudAssistantId,
|
|
46
|
+
} = await import("../cloud-identity.js");
|
|
47
47
|
const { credentialKey } = await import("../credential-key.js");
|
|
48
48
|
|
|
49
|
-
const BASE_URL = "https://
|
|
49
|
+
const BASE_URL = "https://test-cloud.mycadet.ai";
|
|
50
50
|
const ASSISTANT_ID = "11111111-2222-4333-8444-555555555555";
|
|
51
51
|
const ORG_ID = "22222222-3333-4444-8555-666666666666";
|
|
52
52
|
const USER_ID = "33333333-4444-4555-8666-777777777777";
|
|
53
53
|
const API_KEY_ACCOUNT = credentialKey("cadet", "assistant_api_key");
|
|
54
|
-
const BASE_URL_ACCOUNT = credentialKey("cadet", "platform_base_url");
|
|
55
|
-
const USER_ID_ACCOUNT = credentialKey("cadet", "platform_user_id");
|
|
56
|
-
const ASSISTANT_ID_ACCOUNT = credentialKey("cadet", "platform_assistant_id");
|
|
57
|
-
const ORG_ID_ACCOUNT = credentialKey("cadet", "platform_organization_id");
|
|
58
54
|
|
|
59
55
|
const originalAssistantApiKey = process.env.ASSISTANT_API_KEY;
|
|
60
|
-
const
|
|
61
|
-
const originalPlatformAssistantId = process.env.PLATFORM_ASSISTANT_ID;
|
|
62
|
-
const originalPlatformOrgId = process.env.PLATFORM_ORGANIZATION_ID;
|
|
63
|
-
const originalPlatformUserId = process.env.PLATFORM_USER_ID;
|
|
56
|
+
const originalCloudUrl = process.env.CADET_CLOUD_URL;
|
|
64
57
|
|
|
65
58
|
function restoreEnv(name: string, value: string | undefined): void {
|
|
66
59
|
if (value === undefined) {
|
|
@@ -91,35 +84,29 @@ beforeEach(() => {
|
|
|
91
84
|
fetchCalls.length = 0;
|
|
92
85
|
fetchImplFn = async () => new Response("not found", { status: 404 });
|
|
93
86
|
delete process.env.ASSISTANT_API_KEY;
|
|
94
|
-
delete process.env.
|
|
95
|
-
|
|
96
|
-
delete process.env.PLATFORM_ORGANIZATION_ID;
|
|
97
|
-
delete process.env.PLATFORM_USER_ID;
|
|
98
|
-
_resetPlatformIdentityForTests();
|
|
87
|
+
delete process.env.CADET_CLOUD_URL;
|
|
88
|
+
_resetCloudIdentityForTests();
|
|
99
89
|
});
|
|
100
90
|
|
|
101
91
|
afterEach(() => {
|
|
102
92
|
restoreEnv("ASSISTANT_API_KEY", originalAssistantApiKey);
|
|
103
|
-
restoreEnv("
|
|
104
|
-
|
|
105
|
-
restoreEnv("PLATFORM_ORGANIZATION_ID", originalPlatformOrgId);
|
|
106
|
-
restoreEnv("PLATFORM_USER_ID", originalPlatformUserId);
|
|
107
|
-
_resetPlatformIdentityForTests();
|
|
93
|
+
restoreEnv("CADET_CLOUD_URL", originalCloudUrl);
|
|
94
|
+
_resetCloudIdentityForTests();
|
|
108
95
|
});
|
|
109
96
|
|
|
110
|
-
describe("
|
|
97
|
+
describe("fetchCloudIdentityIds", () => {
|
|
111
98
|
test("returns the three ids from a successful validate response", async () => {
|
|
112
99
|
fetchImplFn = async () => validateResponse();
|
|
113
100
|
|
|
114
101
|
await expect(
|
|
115
|
-
|
|
102
|
+
fetchCloudIdentityIds(BASE_URL, "assistant-key"),
|
|
116
103
|
).resolves.toEqual({
|
|
117
104
|
assistantId: ASSISTANT_ID,
|
|
118
105
|
organizationId: ORG_ID,
|
|
119
106
|
userId: USER_ID,
|
|
120
107
|
});
|
|
121
108
|
expect(fetchCalls[0]?.url).toBe(
|
|
122
|
-
`${BASE_URL}${
|
|
109
|
+
`${BASE_URL}${CLOUD_IDENTITY_VALIDATE_PATH}`,
|
|
123
110
|
);
|
|
124
111
|
expect(fetchCalls[0]?.init?.method).toBe("POST");
|
|
125
112
|
const headers = new Headers(fetchCalls[0]?.init?.headers);
|
|
@@ -128,16 +115,16 @@ describe("fetchPlatformIdentityIds", () => {
|
|
|
128
115
|
|
|
129
116
|
test("strips a trailing slash from the base URL", async () => {
|
|
130
117
|
fetchImplFn = async () => validateResponse();
|
|
131
|
-
await
|
|
118
|
+
await fetchCloudIdentityIds(`${BASE_URL}/`, "assistant-key");
|
|
132
119
|
expect(fetchCalls[0]?.url).toBe(
|
|
133
|
-
`${BASE_URL}${
|
|
120
|
+
`${BASE_URL}${CLOUD_IDENTITY_VALIDATE_PATH}`,
|
|
134
121
|
);
|
|
135
122
|
});
|
|
136
123
|
|
|
137
124
|
test("returns null on 401 without throwing", async () => {
|
|
138
125
|
fetchImplFn = async () => new Response("no", { status: 401 });
|
|
139
126
|
await expect(
|
|
140
|
-
|
|
127
|
+
fetchCloudIdentityIds(BASE_URL, "assistant-key"),
|
|
141
128
|
).resolves.toBeNull();
|
|
142
129
|
});
|
|
143
130
|
|
|
@@ -146,66 +133,66 @@ describe("fetchPlatformIdentityIds", () => {
|
|
|
146
133
|
throw new Error("network down");
|
|
147
134
|
};
|
|
148
135
|
await expect(
|
|
149
|
-
|
|
136
|
+
fetchCloudIdentityIds(BASE_URL, "assistant-key"),
|
|
150
137
|
).resolves.toBeNull();
|
|
151
138
|
});
|
|
152
139
|
});
|
|
153
140
|
|
|
154
|
-
describe("
|
|
141
|
+
describe("resolveCloudAssistantId", () => {
|
|
155
142
|
test("returns the in-memory override without calling validate", async () => {
|
|
156
|
-
|
|
143
|
+
applyCloudIdentityIds({
|
|
157
144
|
assistantId: ASSISTANT_ID,
|
|
158
145
|
organizationId: ORG_ID,
|
|
159
146
|
userId: USER_ID,
|
|
160
147
|
});
|
|
161
148
|
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
162
|
-
await expect(
|
|
149
|
+
await expect(resolveCloudAssistantId()).resolves.toBe(ASSISTANT_ID);
|
|
163
150
|
expect(fetchCalls).toHaveLength(0);
|
|
164
151
|
});
|
|
165
152
|
|
|
166
153
|
test("returns empty when the in-memory override is unset and there is no API key", async () => {
|
|
167
|
-
await expect(
|
|
154
|
+
await expect(resolveCloudAssistantId()).resolves.toBe("");
|
|
168
155
|
expect(fetchCalls).toHaveLength(0);
|
|
169
156
|
});
|
|
170
157
|
|
|
171
158
|
test("loads ids from validate when the in-memory override is empty", async () => {
|
|
172
159
|
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
173
|
-
process.env.
|
|
160
|
+
process.env.CADET_CLOUD_URL = BASE_URL;
|
|
174
161
|
fetchImplFn = async () => validateResponse();
|
|
175
162
|
|
|
176
|
-
await expect(
|
|
163
|
+
await expect(resolveCloudAssistantId()).resolves.toBe(ASSISTANT_ID);
|
|
177
164
|
expect(fetchCalls).toHaveLength(1);
|
|
178
165
|
expect(fetchCalls[0]?.url).toBe(
|
|
179
|
-
`${BASE_URL}${
|
|
166
|
+
`${BASE_URL}${CLOUD_IDENTITY_VALIDATE_PATH}`,
|
|
180
167
|
);
|
|
181
168
|
});
|
|
182
169
|
|
|
183
170
|
test("does not retry validate during the cooldown after a failure", async () => {
|
|
184
171
|
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
185
|
-
process.env.
|
|
172
|
+
process.env.CADET_CLOUD_URL = BASE_URL;
|
|
186
173
|
fetchImplFn = async () => new Response("down", { status: 503 });
|
|
187
174
|
|
|
188
|
-
await expect(
|
|
189
|
-
await expect(
|
|
175
|
+
await expect(resolveCloudAssistantId()).resolves.toBe("");
|
|
176
|
+
await expect(resolveCloudAssistantId()).resolves.toBe("");
|
|
190
177
|
expect(fetchCalls).toHaveLength(1);
|
|
191
178
|
});
|
|
192
179
|
|
|
193
180
|
test("retries validate after a failed attempt once the cooldown is cleared", async () => {
|
|
194
181
|
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
195
|
-
process.env.
|
|
182
|
+
process.env.CADET_CLOUD_URL = BASE_URL;
|
|
196
183
|
fetchImplFn = async () => new Response("down", { status: 503 });
|
|
197
184
|
|
|
198
|
-
await expect(
|
|
199
|
-
|
|
185
|
+
await expect(resolveCloudAssistantId()).resolves.toBe("");
|
|
186
|
+
_resetCloudIdentityForTests();
|
|
200
187
|
fetchImplFn = async () => validateResponse();
|
|
201
188
|
|
|
202
|
-
await expect(
|
|
189
|
+
await expect(resolveCloudAssistantId()).resolves.toBe(ASSISTANT_ID);
|
|
203
190
|
expect(fetchCalls).toHaveLength(2);
|
|
204
191
|
});
|
|
205
192
|
|
|
206
193
|
test("concurrent resolves share one in-flight validate", async () => {
|
|
207
194
|
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
208
|
-
process.env.
|
|
195
|
+
process.env.CADET_CLOUD_URL = BASE_URL;
|
|
209
196
|
let release!: (value: Response) => void;
|
|
210
197
|
let notifyFetchStarted!: () => void;
|
|
211
198
|
const fetchStarted = new Promise<void>((resolve) => {
|
|
@@ -218,8 +205,8 @@ describe("resolvePlatformAssistantId", () => {
|
|
|
218
205
|
});
|
|
219
206
|
};
|
|
220
207
|
|
|
221
|
-
const first =
|
|
222
|
-
const second =
|
|
208
|
+
const first = resolveCloudAssistantId();
|
|
209
|
+
const second = resolveCloudAssistantId();
|
|
223
210
|
await fetchStarted;
|
|
224
211
|
expect(fetchCalls).toHaveLength(1);
|
|
225
212
|
release(validateResponse());
|
|
@@ -229,14 +216,14 @@ describe("resolvePlatformAssistantId", () => {
|
|
|
229
216
|
});
|
|
230
217
|
});
|
|
231
218
|
|
|
232
|
-
describe("
|
|
219
|
+
describe("readStoredCloudUserId", () => {
|
|
233
220
|
test("returns a live owner id from in-memory identity", async () => {
|
|
234
|
-
|
|
221
|
+
applyCloudIdentityIds({
|
|
235
222
|
assistantId: ASSISTANT_ID,
|
|
236
223
|
organizationId: ORG_ID,
|
|
237
224
|
userId: USER_ID,
|
|
238
225
|
});
|
|
239
|
-
await expect(
|
|
226
|
+
await expect(readStoredCloudUserId()).resolves.toEqual({
|
|
240
227
|
userId: USER_ID,
|
|
241
228
|
unreachable: false,
|
|
242
229
|
});
|
|
@@ -245,16 +232,16 @@ describe("readStoredPlatformUserId", () => {
|
|
|
245
232
|
|
|
246
233
|
test("loads the owner id from validate and keeps it when validate later fails", async () => {
|
|
247
234
|
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
248
|
-
process.env.
|
|
235
|
+
process.env.CADET_CLOUD_URL = BASE_URL;
|
|
249
236
|
fetchImplFn = async () => validateResponse();
|
|
250
237
|
|
|
251
|
-
await expect(
|
|
238
|
+
await expect(readStoredCloudUserId()).resolves.toEqual({
|
|
252
239
|
userId: USER_ID,
|
|
253
240
|
unreachable: false,
|
|
254
241
|
});
|
|
255
242
|
|
|
256
243
|
fetchImplFn = async () => new Response("down", { status: 503 });
|
|
257
|
-
await expect(
|
|
244
|
+
await expect(readStoredCloudUserId()).resolves.toEqual({
|
|
258
245
|
userId: USER_ID,
|
|
259
246
|
unreachable: false,
|
|
260
247
|
});
|
|
@@ -266,7 +253,7 @@ describe("readStoredPlatformUserId", () => {
|
|
|
266
253
|
value: undefined,
|
|
267
254
|
unreachable: true,
|
|
268
255
|
});
|
|
269
|
-
await expect(
|
|
256
|
+
await expect(readStoredCloudUserId()).resolves.toEqual({
|
|
270
257
|
userId: undefined,
|
|
271
258
|
unreachable: true,
|
|
272
259
|
});
|
|
@@ -278,25 +265,21 @@ describe("readStoredPlatformUserId", () => {
|
|
|
278
265
|
value: "assistant-key",
|
|
279
266
|
unreachable: false,
|
|
280
267
|
});
|
|
281
|
-
credentialResults.set(BASE_URL_ACCOUNT, {
|
|
282
|
-
value: BASE_URL,
|
|
283
|
-
unreachable: false,
|
|
284
|
-
});
|
|
285
268
|
fetchImplFn = async () => new Response("no", { status: 401 });
|
|
286
269
|
|
|
287
|
-
await expect(
|
|
270
|
+
await expect(readStoredCloudUserId()).resolves.toEqual({
|
|
288
271
|
userId: undefined,
|
|
289
272
|
unreachable: false,
|
|
290
273
|
});
|
|
291
274
|
});
|
|
292
275
|
|
|
293
|
-
test("reports unreachable when the API key
|
|
294
|
-
process.env.ASSISTANT_API_KEY
|
|
295
|
-
credentialResults.set(
|
|
276
|
+
test("reports unreachable when the API key vault is down", async () => {
|
|
277
|
+
delete process.env.ASSISTANT_API_KEY;
|
|
278
|
+
credentialResults.set(API_KEY_ACCOUNT, {
|
|
296
279
|
value: undefined,
|
|
297
280
|
unreachable: true,
|
|
298
281
|
});
|
|
299
|
-
await expect(
|
|
282
|
+
await expect(readStoredCloudUserId()).resolves.toEqual({
|
|
300
283
|
userId: undefined,
|
|
301
284
|
unreachable: true,
|
|
302
285
|
});
|
|
@@ -305,11 +288,8 @@ describe("readStoredPlatformUserId", () => {
|
|
|
305
288
|
|
|
306
289
|
test("reports a miss when the API key is present and the base URL is unset", async () => {
|
|
307
290
|
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
unreachable: false,
|
|
311
|
-
});
|
|
312
|
-
await expect(readStoredPlatformUserId()).resolves.toEqual({
|
|
291
|
+
delete process.env.CADET_CLOUD_URL;
|
|
292
|
+
await expect(readStoredCloudUserId()).resolves.toEqual({
|
|
313
293
|
userId: undefined,
|
|
314
294
|
unreachable: false,
|
|
315
295
|
});
|
|
@@ -320,10 +300,10 @@ describe("readStoredPlatformUserId", () => {
|
|
|
320
300
|
const nextAssistantId = "44444444-5555-4666-8777-888888888888";
|
|
321
301
|
const nextUserId = "55555555-6666-4777-8888-999999999999";
|
|
322
302
|
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
323
|
-
process.env.
|
|
303
|
+
process.env.CADET_CLOUD_URL = BASE_URL;
|
|
324
304
|
fetchImplFn = async () => validateResponse();
|
|
325
305
|
|
|
326
|
-
await expect(
|
|
306
|
+
await expect(readStoredCloudUserId()).resolves.toEqual({
|
|
327
307
|
userId: USER_ID,
|
|
328
308
|
unreachable: false,
|
|
329
309
|
});
|
|
@@ -336,11 +316,11 @@ describe("readStoredPlatformUserId", () => {
|
|
|
336
316
|
userId: nextUserId,
|
|
337
317
|
});
|
|
338
318
|
|
|
339
|
-
await expect(
|
|
319
|
+
await expect(readStoredCloudUserId()).resolves.toEqual({
|
|
340
320
|
userId: nextUserId,
|
|
341
321
|
unreachable: false,
|
|
342
322
|
});
|
|
343
|
-
await expect(
|
|
323
|
+
await expect(resolveCloudAssistantId()).resolves.toBe(nextAssistantId);
|
|
344
324
|
expect(fetchCalls).toHaveLength(2);
|
|
345
325
|
const headers = new Headers(fetchCalls[1]?.init?.headers);
|
|
346
326
|
expect(headers.get("Authorization")).toBe("Api-Key next-assistant-key");
|
|
@@ -348,10 +328,10 @@ describe("readStoredPlatformUserId", () => {
|
|
|
348
328
|
|
|
349
329
|
test("drops bound identity when credentials change and validate fails", async () => {
|
|
350
330
|
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
351
|
-
process.env.
|
|
331
|
+
process.env.CADET_CLOUD_URL = BASE_URL;
|
|
352
332
|
fetchImplFn = async () => validateResponse();
|
|
353
333
|
|
|
354
|
-
await expect(
|
|
334
|
+
await expect(readStoredCloudUserId()).resolves.toEqual({
|
|
355
335
|
userId: USER_ID,
|
|
356
336
|
unreachable: false,
|
|
357
337
|
});
|
|
@@ -359,7 +339,7 @@ describe("readStoredPlatformUserId", () => {
|
|
|
359
339
|
process.env.ASSISTANT_API_KEY = "next-assistant-key";
|
|
360
340
|
fetchImplFn = async () => new Response("no", { status: 401 });
|
|
361
341
|
|
|
362
|
-
await expect(
|
|
342
|
+
await expect(readStoredCloudUserId()).resolves.toEqual({
|
|
363
343
|
userId: undefined,
|
|
364
344
|
unreachable: false,
|
|
365
345
|
});
|
|
@@ -368,10 +348,10 @@ describe("readStoredPlatformUserId", () => {
|
|
|
368
348
|
|
|
369
349
|
test("keeps bound identity when the vault is down and the new API key cannot be read", async () => {
|
|
370
350
|
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
371
|
-
process.env.
|
|
351
|
+
process.env.CADET_CLOUD_URL = BASE_URL;
|
|
372
352
|
fetchImplFn = async () => validateResponse();
|
|
373
353
|
|
|
374
|
-
await expect(
|
|
354
|
+
await expect(readStoredCloudUserId()).resolves.toEqual({
|
|
375
355
|
userId: USER_ID,
|
|
376
356
|
unreachable: false,
|
|
377
357
|
});
|
|
@@ -383,7 +363,7 @@ describe("readStoredPlatformUserId", () => {
|
|
|
383
363
|
});
|
|
384
364
|
fetchImplFn = async () => new Response("down", { status: 503 });
|
|
385
365
|
|
|
386
|
-
await expect(
|
|
366
|
+
await expect(readStoredCloudUserId()).resolves.toEqual({
|
|
387
367
|
userId: USER_ID,
|
|
388
368
|
unreachable: false,
|
|
389
369
|
});
|
|
@@ -392,13 +372,19 @@ describe("readStoredPlatformUserId", () => {
|
|
|
392
372
|
|
|
393
373
|
test("does not read platform identity ids from the credential store", async () => {
|
|
394
374
|
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
395
|
-
process.env.
|
|
375
|
+
process.env.CADET_CLOUD_URL = BASE_URL;
|
|
396
376
|
fetchImplFn = async () => validateResponse();
|
|
397
377
|
|
|
398
|
-
await
|
|
378
|
+
await readStoredCloudUserId();
|
|
399
379
|
|
|
400
|
-
expect(credentialReads).not.toContain(
|
|
401
|
-
|
|
402
|
-
|
|
380
|
+
expect(credentialReads).not.toContain(
|
|
381
|
+
credentialKey("cadet", "platform_user_id"),
|
|
382
|
+
);
|
|
383
|
+
expect(credentialReads).not.toContain(
|
|
384
|
+
credentialKey("cadet", "platform_assistant_id"),
|
|
385
|
+
);
|
|
386
|
+
expect(credentialReads).not.toContain(
|
|
387
|
+
credentialKey("cadet", "platform_organization_id"),
|
|
388
|
+
);
|
|
403
389
|
});
|
|
404
390
|
});
|
|
@@ -7,30 +7,6 @@ import { testWorkspaceDir } from "./test-preload.js";
|
|
|
7
7
|
import { loadConfig } from "../config.js";
|
|
8
8
|
|
|
9
9
|
describe("config: hardcoded defaults", () => {
|
|
10
|
-
test("returns expected hardcoded values", () => {
|
|
11
|
-
const config = loadConfig();
|
|
12
|
-
expect(config.shutdownDrainMs).toBe(5000);
|
|
13
|
-
expect(config.runtimeTimeoutMs).toBe(30000);
|
|
14
|
-
expect(config.runtimeMaxRetries).toBe(2);
|
|
15
|
-
expect(config.runtimeInitialBackoffMs).toBe(500);
|
|
16
|
-
expect(config.maxWebhookPayloadBytes).toBe(1024 * 1024);
|
|
17
|
-
expect(config.maxEmailWebhookPayloadBytes).toBe(350 * 1024 * 1024);
|
|
18
|
-
expect(config.maxAttachmentBytes).toEqual({
|
|
19
|
-
telegram: 20 * 1024 * 1024,
|
|
20
|
-
slack: 100 * 1024 * 1024,
|
|
21
|
-
whatsapp: 16 * 1024 * 1024,
|
|
22
|
-
discord: 100 * 1024 * 1024,
|
|
23
|
-
email: 25 * 1024 * 1024,
|
|
24
|
-
default: 100 * 1024 * 1024,
|
|
25
|
-
});
|
|
26
|
-
expect(config.maxAttachmentConcurrency).toBe(3);
|
|
27
|
-
expect(config.runtimeProxyRequireAuth).toBe(true);
|
|
28
|
-
expect(config.trustProxy).toBe(false);
|
|
29
|
-
expect(config.routingEntries).toEqual([]);
|
|
30
|
-
expect(config.logFile.dir).toMatch(/logs$/);
|
|
31
|
-
expect(config.logFile.retentionDays).toBe(30);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
10
|
test("GATEWAY_PORT defaults to 7830", () => {
|
|
35
11
|
const saved = process.env.GATEWAY_PORT;
|
|
36
12
|
delete process.env.GATEWAY_PORT;
|
|
@@ -425,7 +425,6 @@ function makeConfig(overrides: Partial<GatewayConfig> = {}): GatewayConfig {
|
|
|
425
425
|
routingEntries: [],
|
|
426
426
|
port: 7830,
|
|
427
427
|
runtimeProxyRequireAuth: true,
|
|
428
|
-
shutdownDrainMs: 5000,
|
|
429
428
|
runtimeTimeoutMs: 30000,
|
|
430
429
|
runtimeMaxRetries: 2,
|
|
431
430
|
runtimeInitialBackoffMs: 500,
|
|
@@ -125,7 +125,7 @@ describe("credential-request mint (IPC)", () => {
|
|
|
125
125
|
fakeConfigFile(undefined),
|
|
126
126
|
{ service: "github", field: "api_token" },
|
|
127
127
|
{
|
|
128
|
-
|
|
128
|
+
getCloudAssistantId: async () => "assistant-123",
|
|
129
129
|
ensurePublicIngressLive,
|
|
130
130
|
},
|
|
131
131
|
);
|
|
@@ -149,16 +149,16 @@ describe("credential-request mint (IPC)", () => {
|
|
|
149
149
|
expect(ensurePublicIngressLive).not.toHaveBeenCalled();
|
|
150
150
|
});
|
|
151
151
|
|
|
152
|
-
test("does not read the
|
|
153
|
-
const
|
|
152
|
+
test("does not read the cloud assistant id when the config URL resolves", async () => {
|
|
153
|
+
const getCloudAssistantId = mock(async () => "assistant-123");
|
|
154
154
|
const result = await createCredentialRequest(
|
|
155
155
|
fakeGatewayConfig("https://tunnel-dev.mycadet.ai"),
|
|
156
156
|
fakeConfigFile("https://assistant.example.com"),
|
|
157
157
|
{ service: "github", field: "api_token" },
|
|
158
|
-
{
|
|
158
|
+
{ getCloudAssistantId },
|
|
159
159
|
);
|
|
160
160
|
expect(result.ok).toBe(true);
|
|
161
|
-
expect(
|
|
161
|
+
expect(getCloudAssistantId).not.toHaveBeenCalled();
|
|
162
162
|
});
|
|
163
163
|
|
|
164
164
|
test("falls back to TUNNEL_BASE_URL + platform assistant id when the config URL is empty", async () => {
|
|
@@ -168,7 +168,7 @@ describe("credential-request mint (IPC)", () => {
|
|
|
168
168
|
fakeGatewayConfig("https://tunnel-dev.mycadet.ai"),
|
|
169
169
|
fakeConfigFile(undefined),
|
|
170
170
|
{ service: "github", field: "api_token" },
|
|
171
|
-
{
|
|
171
|
+
{ getCloudAssistantId: async () => "assistant-123" },
|
|
172
172
|
);
|
|
173
173
|
|
|
174
174
|
if (!result.ok) throw new Error(`mint failed: ${result.error}`);
|
|
@@ -216,7 +216,7 @@ afterEach(async () => {
|
|
|
216
216
|
rmSync(testDir, { recursive: true, force: true });
|
|
217
217
|
});
|
|
218
218
|
|
|
219
|
-
describe("gateway
|
|
219
|
+
describe("gateway cloud credential bootstrap retry", () => {
|
|
220
220
|
test("reloads Telegram after CES becomes reachable without a metadata rewrite", async () => {
|
|
221
221
|
mkdirSync(testDir, { recursive: true });
|
|
222
222
|
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Two auth modes (mirrors `requireEdgeGuardianAuth`):
|
|
6
6
|
*
|
|
7
|
-
* 1. Platform-managed (DISABLE_HTTP_AUTH=true +
|
|
7
|
+
* 1. Platform-managed (DISABLE_HTTP_AUTH=true + IS_CLOUD=true): identity
|
|
8
8
|
* asserted via `X-Cadet-User-Id` header cross-referenced against the
|
|
9
9
|
* stored `cadet:platform_user_id` credential. Scope authorization is
|
|
10
|
-
* delegated to the upstream
|
|
10
|
+
* delegated to the upstream cloud proxy.
|
|
11
11
|
* 2. Default: edge JWT validated; scoped guard additionally checks the
|
|
12
12
|
* scope_profile claim.
|
|
13
13
|
*
|
|
14
|
-
* Importantly, DISABLE_HTTP_AUTH alone (without
|
|
14
|
+
* Importantly, DISABLE_HTTP_AUTH alone (without IS_CLOUD) does NOT
|
|
15
15
|
* bypass JWT validation — protects against accidental misconfig.
|
|
16
16
|
*/
|
|
17
17
|
|
|
@@ -37,8 +37,8 @@ mock.module("../credential-reader.js", () => ({
|
|
|
37
37
|
...actualCredentialReader,
|
|
38
38
|
readCredential: (key: string) => mockReadCredential(key),
|
|
39
39
|
}));
|
|
40
|
-
mock.module("../
|
|
41
|
-
|
|
40
|
+
mock.module("../cloud-user-id.js", () => ({
|
|
41
|
+
readStoredCloudUserId: async () => {
|
|
42
42
|
if (mockPlatformUserIdUnreachable) {
|
|
43
43
|
return { userId: undefined, unreachable: true };
|
|
44
44
|
}
|
|
@@ -101,17 +101,17 @@ beforeEach(() => {
|
|
|
101
101
|
|
|
102
102
|
afterEach(() => {
|
|
103
103
|
delete process.env.DISABLE_HTTP_AUTH;
|
|
104
|
-
delete process.env.
|
|
104
|
+
delete process.env.IS_CLOUD;
|
|
105
105
|
});
|
|
106
106
|
|
|
107
107
|
// =========================================================================
|
|
108
108
|
// requireEdgeAuth — platform bypass active
|
|
109
109
|
// =========================================================================
|
|
110
110
|
|
|
111
|
-
describe("requireEdgeAuth — DISABLE_HTTP_AUTH +
|
|
111
|
+
describe("requireEdgeAuth — DISABLE_HTTP_AUTH + IS_CLOUD", () => {
|
|
112
112
|
beforeEach(() => {
|
|
113
113
|
process.env.DISABLE_HTTP_AUTH = "true";
|
|
114
|
-
process.env.
|
|
114
|
+
process.env.IS_CLOUD = "true";
|
|
115
115
|
});
|
|
116
116
|
|
|
117
117
|
test("401 when X-Cadet-User-Id header is missing", async () => {
|
|
@@ -175,7 +175,7 @@ describe("requireEdgeAuth — DISABLE_HTTP_AUTH + IS_PLATFORM", () => {
|
|
|
175
175
|
expect(mockValidateEdgeToken).not.toHaveBeenCalled();
|
|
176
176
|
});
|
|
177
177
|
|
|
178
|
-
test("uses platform header check when a
|
|
178
|
+
test("uses platform header check when a cloud bearer is also forwarded", async () => {
|
|
179
179
|
mockReadCredential = mock(async () => PLATFORM_USER_ID);
|
|
180
180
|
const { requireEdgeAuth } = makeMiddleware();
|
|
181
181
|
const res = await requireEdgeAuth(
|
|
@@ -194,17 +194,17 @@ describe("requireEdgeAuth — DISABLE_HTTP_AUTH + IS_PLATFORM", () => {
|
|
|
194
194
|
// =========================================================================
|
|
195
195
|
|
|
196
196
|
describe("requireEdgeAuth — DISABLE_HTTP_AUTH alone is insufficient", () => {
|
|
197
|
-
test("DISABLE_HTTP_AUTH=true without
|
|
197
|
+
test("DISABLE_HTTP_AUTH=true without IS_CLOUD still runs JWT validation", async () => {
|
|
198
198
|
process.env.DISABLE_HTTP_AUTH = "true";
|
|
199
|
-
//
|
|
199
|
+
// IS_CLOUD intentionally NOT set
|
|
200
200
|
const { requireEdgeAuth } = makeMiddleware();
|
|
201
201
|
const res = await requireEdgeAuth(makeReq());
|
|
202
202
|
// No bearer token + no bypass → 401, NOT a free pass
|
|
203
203
|
expect(res?.status).toBe(401);
|
|
204
204
|
});
|
|
205
205
|
|
|
206
|
-
test("
|
|
207
|
-
process.env.
|
|
206
|
+
test("IS_CLOUD=true without DISABLE_HTTP_AUTH still runs JWT validation", async () => {
|
|
207
|
+
process.env.IS_CLOUD = "true";
|
|
208
208
|
// DISABLE_HTTP_AUTH intentionally NOT set
|
|
209
209
|
const { requireEdgeAuth } = makeMiddleware();
|
|
210
210
|
const res = await requireEdgeAuth(makeReq());
|
|
@@ -315,16 +315,16 @@ describe("requireEdgeAuth — JWT mode", () => {
|
|
|
315
315
|
// requireEdgeAuthWithScope — same bypass model + scope check on JWT path
|
|
316
316
|
// =========================================================================
|
|
317
317
|
|
|
318
|
-
describe("requireEdgeAuthWithScope — DISABLE_HTTP_AUTH +
|
|
318
|
+
describe("requireEdgeAuthWithScope — DISABLE_HTTP_AUTH + IS_CLOUD", () => {
|
|
319
319
|
beforeEach(() => {
|
|
320
320
|
process.env.DISABLE_HTTP_AUTH = "true";
|
|
321
|
-
process.env.
|
|
321
|
+
process.env.IS_CLOUD = "true";
|
|
322
322
|
});
|
|
323
323
|
|
|
324
324
|
test("uses platform header check; no scope check on bypass path", async () => {
|
|
325
325
|
// Even with a scope profile that wouldn't grant the required scope under
|
|
326
326
|
// JWT mode, the bypass path only cross-checks the user header. Scope is
|
|
327
|
-
// enforced upstream by the
|
|
327
|
+
// enforced upstream by the cloud proxy.
|
|
328
328
|
mockReadCredential = mock(async () => PLATFORM_USER_ID);
|
|
329
329
|
const { requireEdgeAuthWithScope } = makeMiddleware();
|
|
330
330
|
const res = await requireEdgeAuthWithScope(
|
|
@@ -335,7 +335,7 @@ describe("requireEdgeAuthWithScope — DISABLE_HTTP_AUTH + IS_PLATFORM", () => {
|
|
|
335
335
|
expect(res).toBeNull();
|
|
336
336
|
});
|
|
337
337
|
|
|
338
|
-
test("uses platform header check when a
|
|
338
|
+
test("uses platform header check when a cloud bearer is also forwarded", async () => {
|
|
339
339
|
mockReadCredential = mock(async () => PLATFORM_USER_ID);
|
|
340
340
|
const { requireEdgeAuthWithScope } = makeMiddleware();
|
|
341
341
|
const res = await requireEdgeAuthWithScope(
|
|
@@ -665,7 +665,7 @@ describe("requireEdgeAuth — trustProxy loopback fallback", () => {
|
|
|
665
665
|
|
|
666
666
|
test("platform bypass short-circuits before the fallback regardless of trustProxy", async () => {
|
|
667
667
|
process.env.DISABLE_HTTP_AUTH = "true";
|
|
668
|
-
process.env.
|
|
668
|
+
process.env.IS_CLOUD = "true";
|
|
669
669
|
const { requireEdgeAuth } = makeMiddleware(true);
|
|
670
670
|
// Missing X-Cadet-User-Id, loopback socket, trustProxy on: still the
|
|
671
671
|
// platform 401 (missing user header), NOT a loopback free pass.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tests for the `requireEdgeGuardianAuth` middleware — both modes:
|
|
3
3
|
*
|
|
4
|
-
* 1. Platform-managed (DISABLE_HTTP_AUTH=true +
|
|
4
|
+
* 1. Platform-managed (DISABLE_HTTP_AUTH=true + IS_CLOUD=true): identity
|
|
5
5
|
* asserted via `X-Cadet-User-Id` header cross-referenced against the
|
|
6
6
|
* stored `cadet:platform_user_id` credential.
|
|
7
7
|
* 2. Default (laptop / docker / bare-metal): edge JWT validated, then
|
|
@@ -21,8 +21,8 @@ let mockPlatformUserIdUnreachable = false;
|
|
|
21
21
|
mock.module("../credential-reader.js", () => ({
|
|
22
22
|
readCredential: (key: string) => mockReadCredential(key),
|
|
23
23
|
}));
|
|
24
|
-
mock.module("../
|
|
25
|
-
|
|
24
|
+
mock.module("../cloud-user-id.js", () => ({
|
|
25
|
+
readStoredCloudUserId: async () => {
|
|
26
26
|
if (mockPlatformUserIdUnreachable) {
|
|
27
27
|
return { userId: undefined, unreachable: true };
|
|
28
28
|
}
|
|
@@ -87,17 +87,17 @@ beforeEach(() => {
|
|
|
87
87
|
|
|
88
88
|
afterEach(() => {
|
|
89
89
|
delete process.env.DISABLE_HTTP_AUTH;
|
|
90
|
-
delete process.env.
|
|
90
|
+
delete process.env.IS_CLOUD;
|
|
91
91
|
});
|
|
92
92
|
|
|
93
93
|
// =========================================================================
|
|
94
|
-
// Platform-managed mode (DISABLE_HTTP_AUTH=true +
|
|
94
|
+
// Platform-managed mode (DISABLE_HTTP_AUTH=true + IS_CLOUD=true)
|
|
95
95
|
// =========================================================================
|
|
96
96
|
|
|
97
97
|
describe("requireEdgeGuardianAuth — platform header mode", () => {
|
|
98
98
|
beforeEach(() => {
|
|
99
99
|
process.env.DISABLE_HTTP_AUTH = "true";
|
|
100
|
-
process.env.
|
|
100
|
+
process.env.IS_CLOUD = "true";
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
test("returns 401 when X-Cadet-User-Id header is missing", async () => {
|
|
@@ -162,7 +162,7 @@ describe("requireEdgeGuardianAuth — platform header mode", () => {
|
|
|
162
162
|
expect(mockFindCadetGuardian).not.toHaveBeenCalled();
|
|
163
163
|
});
|
|
164
164
|
|
|
165
|
-
test("uses platform header check when a
|
|
165
|
+
test("uses platform header check when a cloud bearer is also forwarded", async () => {
|
|
166
166
|
mockReadCredential = mock(async () => PLATFORM_USER_ID);
|
|
167
167
|
const { requireEdgeGuardianAuth } = makeMiddleware();
|
|
168
168
|
const res = await requireEdgeGuardianAuth(
|
|
@@ -176,10 +176,10 @@ describe("requireEdgeGuardianAuth — platform header mode", () => {
|
|
|
176
176
|
expect(mockFindCadetGuardian).not.toHaveBeenCalled();
|
|
177
177
|
});
|
|
178
178
|
|
|
179
|
-
test("falls through to JWT mode when
|
|
180
|
-
// DISABLE_HTTP_AUTH=true but
|
|
179
|
+
test("falls through to JWT mode when IS_CLOUD is false (rejects missing bearer token)", async () => {
|
|
180
|
+
// DISABLE_HTTP_AUTH=true but IS_CLOUD=false → should use JWT path, not
|
|
181
181
|
// platform header path. No JWT provided, so expect 401.
|
|
182
|
-
process.env.
|
|
182
|
+
process.env.IS_CLOUD = "false";
|
|
183
183
|
const { requireEdgeGuardianAuth } = makeMiddleware();
|
|
184
184
|
const res = await requireEdgeGuardianAuth(
|
|
185
185
|
makeReq({ "x-cadet-user-id": PLATFORM_USER_ID }),
|