Skip to content

Releases: IntentGate-app/intentgate-gateway

v1.6.2 — Grafana operational dashboard

18 May 12:56

Choose a tag to compare

What's new

Ships a pre-built Grafana dashboard JSON in dashboards/grafana/intentgate-gateway.json — 15 panels covering operational signals: request rate, p99 latency, deny rate, upstream success ratio, per-check decision rate by stage (capability / intent / policy / budget / upstream), per-check latency, end-to-end p50/p95/p99, upstream forward outcomes + latency, revocation lookups + latency, plus Go runtime in a collapsed row.

Importing. Open Grafana → Dashboards → Import → upload dashboards/grafana/intentgate-gateway.json (or paste its contents) → select your Prometheus datasource when prompted. The dashboard lands at /d/intentgate-gateway-ops.

kube-prometheus-stack users. The companion intentgate-helm chart will ship a labeled ConfigMap so the dashboard auto-discovers without manual import (next chart release).

See dashboards/README.md for the panel reference and import variants.

Requirements

  • Gateway started with INTENTGATE_METRICS_ENABLED=true (off by default; opt-in for info-disclosure reasons)
  • A Prometheus scraper hitting GET /metrics on the gateway's listen port

Also in this release

  • Minor docs polish (topology + pipeline diagrams, four-piece customer docs)
  • Postgres fresh-install fixes caught by the demo lab
  • Security policy + scanning config

Compatibility

No breaking changes. Drop-in replacement for v1.6.1.

v1.6.1

15 May 19:59

Choose a tag to compare

IntentGate Gateway v1.6.1

A patch release fixing three bugs in v1.6.0 that affect deployments using the Postgres backends for audit, approvals, or policy stores. Customers using only the in-memory backends are unaffected, but we recommend upgrading anyway since most production deployments switch to Postgres for replica-safety and persistence.

docker pull ghcr.io/netgnarus/intentgate-gateway:1.6.1

The companion intentgate-helm chart will be bumped in a follow-up release.

Fixes

Fresh-install migration failure on policy_active

INTENTGATE_POLICY_STORE=postgres against a brand-new database failed migration with:

policystore: migrate: ERROR: there is no unique or exclusion constraint
matching the ON CONFLICT specification (SQLSTATE 42P10)

The v1.5 CREATE TABLE IF NOT EXISTS policy_active block didn't declare a primary key — the schema relied on an ALTER TABLE migration step that only fires when upgrading FROM v1.4 (which had the PK on id). Fresh installs hit neither code path and the bottom-of-file seed INSERT ... ON CONFLICT (tenant) DO NOTHING had nothing to conflict against.

Fix: PRIMARY KEY (tenant) added to the CREATE TABLE. The 1.4→1.5 migration block is preserved for in-place upgrades.

Who is affected: any deployment standing up INTENTGATE_POLICY_STORE=postgres for the first time against an empty database. Existing v1.4 → v1.5 → v1.6 upgrades aren't affected because the migration block already moved their PK to (tenant) correctly.

Audit chain verify always failed on the first row

/v1/admin/audit/verify always returned ok=false with "hash mismatch (row body tampered)" on row 1, even on a chain that was provably untampered.

The gateway hashes the canonical event including its RFC3339Nano timestamp (9 digits of fractional seconds). Postgres TIMESTAMPTZ stores at microsecond precision (6 digits). When VerifyChain reads the row back, the round-tripped time.Time is missing the last 3 digits, the recomputed hash covers a different string than what was stored, and every chain reported a tampered first row.

Fix: Truncate(time.Microsecond) applied to the timestamp before computing the canonical hash at insert time, so the persisted string matches what verify will see after the database round-trip.

Who is affected: any deployment with INTENTGATE_AUDIT_PERSIST=true. The verify endpoint surfaced this on every chain. Audit data integrity itself was unaffected — the chain hashes were internally consistent; verify just couldn't reconstruct them from the database.

