Inspiration

Every agent-permission model shares one blind spot: the gap between the human's "yes" and the agent's action.

RBAC answers who can do what. OAuth scopes answer what a token may touch. An approval queue answers did a person say yes. None of them answer whether that yes is still valid at the moment the agent actually acts.

A human approves deprecating a production table when it has two critical downstream consumers. Minutes later — before the agent executes — a third is wired up by a dbt job or another team. The world that justified the approval is gone, and nothing notices. The table gets deprecated with three dashboards depending on it, and a clean-looking audit trail. We built DataHubX to close exactly that gap, live against a real DataHub.

What it does

DataHubX is a governance layer for AI agents making real DataHub changes. Every change is approved against live data and re-verified at execution — if the data changed since approval, the action is blocked.

  1. The agent proposes one governed action. It reads DataHub through the official MCP server with every write tool disabled — it has no way to mutate anything.
  2. A policy engine deterministically returns ALLOW / REVIEW / BLOCK and declares which context fields its decision depended on.
  3. A Passport captures exactly those fields from DataHub and hashes them into an SHA-256 fingerprint — the record of the world the human is about to approve.
  4. A human approves that action against that fingerprint, producing an Ed25519-signed, single-use, 15-minute authorization (or a persisted rejection).
  5. The Gateway — the only mutation path in the system — runs fifteen checks in order before any write, ending in a fresh re-read of DataHub whose fingerprint must still match.
  6. Match → consume once, mutate, read the state back, VERIFIED_SUCCESS.
  7. Mismatch — CONTEXT_DRIFT → the authorization is permanently invalidated and DataHub is left byte-for-byte untouched. The agent replans against reality.

It runs live: the console drives a real self-hosted DataHub, and you can sign in to the catalog read-only and verify every mutation — or its absence — yourself.

How we built it

  • Pure domain core (no I/O): action registry, canonicalization + SHA-256 fingerprinting where absent, [] and "" are three distinct worlds and unreadable context fails closed, deterministic policy with declared dependencies, and Ed25519 signing where verifying authority never means being able to mint it.
  • The Gateway: the single privileged path — fifteen ordered checks, consume-before-mutate, read-back verification. It's the only file that imports the mutation module, enforced by a test that walks every source file.
  • DataHub integration: the security-critical Passport reads OpenAPI v3 aeage search — we measured search lagging real edge changes by 30+ seconds.The agent's discovery runs on the official mcp-server-datahub, version-pinned, six read tools allowlisted.
  • State & evidence: Postgres 18 + Prisma. Consumption is one atomic conditional UPDATE (proven by a 20-racer test). The full chain — action → passport → decision → approval →authorization → execution → receipt — is one transaction, and even refused changes land on a public changelog.
  • Delivery: Next.js 16 + Bun on a GCP VM behind Caddy, DataHub OSS v1.7 in Docker with auth enforced, GitHub Actions CI, one-command Docker tryout.

Challenges we ran into

  • Lineage search cannot feed a security decision. We found this by measurement, not docs — so the Passport reads primary-store aspects; search is only for agent discovery, wherestaleness costs a suggestion, not a mutation.
  • Unreadable ≠ empty. A narrowed DataHub token returns less rather than erroring, which would silently turn "production AND PII → REVIEW" into ALLOW. Readability is now part of the type — and this caught a real fail-open bug.
  • Proving nothing happened. The hardest thing to demonstrate is a mutation that didn't occur. The golden scenario asserts DataHub's own state is byte-identical after therefusal.

Accomplishments we're proud of

The central claim is provable, not asserted: 60 unit tests (including an adversarial gateway-security suite that attempts parameter swaps, replays, tampered claims, policy changes, and dishonest verification), 10 Postgres race tests, and an end-to-end golden scenario that asserts DataHub state byte-for-byte. CI is green. The agent's inability to writeis structural, not a prompt — so prompt injection has nothing to reach for.

What we learned

Trust in an agent system shouldn't be a property of the model's behavior — it should be a property of the surrounding machine. The model can propose anything; it simply cannot execute anything the Gateway hasn't independently re-verified against current reality.

What's next

Authenticated approver identity; split deployment with per-component scoped credentials; step-level authorization for multi-step workflows; a policy-management UI; and providerconnectors beyond DataHub — the domain core already knows nothing about DataHub, so the Gateway is the only piece a new provider has to teach.

Built With

Share this project:

Updates