HIP-1262: Reference — Lookup Sets
Abstract
/v1/reference is the lookup data a risk decision needs but cannot derive:
which email domains hand out throwaway inboxes, which addresses belong to a
datacentre or a Tor exit, which card scheme an issuer prefix belongs to, which
browsers the fleet sees everywhere, and how current the designation lists the
screening engine holds actually are (apps/reference/reference.go:15-19). It is
implemented in hanzoai/cloud at apps/reference. This HIP is where HIP-1046
§8's subtree now lives; HIP-1046 keeps the cross-plane invariants.
Motivation
Every one of these facts could be hard-coded where it is consulted, and each copy would go stale on its own schedule with nobody noticing — a designation list that answers "not listed" because it was never loaded is indistinguishable from a clean world. Making the lookup a capability puts freshness on the wire and makes staleness a reported condition rather than a silent one.
Specification
The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as in RFC 2119.
Two stores, one precedence
The Hanzo-maintained BASELINE lives in the shared warehouse —
hanzo.reference_source and hanzo.reference_entry, tables with NO tenant
column at all, so a cross-tenant write is unrepresentable rather than merely
forbidden (apps/reference/store.go:47-49). A tenant's OWN allow and deny
entries live in that organization's own SQLite file, opened per organization
through cloud.OrgStore under the name reference
(apps/reference/override.go, apps/reference/reference.go:34-40).
Resolution MUST be override first, then baseline; first hit wins.
Nothing derived from one organization's rows may enter the baseline, ever. The
only fleet-derived set is an aggregate published above a k-anonymity floor no
single organization can reach alone (apps/reference/set.go:297-299).
The address
The capability answers under /v1/reference: the set list at the root, one set
read, written and cleared at /{set} — a SET, which is why the name is singular
— resolve, and refresh (apps/reference/reference.go:507-525). Every
operation is typed. refresh writes the shared baseline every organization
reads and is therefore SuperAdmin only (apps/reference/reference.go:1328-1329);
it MUST stay one operation under this prefix, never an address family of its own. Today's router still serves
this surface under /v1/risk/reference; that pair is carried by
hanzoai/cloud openapi/misfiled.txt and closes by fold.
A version, a refusal, and freshness on the wire
Every set is a VERSION — the content digest of what was taken, so the same
data is the same version whoever fetched it, and a decision records one string
an auditor resolves back to a publisher, a licence and a date. A set that has
never loaded MUST REFUSE rather than answer "not listed"
(apps/reference/resolve.go:157), and a set whose source needs a licence we do
not hold is declared as a seam that refuses (apps/reference/set.go:93-95).
Freshness rides every answer: the version, when its oldest contributing
publisher was current — the oldest, because a set is exactly as fresh as its
weakest source (apps/reference/resolve.go:71-73) — how old that is, and
whether it is past bound. A stale set still answers, and says that it did.
Tenant, meter, events, observability, stage
Reads and override writes resolve the organization from the validated
principal (apps/reference/reference.go:549) and a request without one is
refused; the baseline is readable by every validated org and writable by none
of them. The capability is free, in those words
(plugin/reference/main.go:21, Price: cloud.Free). It publishes no events on
the bus. Beyond the request span it registers nothing; staleness and refusal —
the two ways this plane can be quietly wrong — are reported on the wire rather
than in a private metric. Its stage is whatever its manifest row declares —
HIP-0139 §8 keeps that in one place, and the beta this line used to assert had
already drifted from it.
Upstreams
It forks no code; the refusal discipline generalises what luxfi/aml
pkg/reference states (apps/reference/reference.go:25-28). What it MIRRORS
is published data, and the catalog declares each source's licence as a fact
beside its origin (apps/reference/set.go):
disposable-email-domains— CC0-1.0 (set.go:221-223);crawler-user-agents— MIT (set.go:255-257);- the Tor bulk exit list — CC BY 3.0 US (
set.go:242); - the IANA special-purpose address and AS-number registries — the registries of
record (
set.go:243-244,:269-271); - cloud and CDN operators' self-published IP feeds — machine-readable by intent,
no licence stated and none claimed (
set.go:234-241); - issuer prefixes — computed here from ISO/IEC 7812 structural facts; no issuer
database is licensed or held (
set.go:283-285); - sanctions designations — receipt only; they stay with the engine that screens
(
set.go:310-313).
A new source MUST enter through this catalog with its licence basis declared, or as a seam that refuses.
Rationale
The alternative was to file these operations under the model-serving plane, and
an earlier cut did exactly that (manifest/apps.go:231-238): lookup data in a
live product with different customers, where its growth reads as that product's
growth. The other alternative — folding into risk — fails on the store rule:
this capability owns two stores of its own, and the baseline's no-tenant-column
shape is a property risk's per-tenant planes cannot host.
Security Considerations
The baseline is consulted by every organization's decisions, so poisoning it is
the high-value attack: refresh is held to the platform's own identity, a
version is a content digest so a tampered take is a different version by
construction, and nothing an organization sends can reach the baseline tables —
their shape has nowhere for it to go. The override plane is the tenant-side
exposure: a per-org file reached only through the validated principal, so one
organization's allow-list cannot bleed into another's decisions. The remaining
risk is absence — an unloaded, unlicensed or stale set silently passing for a
clean answer — closed by refusing the first two and reporting the third.
References
- HIP-0026 — Identity and Access Management
- HIP-0106 — The Hanzo Plugin Contract
- HIP-0139 — Capability
- HIP-1046 — Risk
Copyright
Released under CC0 1.0 Universal Public Domain Dedication.