@mudraid/sidecar 1.1.1 → 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 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.
@@ -2,7 +2,7 @@
2
2
  "schema": "mudraid.sidecar.build-inputs/1",
3
3
  "bundledCore": {
4
4
  "name": "@mudraid/adapter-node",
5
- "version": "1.1.1",
5
+ "version": "1.1.2",
6
6
  "license": "Apache-2.0"
7
7
  },
8
8
  "inputs": [
@@ -36,7 +36,7 @@
36
36
  },
37
37
  {
38
38
  "path": "adapter-node/src/controlLoop.ts",
39
- "sha256": "ab76d5f9032564729bd6a3bf7cbd388a3d155cf9986b16e98c5e191beccce5be"
39
+ "sha256": "e51bdeccd9369006f30a5df6fda3d31aa88d718728143bf4b0d1087ef446040a"
40
40
  },
41
41
  {
42
42
  "path": "adapter-node/src/decideClient.ts",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  {
50
50
  "path": "adapter-node/src/httpAuthority.ts",
51
- "sha256": "fea3fdcd0bd0fe736f68dc80c97257f5edac10d10fa1671285fa9e0652d5d090"
51
+ "sha256": "cdf8f7e18ef8d71d90a88b5dd9cab455b70a6193ded98be84392eca8aa468acb"
52
52
  },
53
53
  {
54
54
  "path": "adapter-node/src/index.ts",
@@ -60,7 +60,7 @@
60
60
  },
61
61
  {
62
62
  "path": "adapter-node/src/types.ts",
63
- "sha256": "c3f95641c1a014bde935963a15728473a22a3ae4c2979c5f9b3bfcdac981d444"
63
+ "sha256": "f2e4f0a1441bb96122c418c0559a6015eb8234a7fb03014027680eacb722fb55"
64
64
  }
65
65
  ]
66
66
  }
@@ -350,7 +350,7 @@ 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.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
356
  surface: {
@@ -367,7 +367,7 @@ var HttpAuthority = class {
367
367
  const now = Date.now();
368
368
  const decidedAt = instant(response["decided_at"]);
369
369
  if (decidedAt > now + 3e4 || now - decidedAt > 6e4) throw new Error("Stale decision");
370
- if (instant(response["deadline_at"]) <= now) throw new Error("Expired decision");
370
+ const deadline = instant(response["deadline_at"]);
371
371
  const signature = object(response["signature"]);
372
372
  const claims = object(signature["claims"]);
373
373
  const keyId = signature["key_id"];
@@ -386,6 +386,7 @@ var HttpAuthority = class {
386
386
  if (instant(claims["not_before"]) > now + 3e4 || instant(claims["expires_at"]) <= now) throw new Error("Invalid decision window");
387
387
  if (snapshot !== this.bundle) throw new Error("Bundle changed during decision");
388
388
  if (response["decision"] !== "allow" && response["decision"] !== "deny") throw new Error("Invalid decision outcome");
389
+ if (deadline <= Date.now()) return { status: "expired" };
389
390
  if (this.observed?.version !== snapshot.version || this.observed.digest !== snapshot.digest) {
390
391
  this.observed = { version: snapshot.version, digest: snapshot.digest, at: new Date(now).toISOString() };
391
392
  }
@@ -409,6 +410,7 @@ var DEFAULT_PUBLIC_METHODS = /* @__PURE__ */ new Set([
409
410
  "tools/list"
410
411
  ]);
411
412
  var DECIDE_UNAVAILABLE_REASONS = {
413
+ expired: "deadline_exceeded",
412
414
  timeout: "deadline_exceeded",
413
415
  error: "authority_source_unavailable",
414
416
  unreachable: "authority_source_unavailable",
@@ -637,6 +639,17 @@ async function evaluateV2(facts, decide) {
637
639
  stripped
638
640
  );
639
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
+ }
640
653
  const reason = DECIDE_UNAVAILABLE_REASONS[result.status] ?? "authority_source_unavailable";
641
654
  return deny(
642
655
  reason,
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  main,
9
9
  staticDecideClient,
10
10
  throwingDecideClient
11
- } from "./chunk-XEUNXTTV.js";
11
+ } from "./chunk-5SXBQNJF.js";
12
12
  export {
13
13
  DEFAULT_MAX_BODY_BYTES,
14
14
  HttpAuthority,
package/dist/server.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  main
3
- } from "./chunk-XEUNXTTV.js";
3
+ } from "./chunk-5SXBQNJF.js";
4
4
 
5
5
  // src/cli.ts
6
6
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mudraid/sidecar",
3
- "version": "1.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.17.9",
25
- "tsx": "4.19.2",
24
+ "@types/node": "20.19.43",
25
+ "esbuild": "0.28.2",
26
+ "tsx": "4.23.15",
26
27
  "typescript": "5.6.3",
27
- "vitest": "2.1.8",
28
- "esbuild": "0.23.1"
28
+ "vitest": "4.1.11"
29
29
  },
30
30
  "exports": {
31
31
  ".": "./dist/index.js"