Escalate events broke the audit chain

After the first fix above, chains verified clean until the first escalate event — at which point verify reported a hash mismatch on the escalate row.

The canonical hash includes pending_id, decided_by, and requires_step_up (the approval-flow fields populated by runApprovalFlow), but the audit_events schema had no columns for them. The insert path hashed them in, the database silently discarded them, and verify's reconstruction couldn't recover them. The same class of bug also affected elevation_id — the column existed but VerifyChain's SELECT was missing it, so any admin event under JIT elevation would have broken the chain too (latent in v1.6.0 because the e2e tests didn't exercise an elevated escalate).

Fix: added pending_id, decided_by, requires_step_up columns to audit_events with idempotent ALTER TABLE ... ADD COLUMN IF NOT EXISTS migrations. Insert writes them; VerifyChain's SELECT + Scan reconstruct them along with the previously-missed elevation_id so the canonical hash is reproducible.

Who is affected: any deployment using INTENTGATE_APPROVALS_BACKEND=postgres (escalate path) or JIT admin elevation. The chain failed deterministically on the first such event.

Upgrade

In-place upgrade is safe. The migration block re-applies idempotently — IF NOT EXISTS on every CREATE TABLE and ALTER TABLE — so restarting against an existing database adds the new columns without data loss.

Existing audit chains written by v1.6.0 are unverifiable by design (the canonical-form mismatch means stored hashes can't be reproduced). v1.6.1 doesn't attempt to repair them; new events written after the upgrade form a new chain that verifies clean. SOC analysts wanting a tamper-evident audit trail should start their evidence window after the v1.6.1 upgrade. For deployments where this matters, optionally re-issue any compliance evidence packs that referenced v1.6.0 chain verification.

What we learned

All three bugs are in code paths that the unit test suite doesn't exercise against a real Postgres — the chain tests run against the in-memory store, and the policy store's existing Postgres test reused a long-lived database whose schema had already been applied at an earlier version. v1.6.1 adds internal/auditstore/postgres_test.go with four regression tests gated on INTENTGATE_TEST_POSTGRES_URL, each dropping the chain tables first so the migration runs against a truly empty database. These would have caught every one of the three bugs.

The deeper takeaway is that the existing pre-tag verify scripts targeted memory backends. The next CI iteration will run the full integration suite against a Postgres service container so this class of regression can't ship again.

Contact

j.cordoba@netgnarus.com for direct questions, security@netgnarus.com for disclosures.

Pro v2 — v1.6.0

12 May 07:57

Choose a tag to compare

IntentGate Gateway v1.6.0

A self-hosted authorization gateway for AI agents. This release is the Pro v2 milestone — tamper-evident audit, multi-tenant authorization, signed webhook emission, streaming audit export, and JIT elevation traceability. Open core, Apache 2.0.

docker pull ghcr.io/netgnarus/intentgate-gateway:1.6.0

The companion intentgate-helm chart deploys gateway + extractor in one helm install — pin to the chart version that wraps gateway v1.6.0.

At a glance

The gateway now answers six questions an auditor or SOC analyst will actually ask:

  1. "Has the audit log been tampered with?" → cryptographic chain verification.
  2. "Which agents/tools belong to which trust domain?" → per-tenant authorization with tenant-scoped admin tokens.
  3. "Why was this call allowed/blocked? Who approved it?" → audit events carry the policy reason, the approver identity, and (new) the JIT elevation id that justified the operator's privilege.
  4. "How do we hook this into our SIEM / on-call?" → HMAC-signed webhook emission for the deny / escalate / step-up subset.
  5. "Can we extract a quarter's worth of decisions for evidence?" → streaming CSV / NDJSON export with full filter passthrough.
  6. "Is the audit chain still advancing or has emission stalled?" → chain-head freshness on the verification endpoint.

Tamper-evident audit chain

Every audit event is hashed into a per-tenant SHA-256 chain at insert time:

hash = SHA-256(prev_hash || canonical_event_json)

The chain head advances atomically inside the same transaction as the row insert, with SELECT ... FOR UPDATE serializing concurrent emitter workers so the chain cannot fork. Pre-feature audit rows from earlier gateway releases have hash = '' and surface as skipped rather than failing verification, so existing deployments cut over without a backfill.

New endpointGET /v1/admin/audit/verify:

{
  "ok":       true,
  "tenant":   "acme",
  "verified": 12345,
  "skipped":  0,
  "head_at":  "2026-05-12T10:14:33.871Z",
  "head_id":  893421
}

When the chain diverges, ok is false and broken_at carries the offending event id, the stored vs. recomputed hashes, and a reason string (hash mismatch vs prev_hash mismatch). The endpoint returns 200 on every successful walk regardless of verdict — the body carries the answer so console clients render green/red without a 4xx/2xx branch.

Use case. SOC 2 / ISO 27001 evidence: an auditor asks "prove the audit log is integrity-protected." Run curl /v1/admin/audit/verify, screenshot the JSON, paste into the evidence pack.

Multi-tenant authorization

The gateway runs as a single logical instance serving multiple trust domains, each with its own:

  • Admin token (set via INTENTGATE_TENANT_ADMINS). A per-tenant admin can mint, revoke, query audit, and decide approvals within their tenant — and only their tenant. A cross-tenant attempt returns 403, not 404, so the API surface is honest about scoping.
  • Capability tokens (the tenant claim is HMAC-signed into the token itself; it cannot be forged by the client).
  • Audit timeline (/v1/admin/audit?tenant=...).
  • Approval queue, policy active-pointer, and per-tenant Rego active-policy slot.
  • Audit hash chain (per-tenant head row; tenants' chains are independent).

New endpointGET /v1/admin/tenants — surfaces configured per-tenant admin scopes so a multi-tenant console can populate a tenant switcher. Returns an empty list on single-tenant deploys; the console hides the switcher in that case.

A superadmin token (INTENTGATE_ADMIN_TOKEN) sees and operates across every tenant — useful for break-glass and platform-team operations.

Streaming audit export

New endpointGET /v1/admin/audit/export. Streams the filtered audit set as CSV (default, spreadsheet-friendly) or NDJSON (format=json, lossless including nested arg_values).

Same filters as /v1/admin/audit: tenant, from, to, agent_id, tool, decision, check, jti, elevation_id. Per-tenant admin tokens force their tenant onto the filter; cross-tenant queries return 403.

curl -H "Authorization: Bearer $ADMIN_TOKEN" \
  "$GATEWAY/v1/admin/audit/export?tenant=acme&from=2026-04-01T00:00:00Z&to=2026-06-30T23:59:59Z" \
  -o acme-q2.csv

The response carries Content-Disposition: attachment with a filename like intentgate-audit-acme-20260512T101433Z.csv so a browser triggers a download dialog. Internally the handler pages through the store at 1000 rows; results are capped at 200,000 rows per export with a audit export hit row cap warning logged on truncation. For larger evidence packs, narrow the window or slice by month.

Use case. GDPR Article 30 records of processing, AI Act Article 12 logging obligations, SOC 2 CC7.2 monitoring evidence — the export is the evidence row format. Pair with the verification endpoint for "we have the data + we can prove it wasn't tampered."

Signed webhook emission

The gateway can fan high-signal authorization events out to a configured webhook URL, separately from SIEM forwarding. Designed for chat-ops and paging — Slack / Teams / PagerDuty — not full audit shipping.

INTENTGATE_WEBHOOK_URL=https://console.example.com/api/webhook/intentgate
INTENTGATE_WEBHOOK_SECRET=<shared-secret>
INTENTGATE_WEBHOOK_EVENTS=deny,escalate,requires_step_up,approval_timeout

Each POST carries an X-IntentGate-Signature: sha256=<hex> HMAC over the raw body using the shared secret, verified in constant time on the receiver side. Retries on 5xx/429 with exponential backoff and a bounded buffer; dropped events surface as a counter rather than blocking the audit fan-out.

Receivers can transform per channel: the IntentGate Console (Pro) ships a built-in receiver that re-fans to Slack Block Kit, Teams Adaptive Card v1.4, and PagerDuty Events v2.

JIT elevation traceability

Every admin event the gateway emits now reads an optional X-IntentGate-Elevation-Id HTTP header and stamps it on the resulting audit row:

{
  "ts": "2026-05-12T10:14:33.871Z",
  "event": "admin/clear_policy",
  "decision": "allow",
  "decided_by": "alice@acme",
  "elevation_id": "elv_01HMZ9..."
}

The audit schema (now at schema_version: "6") adds a requires_step_up flag (advisory; sourced from the Rego policy's requires_step_up decision) and an elevation_id field (links back to the JIT approval row in a connected console). Combined, an auditor can pull "every privileged operation performed under elevation X, by whom, with what justification" with a single query:

curl "$GATEWAY/v1/admin/audit?elevation_id=elv_01HMZ9..." \
  -H "Authorization: Bearer $ADMIN_TOKEN"

The gateway itself does not validate the elevation id — it's metadata, not auth. Authority remains the admin token. This design lets the OSS gateway pair with any operator console that issues JIT elevations (the IntentGate Console Pro ships the full lifecycle out of the box).

Step-up flag on pending approvals

When the Rego policy escalates a tool call with requires_step_up: true, the gateway now propagates that flag onto the pending-approvals row:

GET /v1/admin/approvals
[
  {
    "pending_id": "pa_01HMZ...",
    "tool": "transfer_funds",
    "agent_id": "agent-trade-bot",
    "requires_step_up": true,
    ...
  }
]

Operator consoles read this to gate the Approve verdict behind a fresh step-up factor (TOTP / WebAuthn) before firing — console-side dual-control, not gateway-enforced. The audit row's combination of (decided_by, requires_step_up) is what an auditor verifies against the step-up verification audit event.

Chain-head freshness telemetry

GET /v1/admin/audit/verify now includes head_at (the RFC3339 timestamp of the most recent event in the per-tenant chain) and head_id. Operator dashboards render this as "chain last advanced N seconds ago" — distinguishes a live chain from one stalled at some weeks-old state. Omitted from the response when the tenant has no events yet, so consoles can render a "no events" hint instead of a misleading timestamp.

Other shipped this release

  • POST /v1/admin/mint — issue capability tokens via API (encoded once, never persisted server-side).
  • POST /v1/admin/policies/dry-run — replay a candidate Rego policy against historical audit events.
  • Policy draft + active-pointer endpoints — promote/rollback workflow for the live Rego policy without a redeploy.
  • SCIM-friendly requires_step_up and elevation_id columns persist in the Postgres audit store with appropriate partial indexes.
  • Postgres schema migrations are idempotent (ADD COLUMN IF NOT EXISTS); existing deployments roll forward without a manual step.

Compatibility & upgrade notes

  • Audit event JSON. Schema bumped to "6". All new fields are omitempty; SIEM mappings written against schema 1–5 keep working unchanged.
  • Postgres. Migrations run automatically at gateway startup. New columns: audit_events.elevation_id, pending_approvals.requires_step_up, audit_chain_heads table. All idempotent.
  • Helm. The companion chart (see intentgate-helm) deploys this gateway alongside the extractor. New optional values: webhook.url, webhook.secret, webhook.events. Per-tenant admin tokens accept either inline values or existing-Secret references.
  • No breaking API changes. Existing endpoints, env vars, and capability token formats are unchanged.

Capability claims at a glance

Capability Endpoint Pre-Pro v2?
Capability token mint / revoke POST /v1/admin/{mint,revoke} Yes (mint new in v0.5)
MCP tool-call authorization POST /v1/mcp Yes
Audit query ...
Read more