@caelo-cms/provisioning 0.10.55 → 0.10.58
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/dist/agent-db.js +97 -24
- package/dist/cli-routing.js +1 -1
- package/dist/cli-routing.js.map +1 -1
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/compose.js +5 -0
- package/dist/compose.js.map +1 -1
- package/dist/converge-checkpoint.d.ts +66 -0
- package/dist/converge-checkpoint.d.ts.map +1 -0
- package/dist/converge-checkpoint.js +61 -0
- package/dist/converge-checkpoint.js.map +1 -0
- package/dist/converge-job-gcp.d.ts +46 -0
- package/dist/converge-job-gcp.d.ts.map +1 -0
- package/dist/converge-job-gcp.js +368 -0
- package/dist/converge-job-gcp.js.map +1 -0
- package/dist/converge-job-setup.d.ts +62 -0
- package/dist/converge-job-setup.d.ts.map +1 -0
- package/dist/converge-job-setup.js +228 -0
- package/dist/converge-job-setup.js.map +1 -0
- package/dist/converge-job.d.ts +141 -0
- package/dist/converge-job.d.ts.map +1 -0
- package/dist/converge-job.js +325 -0
- package/dist/converge-job.js.map +1 -0
- package/dist/gcp-names.d.ts +9 -0
- package/dist/gcp-names.d.ts.map +1 -1
- package/dist/gcp-names.js +13 -0
- package/dist/gcp-names.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/infra-contract.d.ts +1 -1
- package/dist/infra-contract.d.ts.map +1 -1
- package/dist/infra-contract.js +33 -1
- package/dist/infra-contract.js.map +1 -1
- package/dist/install-job.d.ts +11 -3
- package/dist/install-job.d.ts.map +1 -1
- package/dist/install-job.js +22 -12
- package/dist/install-job.js.map +1 -1
- package/dist/lifecycle.d.ts +13 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +115 -58
- package/dist/lifecycle.js.map +1 -1
- package/dist/operator-access.d.ts +4 -0
- package/dist/operator-access.d.ts.map +1 -1
- package/dist/operator-access.js +43 -7
- package/dist/operator-access.js.map +1 -1
- package/dist/release-contract.d.ts +3 -2
- package/dist/release-contract.d.ts.map +1 -1
- package/dist/release-contract.js +5 -2
- package/dist/release-contract.js.map +1 -1
- package/dist/release-manifest.d.ts +2 -0
- package/dist/release-manifest.d.ts.map +1 -1
- package/dist/release-manifest.js.map +1 -1
- package/dist/remote-mcp-edge.d.ts +114 -0
- package/dist/remote-mcp-edge.d.ts.map +1 -0
- package/dist/remote-mcp-edge.js +116 -0
- package/dist/remote-mcp-edge.js.map +1 -0
- package/dist/remote-mcp.d.ts +139 -0
- package/dist/remote-mcp.d.ts.map +1 -0
- package/dist/remote-mcp.js +434 -0
- package/dist/remote-mcp.js.map +1 -0
- package/dist/runtime-secrets.d.ts +12 -0
- package/dist/runtime-secrets.d.ts.map +1 -1
- package/dist/runtime-secrets.js +32 -4
- package/dist/runtime-secrets.js.map +1 -1
- package/dist/seal-key-rotation.d.ts +38 -0
- package/dist/seal-key-rotation.d.ts.map +1 -0
- package/dist/seal-key-rotation.js +206 -0
- package/dist/seal-key-rotation.js.map +1 -0
- package/dist/stack-contract.d.ts +206 -3
- package/dist/stack-contract.d.ts.map +1 -1
- package/dist/stack-contract.js +219 -4
- package/dist/stack-contract.js.map +1 -1
- package/dist/stack-converge.d.ts +53 -1
- package/dist/stack-converge.d.ts.map +1 -1
- package/dist/stack-converge.js +124 -4
- package/dist/stack-converge.js.map +1 -1
- package/dist/state-lock-lease.d.ts +142 -0
- package/dist/state-lock-lease.d.ts.map +1 -0
- package/dist/state-lock-lease.js +347 -0
- package/dist/state-lock-lease.js.map +1 -0
- package/dist/state-store.d.ts +66 -9
- package/dist/state-store.d.ts.map +1 -1
- package/dist/state-store.js +249 -30
- package/dist/state-store.js.map +1 -1
- package/dist/upgrade/app-roll.d.ts +36 -7
- package/dist/upgrade/app-roll.d.ts.map +1 -1
- package/dist/upgrade/app-roll.js +53 -19
- package/dist/upgrade/app-roll.js.map +1 -1
- package/dist/upgrade/audit-job-roll.d.ts.map +1 -1
- package/dist/upgrade/audit-job-roll.js +3 -1
- package/dist/upgrade/audit-job-roll.js.map +1 -1
- package/dist/upgrade/converge.d.ts.map +1 -1
- package/dist/upgrade/converge.js +125 -12
- package/dist/upgrade/converge.js.map +1 -1
- package/dist/upgrade/gcp-lookup.d.ts +27 -10
- package/dist/upgrade/gcp-lookup.d.ts.map +1 -1
- package/dist/upgrade/gcp-lookup.js +46 -7
- package/dist/upgrade/gcp-lookup.js.map +1 -1
- package/dist/upgrade/record-rolled.d.ts +40 -0
- package/dist/upgrade/record-rolled.d.ts.map +1 -0
- package/dist/upgrade/record-rolled.js +46 -0
- package/dist/upgrade/record-rolled.js.map +1 -0
- package/dist/upgrade/upgrade.d.ts +45 -1
- package/dist/upgrade/upgrade.d.ts.map +1 -1
- package/dist/upgrade/upgrade.js +60 -17
- package/dist/upgrade/upgrade.js.map +1 -1
- package/dist/upgrader-assess.d.ts +15 -1
- package/dist/upgrader-assess.d.ts.map +1 -1
- package/dist/upgrader-assess.js +36 -6
- package/dist/upgrader-assess.js.map +1 -1
- package/dist/upgrader-gcp.d.ts +15 -0
- package/dist/upgrader-gcp.d.ts.map +1 -1
- package/dist/upgrader-gcp.js +42 -7
- package/dist/upgrader-gcp.js.map +1 -1
- package/dist/upgrader-iam-preflight.d.ts +123 -0
- package/dist/upgrader-iam-preflight.d.ts.map +1 -0
- package/dist/upgrader-iam-preflight.js +414 -0
- package/dist/upgrader-iam-preflight.js.map +1 -0
- package/dist/upgrader-job.d.ts +33 -9
- package/dist/upgrader-job.d.ts.map +1 -1
- package/dist/upgrader-job.js +169 -27
- package/dist/upgrader-job.js.map +1 -1
- package/dist/upgrader-records.d.ts +58 -0
- package/dist/upgrader-records.d.ts.map +1 -0
- package/dist/upgrader-records.js +87 -0
- package/dist/upgrader-records.js.map +1 -0
- package/dist/upgrader-reporter.d.ts +3 -2
- package/dist/upgrader-reporter.d.ts.map +1 -1
- package/dist/upgrader-reporter.js +10 -2
- package/dist/upgrader-reporter.js.map +1 -1
- package/dist/upgrader-setup.d.ts +25 -3
- package/dist/upgrader-setup.d.ts.map +1 -1
- package/dist/upgrader-setup.js +123 -11
- package/dist/upgrader-setup.js.map +1 -1
- package/dist/wizards/gcp-cost.d.ts.map +1 -1
- package/dist/wizards/gcp-cost.js +11 -3
- package/dist/wizards/gcp-cost.js.map +1 -1
- package/dist/wizards/gcp-pulumi.d.ts +6 -0
- package/dist/wizards/gcp-pulumi.d.ts.map +1 -1
- package/dist/wizards/gcp-pulumi.js +14 -2
- package/dist/wizards/gcp-pulumi.js.map +1 -1
- package/dist/wizards/gcp.d.ts.map +1 -1
- package/dist/wizards/gcp.js +106 -4
- package/dist/wizards/gcp.js.map +1 -1
- package/package.json +2 -2
- package/src/agent/run.test.ts +14 -1
- package/src/audit-job-setup.test.ts +7 -1
- package/src/cli-routing.ts +1 -1
- package/src/cli.ts +4 -1
- package/src/compose.ts +5 -0
- package/src/converge-checkpoint.ts +75 -0
- package/src/converge-entrypoint.test.ts +213 -0
- package/src/converge-job-gcp.test.ts +222 -0
- package/src/converge-job-gcp.ts +443 -0
- package/src/converge-job-setup.test.ts +152 -0
- package/src/converge-job-setup.ts +268 -0
- package/src/converge-job.test.ts +486 -0
- package/src/converge-job.ts +542 -0
- package/src/gateway-env-isolation.test.ts +8 -1
- package/src/gcp-names.ts +15 -0
- package/src/gcp-url-map.test.ts +9 -1
- package/src/index.ts +8 -0
- package/src/infra-contract.test.ts +8 -4
- package/src/infra-contract.ts +33 -1
- package/src/install-job.test.ts +3 -1
- package/src/install-job.ts +31 -14
- package/src/lifecycle.ts +137 -71
- package/src/operator-access.test.ts +24 -1
- package/src/operator-access.ts +44 -6
- package/src/release-contract.ts +5 -2
- package/src/release-manifest.test.ts +42 -0
- package/src/release-manifest.ts +2 -0
- package/src/remote-mcp-edge.ts +137 -0
- package/src/remote-mcp.test.ts +690 -0
- package/src/remote-mcp.ts +524 -0
- package/src/runtime-secrets.test.ts +31 -6
- package/src/runtime-secrets.ts +41 -3
- package/src/seal-key-rotation.test.ts +131 -0
- package/src/seal-key-rotation.ts +258 -0
- package/src/stack-contract-parity.test.ts +20 -3
- package/src/stack-contract.test.ts +32 -2
- package/src/stack-contract.ts +363 -4
- package/src/stack-converge-secrets.test.ts +4 -0
- package/src/stack-converge.test.ts +21 -5
- package/src/stack-converge.ts +162 -7
- package/src/state-attach.test.ts +7 -1
- package/src/state-lock-lease.test.ts +302 -0
- package/src/state-lock-lease.ts +423 -0
- package/src/state-lock.test.ts +568 -0
- package/src/state-store.ts +347 -27
- package/src/upgrade/app-roll.ts +102 -21
- package/src/upgrade/audit-job-roll.ts +3 -1
- package/src/upgrade/converge.ts +148 -10
- package/src/upgrade/gcp-lookup.test.ts +80 -0
- package/src/upgrade/gcp-lookup.ts +65 -8
- package/src/upgrade/record-rolled.test.ts +105 -0
- package/src/upgrade/record-rolled.ts +91 -0
- package/src/upgrade/upgrade.test.ts +203 -3
- package/src/upgrade/upgrade.ts +120 -24
- package/src/upgrader-assess.test.ts +92 -3
- package/src/upgrader-assess.ts +58 -9
- package/src/upgrader-gcp.ts +47 -8
- package/src/upgrader-iam-preflight.test.ts +393 -0
- package/src/upgrader-iam-preflight.ts +510 -0
- package/src/upgrader-job.test.ts +586 -15
- package/src/upgrader-job.ts +237 -53
- package/src/upgrader-records.ts +151 -0
- package/src/upgrader-reporter.test.ts +6 -0
- package/src/upgrader-reporter.ts +7 -2
- package/src/upgrader-setup.test.ts +3 -3
- package/src/upgrader-setup.ts +128 -11
- package/src/wizards/gcp-cost.ts +12 -3
- package/src/wizards/gcp-pulumi.test.ts +15 -0
- package/src/wizards/gcp-pulumi.ts +18 -2
- package/src/wizards/gcp.ts +134 -4
- package/stacks/aws/index.ts +10 -0
- package/stacks/azure/index.ts +9 -0
- package/stacks/gcp/index.ts +47 -7
- package/stacks/gcp-firebase/index.ts +38 -6
|
@@ -172,6 +172,48 @@ describe("fetchVerifiedReleaseManifest", () => {
|
|
|
172
172
|
expect(r.ok ? "" : r.error.message).toContain("HTTP 404");
|
|
173
173
|
});
|
|
174
174
|
|
|
175
|
+
it("regression #865: a missing manifest or blob (404) is not transient — a retry cannot find it", async () => {
|
|
176
|
+
const missing = await fetchVerifiedReleaseManifest(
|
|
177
|
+
"0.11.0",
|
|
178
|
+
fixture({ manifestStatus: 404 }).deps,
|
|
179
|
+
);
|
|
180
|
+
expect(missing.ok ? null : missing.error).toMatchObject({ code: "registry" });
|
|
181
|
+
expect(missing.ok ? null : missing.error.transient).toBeUndefined();
|
|
182
|
+
const { deps } = fixture();
|
|
183
|
+
const noBlob = await fetchVerifiedReleaseManifest("0.11.0", {
|
|
184
|
+
...deps,
|
|
185
|
+
fetch: async (url, init) =>
|
|
186
|
+
url.includes("/blobs/") ? new Response("", { status: 404 }) : deps.fetch(url, init),
|
|
187
|
+
});
|
|
188
|
+
expect(noBlob.ok ? null : noBlob.error.code).toBe("registry");
|
|
189
|
+
expect(noBlob.ok ? null : noBlob.error.transient).toBeUndefined();
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("regression #865: 5xx, 429 and network failures are transient", async () => {
|
|
193
|
+
for (const status of [500, 503, 429]) {
|
|
194
|
+
const r = await fetchVerifiedReleaseManifest(
|
|
195
|
+
"0.11.0",
|
|
196
|
+
fixture({ manifestStatus: status }).deps,
|
|
197
|
+
);
|
|
198
|
+
expect(r.ok ? null : r.error).toMatchObject({ code: "registry", transient: true });
|
|
199
|
+
}
|
|
200
|
+
const { deps } = fixture();
|
|
201
|
+
const blob503 = await fetchVerifiedReleaseManifest("0.11.0", {
|
|
202
|
+
...deps,
|
|
203
|
+
fetch: async (url, init) =>
|
|
204
|
+
url.includes("/blobs/") ? new Response("", { status: 503 }) : deps.fetch(url, init),
|
|
205
|
+
});
|
|
206
|
+
expect(blob503.ok ? null : blob503.error).toMatchObject({ code: "registry", transient: true });
|
|
207
|
+
const down = await fetchVerifiedReleaseManifest("0.11.0", {
|
|
208
|
+
...deps,
|
|
209
|
+
fetch: async () => {
|
|
210
|
+
throw new TypeError("fetch failed: ECONNRESET");
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
expect(down.ok ? null : down.error).toMatchObject({ code: "registry", transient: true });
|
|
214
|
+
expect(down.ok ? "" : down.error.message).toContain("ECONNRESET");
|
|
215
|
+
});
|
|
216
|
+
|
|
175
217
|
it("rejects a non-SemVer version without touching the network", async () => {
|
|
176
218
|
const { deps, urls } = fixture();
|
|
177
219
|
const r = await fetchVerifiedReleaseManifest("v0.11.0", deps);
|
package/src/release-manifest.ts
CHANGED
|
@@ -129,6 +129,8 @@ export type ReleaseManifestErrorCode =
|
|
|
129
129
|
export interface ReleaseManifestError {
|
|
130
130
|
readonly code: ReleaseManifestErrorCode;
|
|
131
131
|
readonly message: string;
|
|
132
|
+
/** On `registry` errors a retry may cure; absent for not-found (see @caelo-cms/shared ReleaseArtifactError). */
|
|
133
|
+
readonly transient?: true;
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
export type ReleaseManifestResult =
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* #806 — what the `gcp` stack's load balancer does for remote MCP, declared
|
|
5
|
+
* once for the stack (new installs, imported from `dist/`) and for
|
|
6
|
+
* `cms-provision upgrade` (remote-mcp.ts `ensureRemoteMcpEdge`, existing
|
|
7
|
+
* installs). Pure module: no CLI or Pulumi imports.
|
|
8
|
+
*
|
|
9
|
+
* Routing: the broker's discovery documents live at the host root
|
|
10
|
+
* (`/.well-known/oauth-*`); the URL map sends those prefixes to the gateway
|
|
11
|
+
* together with `/api/*` (`GCP_PUBLIC_BASE_PATHS` in @caelo-cms/shared).
|
|
12
|
+
*
|
|
13
|
+
* Cloud Armor: the stack's policy bans an IP for 10 minutes after 100
|
|
14
|
+
* requests a minute and denies anything the OWASP sqli/xss rule packs flag.
|
|
15
|
+
* Both are wrong for `/api/mcp/*`:
|
|
16
|
+
*
|
|
17
|
+
* - MCP bodies carry HTML legitimately (module markup, page content the
|
|
18
|
+
* agent writes through Caelo's tools), which the xss/sqli packs flag.
|
|
19
|
+
* The broker accepts only bearer-authenticated JSON-RPC that the
|
|
20
|
+
* IAP-gated admin validates with Zod; Cloud Armor's signature match
|
|
21
|
+
* adds false positives there, not protection.
|
|
22
|
+
* - claude.ai and ChatGPT call from their own shared egress IPs, so every
|
|
23
|
+
* user of an install arrives from a handful of addresses. One agent
|
|
24
|
+
* session issues a JSON-RPC POST per tool call (plus initialize and
|
|
25
|
+
* notifications) — a busy Power-MCP agent sustains 1–3 a second. A
|
|
26
|
+
* 100/min ban would cut every user behind the same connector for 10
|
|
27
|
+
* minutes after one busy session.
|
|
28
|
+
*
|
|
29
|
+
* So the MCP paths ({@link MCP_ARMOR_PATH_PATTERN}) get their own rule, evaluated before the general ones
|
|
30
|
+
* (lower priority number = earlier; the first matching rule decides): a
|
|
31
|
+
* per-IP *throttle* of 600 requests a minute — about five busy agent
|
|
32
|
+
* sessions per egress IP — answering 429 above it without a ban, so a burst
|
|
33
|
+
* slows down instead of locking everyone out. Below the threshold the
|
|
34
|
+
* rule's action is `allow`, which ends evaluation: the OWASP packs and the
|
|
35
|
+
* general ban do not run for these paths. Abuse stays bounded by the
|
|
36
|
+
* gateway's max instances (100) and by IAP, which rejects every request
|
|
37
|
+
* without a valid token of an allowlisted user before it reaches the admin.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The paths the MCP rule covers, as an anchored RE2 pattern (Cloud Armor's
|
|
42
|
+
* `matches`): the two MCP endpoints and the broker's `oauth/<name>` and
|
|
43
|
+
* `oauth/<name>/<surface>` routes — lowercase letters and hyphens only.
|
|
44
|
+
*
|
|
45
|
+
* Deliberately not a prefix match. A `startsWith('/api/mcp/')` rule also
|
|
46
|
+
* matches `/api/mcp/../forms/submit` or `/api/mcp/%2e%2e/comments`, which
|
|
47
|
+
* the gateway's URL parser normalises to `/api/forms/submit` — so any
|
|
48
|
+
* public write could borrow the MCP rule's 600/min throttle and skip the
|
|
49
|
+
* OWASP packs and the ban. No dot, no percent sign and no extra segment can
|
|
50
|
+
* match this pattern, so a traversal falls through to the general rules.
|
|
51
|
+
* The dotted metadata aliases (`/.well-known/…`, `oauth/.well-known/…`) are
|
|
52
|
+
* one-off GETs per connection and stay under the general rules.
|
|
53
|
+
*/
|
|
54
|
+
export const MCP_ARMOR_PATH_PATTERN = "^/api/mcp/(chat|admin|oauth/[a-z-]+(/[a-z-]+)?)$";
|
|
55
|
+
|
|
56
|
+
/** The general per-IP ban rule and the OWASP rule packs the MCP rule must precede. */
|
|
57
|
+
export const GENERAL_RATE_LIMIT_PRIORITY = 1000;
|
|
58
|
+
export const OWASP_RULE_PRIORITIES: readonly number[] = [2000, 2001];
|
|
59
|
+
|
|
60
|
+
/** The `/api/mcp/*` rule of the gateway's Cloud Armor policy (see the module comment). */
|
|
61
|
+
export const MCP_ARMOR_RULE = {
|
|
62
|
+
priority: 900,
|
|
63
|
+
description: "Caelo remote MCP: per-IP throttle sized for agent traffic; skips the OWASP packs",
|
|
64
|
+
expression: `request.path.matches('${MCP_ARMOR_PATH_PATTERN}')`,
|
|
65
|
+
action: "throttle",
|
|
66
|
+
/** Requests per {@link MCP_ARMOR_RULE.intervalSec} per source IP. */
|
|
67
|
+
count: 600,
|
|
68
|
+
intervalSec: 60,
|
|
69
|
+
conformAction: "allow",
|
|
70
|
+
exceedAction: "deny(429)",
|
|
71
|
+
enforceOnKey: "IP",
|
|
72
|
+
} as const;
|
|
73
|
+
|
|
74
|
+
/** {@link MCP_ARMOR_RULE} in the shape `gcp.compute.SecurityPolicy` `rules` take. */
|
|
75
|
+
export function mcpArmorRuleArgs() {
|
|
76
|
+
const r = MCP_ARMOR_RULE;
|
|
77
|
+
return {
|
|
78
|
+
action: r.action,
|
|
79
|
+
priority: r.priority,
|
|
80
|
+
description: r.description,
|
|
81
|
+
match: { expr: { expression: r.expression } },
|
|
82
|
+
rateLimitOptions: {
|
|
83
|
+
rateLimitThreshold: { count: r.count, intervalSec: r.intervalSec },
|
|
84
|
+
conformAction: r.conformAction,
|
|
85
|
+
exceedAction: r.exceedAction,
|
|
86
|
+
enforceOnKey: r.enforceOnKey,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The `gcloud compute security-policies rules create|update` flags for
|
|
93
|
+
* {@link MCP_ARMOR_RULE} (without the verb, priority and policy).
|
|
94
|
+
*/
|
|
95
|
+
export function mcpArmorRuleFlags(): string[] {
|
|
96
|
+
const r = MCP_ARMOR_RULE;
|
|
97
|
+
return [
|
|
98
|
+
`--description=${r.description}`,
|
|
99
|
+
`--expression=${r.expression}`,
|
|
100
|
+
`--action=${r.action}`,
|
|
101
|
+
`--rate-limit-threshold-count=${r.count}`,
|
|
102
|
+
`--rate-limit-threshold-interval-sec=${r.intervalSec}`,
|
|
103
|
+
`--conform-action=${r.conformAction}`,
|
|
104
|
+
// gcloud spells deny(429) as deny-429.
|
|
105
|
+
"--exceed-action=deny-429",
|
|
106
|
+
`--enforce-on-key=${r.enforceOnKey}`,
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** A Cloud Armor rule as `gcloud compute security-policies describe --format=json` lists it. */
|
|
111
|
+
export interface LiveArmorRule {
|
|
112
|
+
readonly priority?: number;
|
|
113
|
+
readonly action?: string;
|
|
114
|
+
readonly match?: { readonly expr?: { readonly expression?: string } };
|
|
115
|
+
readonly rateLimitOptions?: {
|
|
116
|
+
readonly rateLimitThreshold?: { readonly count?: number; readonly intervalSec?: number };
|
|
117
|
+
readonly conformAction?: string;
|
|
118
|
+
readonly exceedAction?: string;
|
|
119
|
+
readonly enforceOnKey?: string;
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Whether a live rule is exactly {@link MCP_ARMOR_RULE}. */
|
|
124
|
+
export function isMcpArmorRule(rule: LiveArmorRule): boolean {
|
|
125
|
+
const r = MCP_ARMOR_RULE;
|
|
126
|
+
const o = rule.rateLimitOptions;
|
|
127
|
+
return (
|
|
128
|
+
rule.priority === r.priority &&
|
|
129
|
+
rule.action === r.action &&
|
|
130
|
+
rule.match?.expr?.expression === r.expression &&
|
|
131
|
+
o?.rateLimitThreshold?.count === r.count &&
|
|
132
|
+
o?.rateLimitThreshold?.intervalSec === r.intervalSec &&
|
|
133
|
+
o?.conformAction === r.conformAction &&
|
|
134
|
+
o?.exceedAction === r.exceedAction &&
|
|
135
|
+
(o?.enforceOnKey ?? "ALL") === r.enforceOnKey
|
|
136
|
+
);
|
|
137
|
+
}
|