@mycadet/gateway 0.12.10 → 0.13.0
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/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +10 -10
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +3 -3
- package/node_modules/@mycadet/ces-client/src/http-credentials.ts +18 -1
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +10 -10
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +3 -3
- package/node_modules/@mycadet/gateway-client/src/gateway-ipc-contracts.ts +0 -20
- package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +10 -10
- package/node_modules/@mycadet/service-contracts/src/ingress.ts +3 -3
- package/openapi.json +1 -1
- package/package.json +1 -1
- package/src/__tests__/actor-token-revocation.test.ts +41 -34
- package/src/__tests__/contact-store-mirror-op-missing.test.ts +33 -70
- package/src/__tests__/contacts-mirror-op-reporter.test.ts +33 -89
- package/src/__tests__/credential-requests.test.ts +4 -4
- package/src/__tests__/devices-mine.test.ts +187 -0
- package/src/__tests__/edge-auth.test.ts +1 -20
- package/src/__tests__/edge-guardian-auth.test.ts +1 -17
- package/src/__tests__/feature-flag-resolver.test.ts +2 -30
- package/src/__tests__/feature-flag-watcher-callback.test.ts +0 -22
- package/src/__tests__/feature-flags-route.test.ts +2 -191
- package/src/__tests__/guardian-bootstrap-lookups.test.ts +22 -29
- package/src/__tests__/guardian-init-lockfile.test.ts +2 -2
- package/src/__tests__/guardian-integrity-reporter.test.ts +51 -82
- package/src/__tests__/guardian-integrity.test.ts +16 -20
- package/src/__tests__/handle-inbound-trust-verdict.test.ts +1 -14
- package/src/__tests__/ipc-feature-flag-routes.test.ts +0 -56
- package/src/__tests__/lum-2783-recovery-e2e.test.ts +0 -12
- package/src/__tests__/post-assistant-ready-deferred.test.ts +0 -18
- package/src/__tests__/refresh-device-binding.test.ts +0 -12
- package/src/__tests__/remote-web-pairing-token.test.ts +5 -15
- package/src/__tests__/runtime-client.test.ts +7 -7
- package/src/__tests__/speech-relay-websocket.test.ts +4 -4
- package/src/__tests__/trust-verdict-resolver-guardian-integrity.test.ts +30 -36
- package/src/__tests__/twilio-webhooks.test.ts +2 -2
- package/src/auth/actor-token-revocation.ts +34 -9
- package/src/auth/guardian-bootstrap.ts +1 -1
- package/src/cli/__tests__/pairing.test.ts +95 -0
- package/src/cli/index.ts +1 -1
- package/src/cli/pairing.ts +81 -6
- package/src/contacts-mirror-op-reporter.ts +19 -36
- package/src/db/connection.ts +0 -10
- package/src/feature-flag-resolver.ts +2 -7
- package/src/feature-flag-watcher.ts +1 -14
- package/src/guardian-integrity-reporter.ts +19 -47
- package/src/http/middleware/auth.ts +33 -27
- package/src/http/routes/auth-token.ts +1 -1
- package/src/http/routes/devices-mine.ts +103 -0
- package/src/http/routes/feature-flags.ts +1 -8
- package/src/http/routes/guardian-pin.ts +2 -11
- package/src/http/routes/ipc-runtime-proxy.ts +1 -1
- package/src/http/routes/live-voice-websocket.ts +1 -1
- package/src/http/routes/runtime-audio-stream.ts +1 -1
- package/src/http/routes/runtime-proxy.ts +2 -2
- package/src/http/routes/speech-relay-websocket.ts +2 -2
- package/src/http/routes/twilio-voice-webhook.test.ts +13 -13
- package/src/index.ts +11 -198
- package/src/ipc/feature-flag-handlers.ts +2 -9
- package/src/remote-web/pairing-challenge-store.ts +15 -0
- package/src/risk/command-registry/commands/assistant.ts +0 -24
- package/src/risk/command-registry.test.ts +2 -4
- package/src/schema.ts +44 -372
- package/src/__tests__/auth-fallback-count-tracker.test.ts +0 -92
- package/src/__tests__/auth-fallback-reporter.test.ts +0 -101
- package/src/__tests__/backup-worker-cloud-mode.test.ts +0 -44
- package/src/__tests__/backup-worker-export-timeout.test.ts +0 -164
- package/src/__tests__/migration-teleport-gcs-proxy.test.ts +0 -216
- package/src/__tests__/remote-feature-flag-sync.test.ts +0 -961
- package/src/auth-fallback-count-tracker.ts +0 -113
- package/src/auth-fallback-reporter.ts +0 -127
- package/src/backup/backup-key.ts +0 -138
- package/src/backup/backup-routes.ts +0 -161
- package/src/backup/backup-worker.ts +0 -425
- package/src/backup/list-snapshots.ts +0 -97
- package/src/backup/local-writer.ts +0 -87
- package/src/backup/offsite-writer.ts +0 -182
- package/src/backup/paths.ts +0 -113
- package/src/backup/stream-crypt.ts +0 -258
- package/src/device-id.ts +0 -18
- package/src/feature-flag-remote-store.ts +0 -166
- package/src/http/routes/migration-proxy.ts +0 -636
- package/src/internal-telemetry-client.ts +0 -39
- package/src/ipc/debug-export-handlers.test.ts +0 -102
- package/src/ipc/debug-export-handlers.ts +0 -81
- package/src/remote-feature-flag-sync.ts +0 -440
- package/src/watchdog-reporter.ts +0 -110
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Gateway-side remote feature flag store — file-backed persistence of
|
|
3
|
-
* feature flag values pushed from the cloud.
|
|
4
|
-
*
|
|
5
|
-
* Mirrors the feature-flag-store.ts pattern: file path resolution via
|
|
6
|
-
* getGatewaySecurityDir(), atomic writes (temp file + rename), 0o600
|
|
7
|
-
* permissions, and module-level caching with manual invalidation.
|
|
8
|
-
*
|
|
9
|
-
* Unlike the local override store, writes replace the *entire* value map at
|
|
10
|
-
* once (the cloud pushes a complete snapshot) and immediately update the
|
|
11
|
-
* in-memory cache so no file watcher is needed.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
chmodSync,
|
|
16
|
-
existsSync,
|
|
17
|
-
mkdirSync,
|
|
18
|
-
readFileSync,
|
|
19
|
-
renameSync,
|
|
20
|
-
writeFileSync,
|
|
21
|
-
} from "node:fs";
|
|
22
|
-
import { dirname, join } from "node:path";
|
|
23
|
-
|
|
24
|
-
import { getLogger } from "./logger.js";
|
|
25
|
-
import { getGatewaySecurityDir } from "./paths.js";
|
|
26
|
-
|
|
27
|
-
const log = getLogger("feature-flag-remote-store");
|
|
28
|
-
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
// Types
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
|
|
33
|
-
interface FeatureFlagFileData {
|
|
34
|
-
version: 1;
|
|
35
|
-
values: Record<string, boolean | string>;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// ---------------------------------------------------------------------------
|
|
39
|
-
// File path
|
|
40
|
-
// ---------------------------------------------------------------------------
|
|
41
|
-
|
|
42
|
-
export function getRemoteFeatureFlagStorePath(): string {
|
|
43
|
-
return join(getGatewaySecurityDir(), "feature-flags-remote.json");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
|
-
// Disk I/O with caching
|
|
48
|
-
// ---------------------------------------------------------------------------
|
|
49
|
-
|
|
50
|
-
let cachedRemoteValues: Record<string, boolean | string> | null = null;
|
|
51
|
-
|
|
52
|
-
export function readRemoteFeatureFlags(): Record<string, boolean | string> {
|
|
53
|
-
if (cachedRemoteValues != null) return cachedRemoteValues;
|
|
54
|
-
|
|
55
|
-
const path = getRemoteFeatureFlagStorePath();
|
|
56
|
-
if (!existsSync(path)) {
|
|
57
|
-
cachedRemoteValues = {};
|
|
58
|
-
return cachedRemoteValues;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
const raw = readFileSync(path, "utf-8");
|
|
63
|
-
const data = JSON.parse(raw) as FeatureFlagFileData;
|
|
64
|
-
|
|
65
|
-
if (data.version !== 1) {
|
|
66
|
-
log.warn(
|
|
67
|
-
{ version: data.version },
|
|
68
|
-
"Unknown remote feature flag store version, returning empty values",
|
|
69
|
-
);
|
|
70
|
-
cachedRemoteValues = {};
|
|
71
|
-
return cachedRemoteValues;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (
|
|
75
|
-
data.values &&
|
|
76
|
-
typeof data.values === "object" &&
|
|
77
|
-
!Array.isArray(data.values)
|
|
78
|
-
) {
|
|
79
|
-
const filtered: Record<string, boolean | string> = {};
|
|
80
|
-
for (const [k, v] of Object.entries(data.values)) {
|
|
81
|
-
if (typeof v === "boolean" || typeof v === "string") filtered[k] = v;
|
|
82
|
-
}
|
|
83
|
-
cachedRemoteValues = filtered;
|
|
84
|
-
} else {
|
|
85
|
-
cachedRemoteValues = {};
|
|
86
|
-
}
|
|
87
|
-
return cachedRemoteValues;
|
|
88
|
-
} catch (err) {
|
|
89
|
-
log.error({ err }, "Failed to load remote feature flag store");
|
|
90
|
-
cachedRemoteValues = {};
|
|
91
|
-
return cachedRemoteValues;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Persist remote feature flags to disk and update the in-memory cache.
|
|
97
|
-
* Returns `true` when the new values differ from the previous cache.
|
|
98
|
-
*/
|
|
99
|
-
export function writeRemoteFeatureFlags(
|
|
100
|
-
values: Record<string, boolean | string>,
|
|
101
|
-
): boolean {
|
|
102
|
-
const path = getRemoteFeatureFlagStorePath();
|
|
103
|
-
const dir = dirname(path);
|
|
104
|
-
if (!existsSync(dir)) {
|
|
105
|
-
mkdirSync(dir, { recursive: true });
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const data: FeatureFlagFileData = { version: 1, values };
|
|
109
|
-
const tmpPath = path + ".tmp." + process.pid;
|
|
110
|
-
writeFileSync(tmpPath, JSON.stringify(data, null, 2), { mode: 0o600 });
|
|
111
|
-
renameSync(tmpPath, path);
|
|
112
|
-
chmodSync(path, 0o600);
|
|
113
|
-
|
|
114
|
-
const changed = !shallowEqual(cachedRemoteValues, values);
|
|
115
|
-
cachedRemoteValues = values;
|
|
116
|
-
|
|
117
|
-
const msg = "Wrote remote feature flags";
|
|
118
|
-
const meta = { count: Object.keys(values).length };
|
|
119
|
-
if (changed) {
|
|
120
|
-
log.info(meta, msg);
|
|
121
|
-
} else {
|
|
122
|
-
log.debug(meta, msg);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return changed;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Returns `true` when the incoming flag snapshot matches what's already
|
|
130
|
-
* cached. Only used for log-level gating — correctness doesn't depend on it.
|
|
131
|
-
*/
|
|
132
|
-
function shallowEqual(
|
|
133
|
-
a: Record<string, boolean | string> | null,
|
|
134
|
-
b: Record<string, boolean | string>,
|
|
135
|
-
): boolean {
|
|
136
|
-
if (a == null) return false;
|
|
137
|
-
const aKeys = Object.keys(a);
|
|
138
|
-
if (aKeys.length !== Object.keys(b).length) return false;
|
|
139
|
-
for (const k of aKeys) {
|
|
140
|
-
if (a[k] !== b[k]) return false;
|
|
141
|
-
}
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Clear the in-memory cache so the next `readRemoteFeatureFlags()` call
|
|
147
|
-
* re-reads from disk. Useful in tests for resetting state between cases.
|
|
148
|
-
*/
|
|
149
|
-
export function clearRemoteFeatureFlagStoreCache(): void {
|
|
150
|
-
cachedRemoteValues = null;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Re-read the remote feature flag file from disk into the in-memory cache.
|
|
155
|
-
*
|
|
156
|
-
* Called by the file watcher when `feature-flags-remote.json` changes on
|
|
157
|
-
* disk (e.g. written by a separate process or a previous gateway instance).
|
|
158
|
-
* This ensures the next `readRemoteFeatureFlags()` call returns fresh data
|
|
159
|
-
* without requiring every read to hit disk.
|
|
160
|
-
*/
|
|
161
|
-
export function refreshRemoteFeatureFlagStoreCache(): void {
|
|
162
|
-
cachedRemoteValues = null;
|
|
163
|
-
// Force a re-read into cache immediately so the next
|
|
164
|
-
// readRemoteFeatureFlags() call picks up the new values.
|
|
165
|
-
readRemoteFeatureFlags();
|
|
166
|
-
}
|