@mudraid/sidecar 1.1.0 → 1.1.2
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 +12 -0
- package/dist/build-inputs.json +29 -29
- package/dist/{chunk-AHPE2F3B.js → chunk-5SXBQNJF.js} +28 -10
- package/dist/index.js +1 -1
- package/dist/server.js +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -55,3 +55,15 @@ The image uses a build stage and runs compiled code as the unprivileged Node use
|
|
|
55
55
|
## Qualification still pending
|
|
56
56
|
|
|
57
57
|
Exact body bytes, caller, HTTP target and action/configuration are now bound to the signed decision, and the sidecar forwards its owned authorized snapshot. Trusted business-fact profiles and policy projection remain unimplemented; the runtime must not be represented as proving independent business-state truth or a committed operation. Standalone installed-package checks also do not establish network bypass resistance, containment-channel convergence, graceful drain, chaos/soak behavior or multi-architecture publication. These require their respective runtime evidence before broader support claims.
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
### Authorization expires before forwarding
|
|
61
|
+
|
|
62
|
+
A verified decision that arrives after its deadline is refused with HTTP 503,
|
|
63
|
+
`ENFORCE_DECIDE_UNAVAILABLE`, and reason `deadline_exceeded`. The message explains
|
|
64
|
+
that authorization expired and this attempt was not forwarded. This differs
|
|
65
|
+
from an unreachable authority; it does not mean that permission was denied.
|
|
66
|
+
The adapter does not automatically retry. A deliberate retry must obtain a fresh
|
|
67
|
+
decision. Use application-level idempotency for operations that could already
|
|
68
|
+
have executed in an earlier attempt; this error makes no claim about those
|
|
69
|
+
other attempts. Never reuse an expired decision or disable expiry validation.
|
package/dist/build-inputs.json
CHANGED
|
@@ -2,38 +2,10 @@
|
|
|
2
2
|
"schema": "mudraid.sidecar.build-inputs/1",
|
|
3
3
|
"bundledCore": {
|
|
4
4
|
"name": "@mudraid/adapter-node",
|
|
5
|
-
"version": "1.1.
|
|
5
|
+
"version": "1.1.2",
|
|
6
6
|
"license": "Apache-2.0"
|
|
7
7
|
},
|
|
8
8
|
"inputs": [
|
|
9
|
-
{
|
|
10
|
-
"path": "adapter-node/src/controlLoop.ts",
|
|
11
|
-
"sha256": "ab76d5f9032564729bd6a3bf7cbd388a3d155cf9986b16e98c5e191beccce5be"
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"path": "adapter-node/src/decideClient.ts",
|
|
15
|
-
"sha256": "34a649478f14e70a694e34f48df917caf2960addb917840d063ecf0c2b2b42b9"
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"path": "adapter-node/src/executionBinding.ts",
|
|
19
|
-
"sha256": "46f30a08a1c9816d5aa1fb04851980430f30e67e6a6e3d8134ee98ec935d7df6"
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
"path": "adapter-node/src/httpAuthority.ts",
|
|
23
|
-
"sha256": "9d75be27fd2a74e3ba7700e28ff26e1041262e70a8c621e77ba9d1c55b1efc16"
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
"path": "adapter-node/src/index.ts",
|
|
27
|
-
"sha256": "f13da52bce3d35ef7fe08e2fcbb25c05b2946c987eb59293126b19987cf5b951"
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
"path": "adapter-node/src/signedBundle.ts",
|
|
31
|
-
"sha256": "8a559c9ecfc2f69a392b6334159edc4384bd1c4b7033c53c5c38f9fc41f3c87e"
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"path": "adapter-node/src/types.ts",
|
|
35
|
-
"sha256": "c3f95641c1a014bde935963a15728473a22a3ae4c2979c5f9b3bfcdac981d444"
|
|
36
|
-
},
|
|
37
9
|
{
|
|
38
10
|
"path": "src/cli.ts",
|
|
39
11
|
"sha256": "848e7ecbeed33be9e9da3786e1b8a90eb29e62a2bd391a23f57d27710ff37d52"
|
|
@@ -61,6 +33,34 @@
|
|
|
61
33
|
{
|
|
62
34
|
"path": "src/upstream.ts",
|
|
63
35
|
"sha256": "804536cd44cf926fd5415b4bba95d03dfe031b7f00688f275184daf3b802caf8"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"path": "adapter-node/src/controlLoop.ts",
|
|
39
|
+
"sha256": "e51bdeccd9369006f30a5df6fda3d31aa88d718728143bf4b0d1087ef446040a"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"path": "adapter-node/src/decideClient.ts",
|
|
43
|
+
"sha256": "34a649478f14e70a694e34f48df917caf2960addb917840d063ecf0c2b2b42b9"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"path": "adapter-node/src/executionBinding.ts",
|
|
47
|
+
"sha256": "46f30a08a1c9816d5aa1fb04851980430f30e67e6a6e3d8134ee98ec935d7df6"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"path": "adapter-node/src/httpAuthority.ts",
|
|
51
|
+
"sha256": "cdf8f7e18ef8d71d90a88b5dd9cab455b70a6193ded98be84392eca8aa468acb"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"path": "adapter-node/src/index.ts",
|
|
55
|
+
"sha256": "f13da52bce3d35ef7fe08e2fcbb25c05b2946c987eb59293126b19987cf5b951"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"path": "adapter-node/src/signedBundle.ts",
|
|
59
|
+
"sha256": "8a559c9ecfc2f69a392b6334159edc4384bd1c4b7033c53c5c38f9fc41f3c87e"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"path": "adapter-node/src/types.ts",
|
|
63
|
+
"sha256": "f2e4f0a1441bb96122c418c0559a6015eb8234a7fb03014027680eacb722fb55"
|
|
64
64
|
}
|
|
65
65
|
]
|
|
66
66
|
}
|
|
@@ -63,7 +63,7 @@ function buildFacts(inbound, config) {
|
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
//
|
|
66
|
+
// vendor/adapter-node/src/decideClient.ts
|
|
67
67
|
function staticDecideClient(result) {
|
|
68
68
|
return async () => result;
|
|
69
69
|
}
|
|
@@ -73,10 +73,10 @@ function throwingDecideClient(error) {
|
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
//
|
|
76
|
+
// vendor/adapter-node/src/httpAuthority.ts
|
|
77
77
|
import { randomUUID } from "node:crypto";
|
|
78
78
|
|
|
79
|
-
//
|
|
79
|
+
// vendor/adapter-node/src/signedBundle.ts
|
|
80
80
|
import { createHash, createPublicKey, verify } from "node:crypto";
|
|
81
81
|
function object(value) {
|
|
82
82
|
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("Invalid object");
|
|
@@ -181,7 +181,7 @@ function verifyBundle(input, keys, binding, active, now = Date.now()) {
|
|
|
181
181
|
return freeze({ version, digest, expiresAt: expires, surface: JSON.parse(JSON.stringify(surface)), actions });
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
//
|
|
184
|
+
// vendor/adapter-node/src/executionBinding.ts
|
|
185
185
|
import { createHash as createHash2 } from "node:crypto";
|
|
186
186
|
var sha256 = (bytes) => createHash2("sha256").update(bytes).digest("hex");
|
|
187
187
|
function bindExecution(snapshot, action, context) {
|
|
@@ -223,7 +223,7 @@ function boundedArgumentBody(body) {
|
|
|
223
223
|
return Buffer.from(body).toString("base64");
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
-
//
|
|
226
|
+
// vendor/adapter-node/src/httpAuthority.ts
|
|
227
227
|
function keyMap(entries) {
|
|
228
228
|
if (!Array.isArray(entries)) throw new Error("Invalid verification key set");
|
|
229
229
|
const keys = /* @__PURE__ */ Object.create(null);
|
|
@@ -350,9 +350,14 @@ var HttpAuthority = class {
|
|
|
350
350
|
const response = await this.request("decide", "POST", {
|
|
351
351
|
schema_version: "mudraid.enforce.decide-request/1",
|
|
352
352
|
decision_id: decisionId,
|
|
353
|
-
adapter: { type: this.adapterType, version: "1.1.
|
|
353
|
+
adapter: { type: this.adapterType, version: "1.1.2" },
|
|
354
354
|
bundle: { version: snapshot.version, payload_digest: snapshot.digest },
|
|
355
|
-
|
|
355
|
+
// Bundle display metadata is not part of the strict decision contract.
|
|
356
|
+
surface: {
|
|
357
|
+
platform_id: snapshot.surface["platform_id"],
|
|
358
|
+
environment: snapshot.surface["environment"],
|
|
359
|
+
canonical_resource_uri: snapshot.surface["canonical_resource_uri"]
|
|
360
|
+
},
|
|
356
361
|
action: mapped,
|
|
357
362
|
request: { transport: "mcp_streamable_http", http_method: context.httpMethod, path: context.path },
|
|
358
363
|
presented_authorization: context.presentedAuthorization,
|
|
@@ -362,7 +367,7 @@ var HttpAuthority = class {
|
|
|
362
367
|
const now = Date.now();
|
|
363
368
|
const decidedAt = instant(response["decided_at"]);
|
|
364
369
|
if (decidedAt > now + 3e4 || now - decidedAt > 6e4) throw new Error("Stale decision");
|
|
365
|
-
|
|
370
|
+
const deadline = instant(response["deadline_at"]);
|
|
366
371
|
const signature = object(response["signature"]);
|
|
367
372
|
const claims = object(signature["claims"]);
|
|
368
373
|
const keyId = signature["key_id"];
|
|
@@ -381,6 +386,7 @@ var HttpAuthority = class {
|
|
|
381
386
|
if (instant(claims["not_before"]) > now + 3e4 || instant(claims["expires_at"]) <= now) throw new Error("Invalid decision window");
|
|
382
387
|
if (snapshot !== this.bundle) throw new Error("Bundle changed during decision");
|
|
383
388
|
if (response["decision"] !== "allow" && response["decision"] !== "deny") throw new Error("Invalid decision outcome");
|
|
389
|
+
if (deadline <= Date.now()) return { status: "expired" };
|
|
384
390
|
if (this.observed?.version !== snapshot.version || this.observed.digest !== snapshot.digest) {
|
|
385
391
|
this.observed = { version: snapshot.version, digest: snapshot.digest, at: new Date(now).toISOString() };
|
|
386
392
|
}
|
|
@@ -391,11 +397,11 @@ var HttpAuthority = class {
|
|
|
391
397
|
}
|
|
392
398
|
};
|
|
393
399
|
|
|
394
|
-
//
|
|
400
|
+
// vendor/adapter-node/src/types.ts
|
|
395
401
|
var RESERVED_HEADER_PREFIX = "x-mudraid-";
|
|
396
402
|
var MAX_TOOL_NAME_LEN = 512;
|
|
397
403
|
|
|
398
|
-
//
|
|
404
|
+
// vendor/adapter-node/src/controlLoop.ts
|
|
399
405
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
400
406
|
var CONTROL_VERBS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS", "DELETE"]);
|
|
401
407
|
var DEFAULT_PUBLIC_METHODS = /* @__PURE__ */ new Set([
|
|
@@ -404,6 +410,7 @@ var DEFAULT_PUBLIC_METHODS = /* @__PURE__ */ new Set([
|
|
|
404
410
|
"tools/list"
|
|
405
411
|
]);
|
|
406
412
|
var DECIDE_UNAVAILABLE_REASONS = {
|
|
413
|
+
expired: "deadline_exceeded",
|
|
407
414
|
timeout: "deadline_exceeded",
|
|
408
415
|
error: "authority_source_unavailable",
|
|
409
416
|
unreachable: "authority_source_unavailable",
|
|
@@ -632,6 +639,17 @@ async function evaluateV2(facts, decide) {
|
|
|
632
639
|
stripped
|
|
633
640
|
);
|
|
634
641
|
}
|
|
642
|
+
if (result.status === "expired") {
|
|
643
|
+
return deny(
|
|
644
|
+
"deadline_exceeded",
|
|
645
|
+
"authorization",
|
|
646
|
+
503,
|
|
647
|
+
"ENFORCE_DECIDE_UNAVAILABLE",
|
|
648
|
+
"Authorization expired before this request could be forwarded. This attempt was not forwarded. Obtain fresh authorization before retrying; do not automatically retry operations that may already have executed in another attempt.",
|
|
649
|
+
stripped,
|
|
650
|
+
"not_safely_decided"
|
|
651
|
+
);
|
|
652
|
+
}
|
|
635
653
|
const reason = DECIDE_UNAVAILABLE_REASONS[result.status] ?? "authority_source_unavailable";
|
|
636
654
|
return deny(
|
|
637
655
|
reason,
|
package/dist/index.js
CHANGED
package/dist/server.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mudraid/sidecar",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Customer-hosted MudraID enforcement proxy with authenticated configuration and signed decisions.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
"node": ">=20"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@types/node": "20.
|
|
25
|
-
"
|
|
24
|
+
"@types/node": "20.19.43",
|
|
25
|
+
"esbuild": "0.28.2",
|
|
26
|
+
"tsx": "4.23.15",
|
|
26
27
|
"typescript": "5.6.3",
|
|
27
|
-
"vitest": "
|
|
28
|
-
"esbuild": "0.23.1"
|
|
28
|
+
"vitest": "4.1.11"
|
|
29
29
|
},
|
|
30
30
|
"exports": {
|
|
31
31
|
".": "./dist/index.js"
|