@gethelio/proxy 0.7.0 → 0.8.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/dist/cli.js CHANGED
@@ -3277,6 +3277,7 @@ var GovernedForwarder = class {
3277
3277
  let result;
3278
3278
  let approvalOutcome;
3279
3279
  let approvalWaitMs = 0;
3280
+ let approvalContext;
3280
3281
  let rateLimitResult;
3281
3282
  let spendLimitResult;
3282
3283
  let forwardingError;
@@ -3306,6 +3307,7 @@ var GovernedForwarder = class {
3306
3307
  result = approvalResult.result;
3307
3308
  approvalOutcome = approvalResult.outcome;
3308
3309
  approvalWaitMs = approvalResult.approvalWaitMs;
3310
+ approvalContext = approvalResult.approvalContext;
3309
3311
  }
3310
3312
  } else if (decision.action === "rate_limit") {
3311
3313
  if (!this.rateLimiter) {
@@ -3358,6 +3360,7 @@ var GovernedForwarder = class {
3358
3360
  dependencyResult,
3359
3361
  evidenceBlocked,
3360
3362
  approvalOutcome,
3363
+ approvalContext,
3361
3364
  rateLimitResult,
3362
3365
  spendLimitResult,
3363
3366
  isDryRun,
@@ -3379,6 +3382,16 @@ var GovernedForwarder = class {
3379
3382
  request.signal
3380
3383
  );
3381
3384
  const approvalWaitMs = performance.now() - approvalStart;
3385
+ const ticket = outcome.ticketId ? router.getTicket(outcome.ticketId) : void 0;
3386
+ const denialReason = outcome.status === "denied" && outcome.reason ? outcome.reason : void 0;
3387
+ const approvalContext = outcome.ticketId && (denialReason || ticket?.escalated_at) ? {
3388
+ ticket_id: outcome.ticketId,
3389
+ ...denialReason ? { denial_reason: denialReason } : {},
3390
+ ...ticket?.escalated_at ? {
3391
+ escalated_at: ticket.escalated_at,
3392
+ escalated_to: [...ticket.escalated_to ?? []]
3393
+ } : {}
3394
+ } : void 0;
3382
3395
  let result;
3383
3396
  if (outcome.status === "approved" || outcome.status === "break_glass") {
3384
3397
  if (request.signal?.aborted) {
@@ -3407,7 +3420,7 @@ var GovernedForwarder = class {
3407
3420
  result = makeErrorResult(request, POLICY_DENIED, message, { ...feedback });
3408
3421
  }
3409
3422
  }
3410
- return { result, outcome, approvalWaitMs };
3423
+ return { result, outcome, approvalWaitMs, approvalContext };
3411
3424
  }
3412
3425
  async handleRateLimit(request, decision, toolName) {
3413
3426
  const limiter = this.rateLimiter;
@@ -3587,7 +3600,7 @@ var GovernedForwarder = class {
3587
3600
  wasForwardedUpstream(decision, approvalOutcome, rateLimitResult, spendLimitResult) {
3588
3601
  return decision.action === "allow" || approvalOutcome?.status === "approved" || approvalOutcome?.status === "break_glass" || approvalOutcome?.status === "timeout" && this.approvalRouter?.defaultOnTimeout === "allow" || rateLimitResult?.allowed === true || spendLimitResult?.allowed === true;
3589
3602
  }
3590
- writeAuditRecord(request, timestamp, toolName, toolArguments, decision, result, totalDurationMs, approvalWaitMs, flaggedDestructive, evidenceResult, dependencyResult, evidenceBlocked, approvalOutcome, rateLimitResult, spendLimitResult, isDryRun, forwardingError, drift) {
3603
+ writeAuditRecord(request, timestamp, toolName, toolArguments, decision, result, totalDurationMs, approvalWaitMs, flaggedDestructive, evidenceResult, dependencyResult, evidenceBlocked, approvalOutcome, approvalContext, rateLimitResult, spendLimitResult, isDryRun, forwardingError, drift) {
3591
3604
  if (!this.auditWriter) return;
3592
3605
  const wasForwarded = this.wasForwardedUpstream(
3593
3606
  decision,
@@ -3622,6 +3635,12 @@ var GovernedForwarder = class {
3622
3635
  }
3623
3636
  };
3624
3637
  }
3638
+ if (approvalContext) {
3639
+ evidenceChain = {
3640
+ ...evidenceChain ?? {},
3641
+ approval: { ...approvalContext }
3642
+ };
3643
+ }
3625
3644
  if (rateLimitResult) {
3626
3645
  evidenceChain = {
3627
3646
  ...evidenceChain ?? {},
@@ -5255,6 +5274,7 @@ var EvidenceStore = class _EvidenceStore {
5255
5274
  // src/evidence/api.ts
5256
5275
  import { Hono as Hono5 } from "hono";
5257
5276
  import { bodyLimit } from "hono/body-limit";
5277
+ import { HTTPException } from "hono/http-exception";
5258
5278
  import { z as z5 } from "zod";
5259
5279
 
5260
5280
  // src/auth/bearer.ts
@@ -5455,6 +5475,11 @@ function createSidebandApp(store, options = {}) {
5455
5475
  const app = new Hono5();
5456
5476
  const sdkToken = options.token && options.token.length > 0 ? options.token : void 0;
5457
5477
  const adapterToken = options.adapterToken && options.adapterToken.length > 0 ? options.adapterToken : void 0;
5478
+ app.onError((err, c) => {
5479
+ if (err instanceof HTTPException) return err.getResponse();
5480
+ console.error("[helio] Unhandled sideband API error:", err);
5481
+ return c.json({ error: "Internal server error" }, 500);
5482
+ });
5458
5483
  app.use("*", async (c, next) => {
5459
5484
  const origin = c.req.header("origin");
5460
5485
  if (origin) {
@@ -5832,6 +5857,7 @@ var GovernanceService = class {
5832
5857
  }
5833
5858
  let approvalStatus = null;
5834
5859
  let approvedBy = null;
5860
+ let approvalContext;
5835
5861
  if (entry.approvalTicketId) {
5836
5862
  const ticket = this.getTicketStatus(entry.approvalTicketId);
5837
5863
  const status = ticket?.status;
@@ -5840,6 +5866,16 @@ var GovernanceService = class {
5840
5866
  }
5841
5867
  approvalStatus = status;
5842
5868
  approvedBy = ticket.resolved_by ?? null;
5869
+ if (ticket.denial_reason || ticket.escalated_at) {
5870
+ approvalContext = {
5871
+ ticket_id: entry.approvalTicketId,
5872
+ ...ticket.denial_reason ? { denial_reason: ticket.denial_reason } : {},
5873
+ ...ticket.escalated_at ? {
5874
+ escalated_at: ticket.escalated_at,
5875
+ escalated_to: [...ticket.escalated_to ?? []]
5876
+ } : {}
5877
+ };
5878
+ }
5843
5879
  }
5844
5880
  if (req.actual_amount !== void 0) {
5845
5881
  if (!Number.isFinite(req.actual_amount) || req.actual_amount < 0) {
@@ -5876,6 +5912,7 @@ var GovernanceService = class {
5876
5912
  limitsChain,
5877
5913
  approvalStatus,
5878
5914
  approvedBy,
5915
+ approvalContext,
5879
5916
  upstreamError: req.status === "error" ? req.error ?? "tool call failed" : null,
5880
5917
  upstreamResponse: req.result ?? null,
5881
5918
  upstreamLatencyMs: req.duration_ms ?? null
@@ -6281,6 +6318,9 @@ var GovernanceService = class {
6281
6318
  if (args.sidebandUnreported) {
6282
6319
  evidenceChain = { ...evidenceChain ?? {}, sideband: { unreported: true } };
6283
6320
  }
6321
+ if (args.approvalContext) {
6322
+ evidenceChain = { ...evidenceChain ?? {}, approval: { ...args.approvalContext } };
6323
+ }
6284
6324
  const record = {
6285
6325
  timestamp: args.timestampIso,
6286
6326
  session_id: args.sessionId,
@@ -7367,6 +7407,7 @@ import { readFileSync } from "fs";
7367
7407
  import { join } from "path";
7368
7408
  import { randomUUID as randomUUID6 } from "crypto";
7369
7409
  import { Hono as Hono8 } from "hono";
7410
+ import { HTTPException as HTTPException2 } from "hono/http-exception";
7370
7411
  import { z as z8 } from "zod";
7371
7412
  import { cors } from "hono/cors";
7372
7413
  import { serveStatic } from "@hono/node-server/serve-static";
@@ -7633,6 +7674,16 @@ function shouldSetSecureCookie(url, xForwardedProto) {
7633
7674
  if (xForwardedProto?.toLowerCase() === "https") return true;
7634
7675
  return new URL(url).protocol === "https:";
7635
7676
  }
7677
+ function isPrivateIpv4(host) {
7678
+ const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
7679
+ if (!match) return false;
7680
+ const a = Number(match[1]);
7681
+ const b = Number(match[2]);
7682
+ const c = Number(match[3]);
7683
+ const d = Number(match[4]);
7684
+ if (a > 255 || b > 255 || c > 255 || d > 255) return false;
7685
+ return a === 10 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168;
7686
+ }
7636
7687
  function createDashboardAppWithLifecycle(deps, options) {
7637
7688
  const {
7638
7689
  auditStore,
@@ -7646,6 +7697,11 @@ function createDashboardAppWithLifecycle(deps, options) {
7646
7697
  const apiSecret = options?.apiSecret;
7647
7698
  const sessionStore = apiSecret ? new DashboardSessionStore({ secret: apiSecret, ttlMs: SESSION_TTL_MS }) : void 0;
7648
7699
  const app = new Hono8();
7700
+ app.onError((err, c) => {
7701
+ if (err instanceof HTTPException2) return err.getResponse();
7702
+ console.error("[helio] Unhandled dashboard API error:", err);
7703
+ return c.json({ error: "Internal server error" }, 500);
7704
+ });
7649
7705
  app.use(
7650
7706
  "*",
7651
7707
  cors({
@@ -7655,7 +7711,7 @@ function createDashboardAppWithLifecycle(deps, options) {
7655
7711
  const url = new URL(origin);
7656
7712
  const h = url.hostname;
7657
7713
  if (h === "localhost" || h === "127.0.0.1" || h === "0.0.0.0") return origin;
7658
- if (/^(10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)/.test(h)) return origin;
7714
+ if (isPrivateIpv4(h)) return origin;
7659
7715
  } catch {
7660
7716
  }
7661
7717
  return null;