Documentation
¶
Overview ¶
Package 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.
EVERY SET IS A VERSION, AND EVERY ANSWER NAMES IT. A version is the content digest of what was taken, so the same data is the same version whoever fetched it, and a decision can record one string that an auditor resolves back to a publisher, a licence and a date. A set that has never loaded REFUSES rather than answering "not listed", because a jurisdiction list that answers "not listed" because it was never loaded is indistinguishable from a clean world — the discipline luxfi/aml pkg/reference states and this plane generalises.
FRESHNESS IS ITSELF A RISK SIGNAL, so it is on the wire: every answer carries the version, when its oldest contributing publisher was current, how old that is, and whether it is past the bound. A stale set still answers — yesterday's list beats none — and says that it did.
TWO PLANES, TWO STORES, ONE PRECEDENCE. The Hanzo-maintained BASELINE lives in the shared warehouse (store.go) and its tables have NO tenant column at all: there is nowhere in the shape for an organisation to go, so a cross-tenant write is unrepresentable rather than merely forbidden. A tenant's OWN allow and deny entries live in that organisation's own SQLite file (override.go), reached through the one door a validated org walks through. Resolution is override first, then baseline; first hit wins.
WHAT MAY BE IN THE BASELINE. Data someone else published under terms we hold — every source in the catalog states its licence — and aggregates over fleet traffic that pass a k-anonymity floor no single organisation can reach alone. Nothing derived from one organisation's rows, ever. Where a source we would want needs a licence we do not have, the catalog declares it as a SEAM that refuses, because an unlicensed set and an absent one look identical from the outside and only one of them is a decision.
Surface (/v1 only):
GET /v1/risk/reference every set, its version and its freshness
GET /v1/risk/reference/{set} one set, plus this org's overrides
PUT /v1/risk/reference/{set} write this org's overrides
DELETE /v1/risk/reference/{set} clear one of this org's overrides
POST /v1/risk/reference/resolve resolve keys, naming the version consulted
POST /v1/risk/reference/refresh take a new version of a set (SuperAdmin)
Index ¶
- Constants
- func Mount(app cloud.Router, deps cloud.Deps) error
- func Publishable(orgs uint32, n uint64) bool
- func Shutdown() error
- type ClearReferenceIn
- type ClearReferenceOut
- type Entry
- type Grant
- type Kind
- type Match
- type ReferenceAnswer
- type ReferenceIn
- type ReferenceOut
- type ReferenceOverride
- type ReferenceOverrideIn
- type ReferenceReceipt
- type ReferenceSet
- type ReferenceSetsOut
- type ReferenceSource
- type ReferenceTaken
- type ReferenceVersion
- type RefreshReferenceIn
- type RefreshReferenceOut
- type ResolveReferenceIn
- type ResolveReferenceOut
- type Set
- type SetReferenceIn
- type SetReferenceOut
- type Source
Constants ¶
const ( Orgs = 25 Rows = 1000 )
The k-anonymity floor for anything derived from fleet traffic.
Orgs is the number of DISTINCT organisations that must have contributed before a key may be published. Twenty-five is chosen so that an adversary who controls several organisations still cannot attribute the row: to learn about one contributor you must know every other contributor's value.
Rows bounds the other direction. Twenty-five organisations contributing one observation each is twenty-five readable facts, not a population.
const ( Allow = "allow" Deny = "deny" )
The two verdicts an override can carry. An override is a DECISION, unlike a baseline entry, which carries facts and leaves the decision to policy — the tenant is the only party entitled to say "for us, this one is fine".
Variables ¶
This section is empty.
Functions ¶
func Mount ¶
Mount wires /v1/risk/reference/* and starts the hydrate-and-refresh loop.
The loop is started rather than the sets being loaded inline because the warehouse connects ASYNCHRONOUSLY: at mount time it is usually not up, and a mount that failed on that would abort the subsystem for a condition that resolves itself seconds later. Until the first hydrate succeeds every set refuses, which is the correct answer for a plane that has not loaded — and the one that matters after a restart, because this deployment runs one replica with a recreate rollout, so every rollout starts from nothing.
func Publishable ¶
Publishable is the k-anonymity gate as a PURE PREDICATE. It is exported because it is the ONE definition: the statement that computes a derived set binds these numbers, the reader re-checks them, and any other plane that publishes a cross-organisation aggregate must call this rather than restate the constants — two spellings of a floor is one floor that can drift, and the drift always favours the weaker.
Types ¶
type ClearReferenceIn ¶
type ClearReferenceIn struct {
// Set is the set to clear in, from the path.
Set string `json:"-" url:"set"`
// Key is the exact override key to remove.
Key string `json:"-" url:"key"`
}
ClearReferenceIn names one of your org's overrides to remove.
The key is a query parameter rather than a path segment because a key can be a CIDR or a pattern, and those carry the characters a path segment cannot.
type ClearReferenceOut ¶
type ClearReferenceOut struct {
// Set is the set cleared in.
Set string `json:"set"`
// Key is the entry named.
Key string `json:"key"`
// Cleared is false when your org held no such override — which is not an
// error, it is the honest answer to a removal that had nothing to remove.
Cleared bool `json:"cleared"`
// Overrides is how many your org still holds in this set.
Overrides int `json:"overrides"`
}
ClearReferenceOut reports whether there was an entry to remove.
type Entry ¶
type Entry struct {
// Key is the normalised member: a domain, a CIDR, an IIN prefix, a digest.
Key string
// Value is what the publisher says about it — class, operator, region,
// scheme. Facts, never a verdict: the verdict is the caller's policy, and a
// baseline that shipped verdicts would be making every tenant's policy for it.
Value map[string]string
// Score is a risk weight in [0,1] where the source expresses one, else zero.
Score float64
// Orgs and N are the k-anonymity evidence for a derived entry: how many
// distinct organisations and how many observations produced it. Zero for a
// published source, where the evidence is the licence instead.
Orgs uint32
N uint64
}
Entry is one member of a set: the key, the facts the publisher states about it, and — for a set derived from fleet traffic — the two counts that prove the row could not have come from one organisation.
type Grant ¶
type Grant string
Grant is the BASIS on which a source's data may reach a tenant through this plane. It is a closed vocabulary rather than free text, and that is the whole point of the type.
Terms used to be the only field, and it carried both kinds of sentence at once: "CC0-1.0" (a licence) and "operator-published range list" (a description of where a file came from). The gate over it could only ask whether the string was non-empty, so an unlicensed source wearing a licence field passed — the mirror image of the seam argument this plane is built on, where an unlicensed set REFUSES precisely because an absent one and an unlicensed one look identical from the outside.
Splitting the kind from the citation makes the position machine-checkable and puts it on the wire, so which sources rest on a licence and which rest on an operator's own publication is an audit anyone can run rather than a judgement buried in a string.
const ( // GrantLicence — the publisher states an explicit licence that permits // redistribution. Terms names it: CC0-1.0, MIT, CC BY 3.0 US. GrantLicence Grant = "licence" // GrantRegistry — the registry of record publishes the data for anyone to // consult, which is what a registry is for. Terms names the registry. GrantRegistry Grant = "registry" // GrantOperator — an operator's machine-readable statement about its OWN // network, published so third parties can filter and route by it. It is NOT a // licence and this value does not claim one: it says the data is a list of // factual prefixes the operator publishes for exactly this use, and Terms names // the publication. Stating that plainly is what lets someone review it. GrantOperator Grant = "operator" // GrantOwn — computed here, from a published standard or from fleet aggregates // that clear the k-anonymity floor. Nothing of anyone else's is redistributed. GrantOwn Grant = "own" // GrantNone — nothing reaches a tenant through this source at all: the // membership is held by the component that screens against it and this plane // carries only its freshness. The only honest basis for a set of kind attest. GrantNone Grant = "none" )
func (Grant) Redistributes ¶
Redistributes reports whether this basis lets a publisher's bytes reach a tenant. It is the predicate a fetched source must satisfy.
type Kind ¶
type Kind string
Kind is how a set's baseline comes to exist. Four kinds and no more, because each one implies a different answer to "what does silence mean here".
const ( // KindFetch is downloaded from a published source. An EMPTY fetch set is a // failure, never a fact: no publisher's list of disposable domains or hosting // ranges is empty, so zero entries means the fetch or the parse is wrong. KindFetch Kind = "fetch" // KindLocal is computed here — a structural table that follows from a // published standard, or an aggregate over fleet traffic. An empty local set // IS a fact: "no device is shared across enough organisations to publish" is a // true statement about the world. KindLocal Kind = "local" // KindAttest is held by the component that screens against it. This plane // records that component's load receipt and answers ONLY freshness — never // membership, because a second copy of a sanctions list is a second thing to // keep current and the two would disagree on the day it mattered. KindAttest Kind = "attest" // KindSeam is declared and NOT held: the source needs a licence we do not // have. Every lookup against it refuses. A seam is louder than an omission, // which is the whole reason it is in the catalog. KindSeam Kind = "seam" )
type Match ¶
type Match string
Match is how a key is tested against a set's entries. Five matchers, each a pure function over a built snapshot (see resolve.go).
const ( // MatchExact is equality on the normalised key: an ASN, a device digest, a // publisher name. MatchExact Match = "exact" // MatchDomain walks a hostname up its labels — mail.tempbox.example matches an // entry for tempbox.example — because a disposable provider's subdomains are // disposable too. MatchDomain Match = "domain" // MatchNet is longest-prefix on an IP address against CIDR entries. MatchNet Match = "net" // MatchDigits is longest numeric prefix, which is how an issuer identification // number addresses a card scheme. MatchDigits Match = "digits" // MatchPattern tests the key against each entry as a regular expression, // which is how a crawler declares itself in a user-agent string. MatchPattern Match = "pattern" // MatchRange is containment in a closed numeric interval, which is how a // number registry delegates autonomous system numbers in blocks. MatchRange Match = "range" )
type ReferenceAnswer ¶
type ReferenceAnswer struct {
// Set is the set consulted.
Set string `json:"set"`
// Key is the key as asked.
Key string `json:"key"`
// Hit is whether the key is a member. It is meaningful ONLY when Refusal is
// empty: false with a refusal means the set could not be consulted, which is
// not the same as the key being clean.
Hit bool `json:"hit"`
// From is override or baseline — which plane answered.
From string `json:"from,omitempty"`
// Matched is the member that covered the key, which for a domain or a network
// is the enclosing entry rather than the key itself.
Matched string `json:"matched,omitempty"`
// Verdict is the tenant's own allow or deny, present only for an override.
// The baseline never carries one: it states facts and leaves the decision to
// the caller's policy.
Verdict string `json:"verdict,omitempty"`
// Value is what the publisher says about the member — class, operator,
// scheme, region.
Value map[string]string `json:"value,omitempty"`
// Score is the published risk weight where the source expresses one.
Score float64 `json:"score,omitempty"`
// Version is the exact baseline version consulted, composed of each
// contributing publisher and its content digest. It is what makes a decision
// reproducible: an auditor takes this string and knows precisely what was
// consulted.
Version string `json:"version,omitempty"`
// AsOf is when the oldest contributing publisher was current, RFC 3339.
AsOf string `json:"asOf,omitempty"`
// Age is how old that is, as a duration.
Age string `json:"age,omitempty"`
// Stale is whether the set is past its freshness bound. A stale set still
// answers — yesterday's list beats none — and this is how a decision knows it
// leaned on one.
Stale bool `json:"stale,omitempty"`
// Refusal is why the set could not be consulted, when it could not: never
// loaded, held elsewhere, or a source we hold no licence for. Non-empty means
// Hit must not be read as an answer.
Refusal string `json:"refusal,omitempty"`
}
ReferenceAnswer is what the plane says about one key in one set — including, always, which version said it.
type ReferenceIn ¶
type ReferenceIn struct {
// Set is the set to describe, from the path.
Set string `json:"-" url:"set"`
// After pages the override listing: the last key of the previous page.
After string `json:"after"`
// Limit caps the override listing: default 200, maximum 1000.
Limit int `json:"limit"`
}
ReferenceIn addresses one set and pages this org's overrides in it.
type ReferenceOut ¶
type ReferenceOut struct {
// Set is the published set: its version, its freshness and its sources.
Set ReferenceSet `json:"set"`
// Overrides is YOUR org's entries over that baseline, in key order. They are
// held in your organisation's own store and are not visible to any other.
Overrides []ReferenceOverride `json:"overrides"`
// Next is the key to page from, empty when this is the last page.
Next string `json:"next,omitempty"`
}
ReferenceOut is one set and this org's own entries in it.
type ReferenceOverride ¶
type ReferenceOverride struct {
// Key is the member this organisation is speaking about.
Key string `json:"key"`
// Verdict is allow or deny.
Verdict string `json:"verdict"`
// Note is why, in the operator's own words. Optional, and bounded.
Note string `json:"note,omitempty"`
// At is when it was written, RFC 3339.
At string `json:"at"`
// By is who wrote it.
By string `json:"by,omitempty"`
}
ReferenceOverride is one entry a tenant laid over the baseline.
type ReferenceOverrideIn ¶
type ReferenceOverrideIn struct {
// Key is the member: a domain, a CIDR or address, an issuer prefix, a
// device digest. It is matched the same way the baseline is, so a deny on
// tempbox.example also covers mail.tempbox.example.
Key string `json:"key"`
// Verdict is allow or deny, and nothing else. An override is a decision —
// unlike a baseline entry, which states facts and leaves the decision to your
// policy — because your organisation is the only party entitled to say "for
// us, this one is fine".
Verdict string `json:"verdict"`
// Note is why, in your own words. Optional, bounded to 512 bytes.
Note string `json:"note,omitempty"`
}
ReferenceOverrideIn is one entry your org is laying over the baseline.
type ReferenceReceipt ¶
type ReferenceReceipt struct {
// Source is the publisher this receipt is for.
Source string `json:"source"`
// Version is the digest of what that publisher supplied, so a refresh that
// changed nothing can be told from a refresh that did not run.
Version string `json:"version"`
// AsOf is when the load happened, RFC 3339. Absent is dated on arrival, which
// can only make the list look older than it is.
AsOf string `json:"asOf,omitempty"`
// Keys is how many designations that load carried. Zero from a publisher who
// designates somebody is a failed load wearing a successful one's clothes,
// and belongs in Refusal instead.
Keys int `json:"keys"`
// Refusal is why the load failed, when it did.
Refusal string `json:"refusal,omitempty"`
}
ReferenceReceipt is a load receipt from the component that HOLDS a set's membership — the screening engine, for the designation lists.
type ReferenceSet ¶
type ReferenceSet struct {
// Set is the name this set is addressed by.
Set string `json:"set"`
// Kind is how the baseline comes to exist: fetch (downloaded from a
// publisher), local (computed here), attest (held by the component that
// screens against it, freshness reported), or seam (declared and NOT held,
// because the source needs a licence we do not have).
Kind string `json:"kind"`
// What the set holds, in one sentence.
What string `json:"what"`
// Match is how a key is tested: exact, domain, net, digits, pattern or range.
Match string `json:"match"`
// Version is the exact baseline consulted — every contributing publisher and
// its content digest. A decision records this and an auditor resolves it back.
Version string `json:"version,omitempty"`
// AsOf is when the OLDEST contributing publisher was current, RFC 3339. The
// oldest and not the newest: a set is exactly as fresh as its weakest source.
AsOf string `json:"asOf,omitempty"`
// Age is how long ago that was.
Age string `json:"age,omitempty"`
// MaxAge is how old this set may be before it is stale.
MaxAge string `json:"maxAge"`
// Stale is whether it is past that bound. A stale set still answers and says
// so, because yesterday's list beats none.
Stale bool `json:"stale"`
// Keys is how many members the baseline carries.
Keys int `json:"keys"`
// Overrides is how many entries YOUR org has laid over this baseline.
Overrides int `json:"overrides"`
// Sources is each contributing publisher, its licence and its own freshness.
Sources []ReferenceSource `json:"sources,omitempty"`
// Refusal names why the set cannot be relied on, when it cannot: never
// loaded, held elsewhere, or a licence we do not hold. Non-empty means a
// lookup against this set will not answer, rather than answering clean.
Refusal string `json:"refusal,omitempty"`
}
ReferenceSet is one published set and how current it is.
Age and Stale are first-class because a stale list answers "not listed" for everything and reads exactly like a clean world — the failure this whole plane exists to make visible.
type ReferenceSetsOut ¶
type ReferenceSetsOut struct {
// Sets is the whole catalog, in a stable order.
Sets []ReferenceSet `json:"sets"`
// Stale names the sets past their freshness bound — the list to alarm on.
Stale []string `json:"stale,omitempty"`
// Refused names the sets that cannot be consulted at all. A key checked
// against one of these is UNKNOWN, not clean.
Refused []string `json:"refused,omitempty"`
}
ReferenceSetsOut is every set the plane publishes.
type ReferenceSource ¶
type ReferenceSource struct {
// Source is the publisher.
Source string `json:"source"`
// Origin is exactly where it was taken from, so it can be taken again.
Origin string `json:"origin"`
// Basis is the KIND of permission this publisher's data reaches you under:
// licence (an explicit grant), registry (the registry of record publishing for
// anyone to consult), operator (an operator's own machine-readable statement
// about its own network, published for third parties to filter by — not a
// licence, and not claimed as one), own (computed here), or none (nothing
// reaches you: the membership is held by the component that screens against
// it). It is on the wire so the licence position is an audit you can run.
Basis string `json:"basis"`
// Terms is the CITATION that basis points at — the licence identifier, the
// registry, or the operator publication. A source with no stated terms is not
// in the catalog.
Terms string `json:"terms"`
// Version is the content digest of what this publisher last supplied. Two
// refreshes that agree on it took the same data.
Version string `json:"version,omitempty"`
// AsOf is when this publisher was current, RFC 3339.
AsOf string `json:"asOf,omitempty"`
// Keys is how many members this publisher contributed.
Keys int `json:"keys"`
// Refusal is why this publisher's last take failed, if it did. The set keeps
// its previous version of this source and ages out visibly rather than
// silently shrinking.
Refusal string `json:"refusal,omitempty"`
}
ReferenceSource is one publisher's contribution to a set.
type ReferenceTaken ¶
type ReferenceTaken struct {
// Source is the publisher.
Source string `json:"source"`
// Version is the content digest that landed.
Version string `json:"version,omitempty"`
// Keys is how many members it carries.
Keys int `json:"keys"`
// Wrote is how many rows this run actually wrote. Zero with Unchanged means
// the publisher served the same set again.
Wrote int `json:"wrote"`
// Unchanged is true when the publisher's data was byte-for-byte the set we
// already held.
Unchanged bool `json:"unchanged,omitempty"`
// Resumed is true when this run continued a version a previous run left
// half-landed.
Resumed bool `json:"resumed,omitempty"`
// Refusal is why this publisher contributed nothing, if it did not. The set
// keeps its previous version of this source rather than shrinking.
Refusal string `json:"refusal,omitempty"`
}
ReferenceTaken is what one publisher contributed to a refresh.
type ReferenceVersion ¶
type ReferenceVersion struct {
// Set is the set.
Set string `json:"set"`
// Version is every contributing publisher and its content digest.
Version string `json:"version,omitempty"`
// AsOf is when the oldest of them was current, RFC 3339.
AsOf string `json:"asOf,omitempty"`
// Stale is whether it is past its freshness bound.
Stale bool `json:"stale"`
// Refusal is why it could not be consulted, when it could not.
Refusal string `json:"refusal,omitempty"`
}
ReferenceVersion is one set's identity at the moment it was consulted.
type RefreshReferenceIn ¶
type RefreshReferenceIn struct {
// Set is the set to refresh.
Set string `json:"set"`
// Receipts are supplied by the component that holds the membership, for a set
// of kind attest. They are refused on any other kind, and a set of kind attest
// is refused without them: this plane never invents a freshness it did not
// observe.
Receipts []ReferenceReceipt `json:"receipts,omitempty" url:"-"`
// Force accepts a take whose size moved past the change bound. A publisher
// serving a tenth or ten times its previous list is refused by default and the
// previous version is left standing; this is the operator saying the change is
// real. It cannot make an empty, truncated or unparseable take land — those are
// errors, not magnitudes.
Force bool `json:"force,omitempty"`
}
RefreshReferenceIn asks the plane to take a new version of one set.
type RefreshReferenceOut ¶
type RefreshReferenceOut struct {
// Set is the set refreshed.
Set string `json:"set"`
// Took is what each publisher contributed.
Took []ReferenceTaken `json:"took"`
// Version is the set's new composed version.
Version string `json:"version,omitempty"`
// Stale is whether it is STILL past its freshness bound after the refresh,
// which is what a publisher that has stopped answering looks like.
Stale bool `json:"stale"`
}
RefreshReferenceOut is the outcome, per publisher.
type ResolveReferenceIn ¶
type ResolveReferenceIn struct {
// Sets narrows which sets to consult. Empty consults every set whose matcher
// can read the keys given.
Sets []string `json:"sets,omitempty" url:"-"`
// Keys are the values to look up, at most 100 per call: email addresses or
// domains, IP addresses, card prefixes, user-agent strings, autonomous system
// numbers, device digests.
Keys []string `json:"keys" url:"-"`
}
ResolveReferenceIn asks about keys.
type ResolveReferenceOut ¶
type ResolveReferenceOut struct {
// Answers is one entry per (set, key) consulted.
Answers []ReferenceAnswer `json:"answers"`
// Consulted names the version of every set that took part, so a decision can
// record precisely what it leaned on. Record this with the decision: it is
// what makes the decision reproducible a year later.
Consulted []ReferenceVersion `json:"consulted"`
// Stale names the consulted sets past their freshness bound. Staleness is
// itself a risk signal — a decision taken against a three-week-old list is a
// weaker decision, and this is how it knows.
Stale []string `json:"stale,omitempty"`
// Refused names the consulted sets that could not answer at all. A key that
// missed in one of these is UNKNOWN, not clean.
Refused []string `json:"refused,omitempty"`
}
ResolveReferenceOut is what the plane knows, and exactly which version knew it.
type Set ¶
type Set struct {
// Name is the address: /v1/risk/reference/<name>. One word, lower case.
Name string
// Kind decides what an empty set means and whether membership is held here.
Kind Kind
// What is one sentence an operator can read.
What string
// Match is how a key is tested against this set's entries.
Match Match
// MaxAge is how old a source's newest successful load may be before this set
// is STALE. Past it the set still answers, and every answer says so — a stale
// list answers "not listed" for everything and reads exactly like a clean
// world, which is the failure this whole plane exists to make visible.
MaxAge time.Duration
// Sources are the publishers this set draws on. Empty for local and seam sets.
Sources []Source
// Refusal is why a seam set cannot be consulted. Non-empty ONLY for KindSeam,
// and it names the licence we do not hold rather than saying "unavailable".
Refusal string
}
Set is one published reference set: what it holds, how fresh it has to be, and where its entries lawfully come from.
func Catalog ¶
func Catalog() []Set
Catalog is every set, in a stable order. It is the ONE declaration: the routes project it, the refresh walks it, and a lookup for a name not in it is a 404 rather than an invented empty answer.
LAWFULNESS IS A FIELD, NOT A FOOTNOTE. Every fetched source states the terms it is redistributed under, and every source we would want but may not have is present as a seam naming the licence we lack. The three seams below are the honest state of the art: politically-exposed-person listings, issuer identification tables and commercial network reputation are all sold, and the free copies in circulation are either non-commercial-only or of unstated provenance. Embedding one of those would put a licence breach inside a compliance product.
type SetReferenceIn ¶
type SetReferenceIn struct {
// Set is the set to write in, from the path.
Set string `json:"-" url:"set"`
// Entries are the overrides to write, up to 1000 per call.
Entries []ReferenceOverrideIn `json:"entries" url:"-"`
}
SetReferenceIn writes your org's overrides in one set.
There is deliberately no organisation, scope or tenant field: the store is resolved from your validated principal, so an override cannot be aimed at anyone else's world. That is a property of the shape, not a check.
type SetReferenceOut ¶
type SetReferenceOut struct {
// Set is the set written in.
Set string `json:"set"`
// Written is how many entries this call wrote.
Written int `json:"written"`
// Overrides is how many your org now holds in this set.
Overrides int `json:"overrides"`
}
SetReferenceOut is the receipt for an override write.
type Source ¶
type Source struct {
// Name is the publisher, stable across versions — it is the key freshness is
// tracked per.
Name string
// Origin is the exact URL fetched, so an auditor can take the same bytes.
Origin string
// Basis is the KIND of permission this data reaches a tenant under, from a
// closed vocabulary. Required: the zero value is not a basis, and the catalog
// gate refuses it.
Basis Grant
// Terms is the CITATION the basis points at — the licence identifier, the
// registry, or the operator publication. Required: a basis with nothing behind
// it is an assertion.
Terms string
// contains filtered or unexported fields
}
Source is one publisher of one set: where it is, on what basis we may pass it on, and how its bytes become entries.