Documentation
¶
Overview ¶
Package meaninglabels is the Meaning Graph's sensitivity vocabulary: labels that say how sensitive a table, column or entity field is. A label's class is the field's Perimeter protection class (backstage spec features/meaning-sensitivity). The package is engine-free: it imports no DALgo driver, and its store works over any dal.DB the edge composes.
Index ¶
- Constants
- Variables
- func AnyProtected(doc Document, source string, tables map[string][]Column) bool
- func Apply(doc Document, change Change, actor Actor, at time.Time) (Document, Event, error)
- func BareName(reference string) string
- func Candidates(reference string) []string
- func CheckLooseningTarget(doc Document, t Target, tables map[string][]string) error
- func CheckReveal(labels []ColumnLabel, revealed []string, agent bool) error
- func CheckRevision(current Document, ifRevision string) error
- func Encode(doc Document) ([]byte, error)
- func ErrorCode(err error) string
- func ExactTarget(t Target, tables map[string][]string) error
- func Key(project *record.Key) *record.Key
- func NormalizeName(name string) string
- func RawRefusal(doc Document, source string, tables map[string][]Column, agent bool) error
- func Reviewed(doc Document, source, table string) bool
- func TableMatches(labelTable, table string) bool
- func ValidateClassKind(class Class, kind Kind) error
- type Action
- type Actor
- type Change
- type Class
- type ClassPolicy
- type Column
- type ColumnLabel
- type DALgoStore
- type Dismissal
- type Document
- type EffectiveOrigin
- type Error
- type Event
- type Kind
- type Label
- type Origin
- type Plan
- type Protection
- type Rule
- type State
- type Store
- type Suggestion
- type Target
- type TargetKind
Constants ¶
const ( CodeClassUnknown = "LABEL_CLASS_UNKNOWN" CodeKindClassMismatch = "LABEL_KIND_CLASS_MISMATCH" CodeSecretNonRevealable = "LABEL_SECRET_ALWAYS_NON_REVEALABLE" CodeAgentNotAllowed = "LABEL_CHANGE_NOT_ALLOWED_FOR_AGENT" CodeRevisionConflict = "LABELS_REVISION_CONFLICT" CodeInvalidTarget = "LABEL_TARGET_INVALID" CodeInvalidDocument = "LABELS_DOCUMENT_INVALID" CodeLabelNotFound = "LABEL_NOT_FOUND" CodeReasonRequired = "LABEL_REASON_REQUIRED" CodeFieldProtected = "FIELD_PROTECTED" CodeRawRefused = "FIELD_PROTECTION_RAW_REFUSED" CodeRevealNotForAgent = "REVEAL_NOT_ALLOWED_FOR_AGENT" CodeFieldNonRevealable = "FIELD_NON_REVEALABLE" CodeUnknownAction = "LABEL_ACTION_UNKNOWN" CodeSuggestionNotPending = "LABEL_NOT_PENDING" CodeTargetAmbiguous = "LABEL_TARGET_AMBIGUOUS" )
Error codes returned on the wire.
const AskText = "" /* 129-byte string literal not displayed */
AskText is the hint attached to a masked revealable column.
const Collection = "meaningLabels"
Collection is the DALgo collection that holds label documents.
const DocumentID = "labels"
DocumentID is the ID of a project's one label document.
const Format = "datatug-labels/v1"
Format is the label document's format identifier.
const MaskedValue = "••••"
MaskedValue is how text and table output render a masked cell.
const MaxDocumentBytes = 1 << 20
MaxDocumentBytes bounds a stored label document.
const NeverText = "" /* 145-byte string literal not displayed */
NeverText is the hint attached to a masked non-revealable column.
Variables ¶
var Kinds = map[Class][]Kind{ ClassSecret: {"password", "password-hash", "api-key", "token", "private-key", "session-id", "otp-seed"}, ClassFinancial: {"card-number", "card-cvv", "bank-account", "iban", "routing-number"}, ClassPII: {"person-name", "email", "phone", "postal-address", "birth-date", "national-id", "passport-number", "ip-address", "geo-location"}, }
Kinds lists the published kinds of each protected class.
var Rules = []Rule{ rule("secret-password-hash", ClassSecret, "password-hash", `(^|_)(password|passwd|pwd|pass)_?(hash|hashed|digest|salt)($|_)|(^|_)(hashed_?password|salt)($|_)`), rule("secret-password", ClassSecret, "password", `(^|_)(password|passwd|pwd|pin|pin_?code|credentials?)($|_)`), rule("secret-api-key", ClassSecret, "api-key", `(^|_)(api_?key|apikey|access_?key|secret_?key|client_?secret|signing_?key|encryption_?key)($|_)`), rule("secret-private-key", ClassSecret, "private-key", `(^|_)private_?key($|_)`), rule("secret-otp-seed", ClassSecret, "otp-seed", `(^|_)(otp|totp|mfa)_?(seed|secret)($|_)`), rule("secret-session-id", ClassSecret, "session-id", `(^|_)session_?(id|key|token)($|_)`), rule("secret-token", ClassSecret, "token", `(^|_)(token|access_?token|refresh_?token|auth_?token|bearer|secret)($|_)`), rule("financial-card-number", ClassFinancial, "card-number", `(^|_)(card|cc|credit_?card)_?(number|num|no)($|_)|(^|_)pan($|_)`), rule("financial-card-cvv", ClassFinancial, "card-cvv", `(^|_)(cvv|cvv2|cvc|csc)($|_)`), rule("financial-iban", ClassFinancial, "iban", `(^|_)iban($|_)`), rule("financial-routing-number", ClassFinancial, "routing-number", `(^|_)(routing_?(number|no)|sort_?code|swift|bic)($|_)`), rule("financial-bank-account", ClassFinancial, "bank-account", `(^|_)(bank_?)?(account|acct)_?(number|num|no)($|_)|(^|_)bank_?account($|_)`), rule("pii-email", ClassPII, "email", `(^|_)e_?mail($|_)|(^|_)email_?address($|_)`), rule("pii-phone", ClassPII, "phone", `(^|_)(phone|phonenumber|mobile|fax|telephone|tel|cell)($|_)`), rule("pii-national-id", ClassPII, "national-id", `(^|_)(ssn|social_?security(_?number)?|national_?id|tax_?id|nin|sin|drivers?_?licen[cs]e(_?(number|no))?)($|_)`), rule("pii-passport-number", ClassPII, "passport-number", `(^|_)passport(_?(number|no))?($|_)`), rule("pii-birth-date", ClassPII, "birth-date", `(^|_)(birth_?date|date_?of_?birth|dob|birthday)($|_)`), rule("pii-person-name", ClassPII, "person-name", `(^|_)((first|last|full|middle|given|family|contact|sur|maiden|card_?holder|holder)_?name|surname|cardholder)($|_)`), rule("pii-ip-address", ClassPII, "ip-address", `(^|_)(ip|ip_?address|ipv4|ipv6)($|_)`), rule("pii-postal-address", ClassPII, "postal-address", `(^|_)(address\d?|street|postal_?code|zip|zip_?code|post_?code)($|_)`), rule("pii-geo-location", ClassPII, "geo-location", `(^|_)(latitude|longitude|lat|lng|lon|geo_?location)($|_)`), }
Rules is the deterministic suggestion rule table, first match wins. It reads names and declared types only, never values.
Functions ¶
func AnyProtected ¶
AnyProtected reports whether any column of the source has a protected effective label (owner label, proposal or read-time suggestion), or any protected label is stored for the source. An agent's raw read of such a source is refused. tables maps reported table names to their columns.
func Apply ¶
Apply applies one change to a copy of doc and returns the new document with a fresh revision and the audit event. doc is not modified.
func BareName ¶
BareName is the most likely column name a reference stands for: the last segment, unquoted and unescaped ("a""b" is a"b, [e.mail] is e.mail).
func Candidates ¶ added in v0.141.1
Candidates lists every column name a reference could stand for, most likely first: the unescaped quoted last segment, the last dot segment with quotes trimmed, and the raw last segment.
func CheckLooseningTarget ¶
CheckLooseningTarget is the edge's check before it saves a change whose event loosens: the target must be an entry already stored with exactly that target, or exactly one table (and column) the source reports, schema-qualified and case-exact. tables maps reported qualified table names to their column names.
func CheckReveal ¶
func CheckReveal(labels []ColumnLabel, revealed []string, agent bool) error
CheckReveal refuses a reveal request for an agent, or one that names a non-revealable column.
func CheckRevision ¶
CheckRevision refuses a save based on a stale revision. A missing document has revision "".
func ExactTarget ¶
ExactTarget checks that t names exactly one table the source reports (schema-qualified, case-exact), and for a column target one of its columns exactly. tables maps reported qualified table names to column names.
func NormalizeName ¶
NormalizeName turns an identifier into lower-case words joined by "_".
func RawRefusal ¶
RawRefusal returns FIELD_PROTECTION_RAW_REFUSED for an agent on a source with protected columns, and nil otherwise. An empty tables map refuses too: a boundary that could not enumerate the source's columns cannot show that the source is unlabelled.
func Reviewed ¶
Reviewed reports whether an owner labelled the object itself (a table-level label, none included), matching exactly. An unreviewed view or other non-table object is masked entirely, for every subject.
func TableMatches ¶
TableMatches reports whether a label's table names the table being read, for protecting entries. Names compare ignoring case, segment by segment from the end, over the shorter of the two: "customers" covers "public.customers", and "dbo.Customers" covers "Customers" and "Northwind.dbo.Customers". These rules only ever widen what is masked.
func ValidateClassKind ¶
ValidateClassKind checks that class is known and kind, if set, belongs to it.
Types ¶
type Actor ¶
type Actor struct {
ID string `json:"id"`
Agent bool `json:"agent,omitempty"`
AgentUser string `json:"agentUser,omitempty"`
}
Actor is who makes a change. An agent may only propose (tighten).
type Change ¶
type Change struct {
Action Action `json:"action"`
Target Target `json:"target"`
Class Class `json:"class,omitempty"`
Kind Kind `json:"kind,omitempty"`
NonRevealable bool `json:"nonRevealable,omitempty"`
Reason string `json:"reason,omitempty"`
}
Change is one requested label change. Targets name the exact names the source reports; the edge checks loosening targets with ExactTarget first. For confirm and dismiss of a read-time suggestion (which is never stored) the caller passes the suggestion's Class and Kind.
type Class ¶
type Class string
Class is a sensitivity class; it is also the Perimeter protection class.
const ( // ClassSecret is security-critical data: it grants access or proves identity. ClassSecret Class = "secret" // ClassFinancial is protected financial data such as card numbers. ClassFinancial Class = "financial" // ClassPII is personal or private data about a person. ClassPII Class = "pii" // ClassNone records an owner's "reviewed and not sensitive" decision. ClassNone Class = "none" )
type ClassPolicy ¶
type ClassPolicy struct {
Source string `json:"source"`
Class Class `json:"class"`
NonRevealable bool `json:"nonRevealable"`
}
ClassPolicy marks a whole class non-revealable on one source.
type ColumnLabel ¶
type ColumnLabel struct {
Column string `json:"column"`
Class Class `json:"class,omitempty"`
Kind Kind `json:"kind,omitempty"`
Origin EffectiveOrigin `json:"origin,omitempty"`
State State `json:"state,omitempty"`
NonRevealable bool `json:"nonRevealable,omitempty"`
Rule string `json:"rule,omitempty"`
}
ColumnLabel is a column's effective label. Class is "" when no label applies.
func Effective ¶
func Effective(doc Document, source, table string, columns []Column) []ColumnLabel
Effective computes the effective label of each column of one table. An owner label on the column decides alone (none included). Otherwise the result is the stricter of the table's owner label (protected classes only), pending proposals on the column or table, and the read-time suggestion unless an owner dismissed it on that column. Class policies of the source apply last.
func EffectiveObject ¶
func EffectiveObject(doc Document, source, table string, view bool, columns []Column) []ColumnLabel
EffectiveObject is Effective for an object of any kind: a view or other non-table object (view true, including an object whose kind is unknown) that no owner reviewed has every column masked. Class policies apply.
func Tighten ¶
func Tighten(authoritative, extra []ColumnLabel) []ColumnLabel
Tighten merges a second set of effective labels for the same columns into authoritative ones, only ever making them stricter: the control plane's labels are authoritative and a project file can add, never remove.
func (ColumnLabel) Protected ¶
func (c ColumnLabel) Protected() bool
Protected reports whether the column is masked by default.
func (ColumnLabel) Revealable ¶
func (c ColumnLabel) Revealable() bool
Revealable reports whether an elevated approval may reveal the column. secret is never revealable, whatever the flag says.
type DALgoStore ¶
DALgoStore keeps the document in any dal.DB; the edge composes the driver.
type Dismissal ¶
type Dismissal struct {
Target Target `json:"target"`
Class Class `json:"class"`
Kind Kind `json:"kind,omitempty"`
By string `json:"by,omitempty"`
At time.Time `json:"at"`
Reason string `json:"reason,omitempty"`
}
Dismissal records an owner's dismissal of a suggested or proposed label, so the same suggestion is not made again.
type Document ¶
type Document struct {
Format string `json:"format"`
Revision string `json:"revision,omitempty"`
Labels []Label `json:"labels"`
Dismissed []Dismissal `json:"dismissed,omitempty"`
ClassPolicies []ClassPolicy `json:"classPolicies,omitempty"`
}
Document is a project's label document.
func NewDocument ¶
func NewDocument() Document
NewDocument returns an empty document. An empty document has revision "", the same as a project that has no document yet.
func (Document) ComputeRevision ¶
ComputeRevision is the sha256 of the document's content without its revision, or "" for a document with no content.
type EffectiveOrigin ¶
type EffectiveOrigin string
EffectiveOrigin says what produced an effective label.
const ( FromColumn EffectiveOrigin = "column" FromTable EffectiveOrigin = "table" FromSuggested EffectiveOrigin = "suggested" FromProposed EffectiveOrigin = "proposed" // FromUnreviewedObject masks every column of a view or other non-table // object no owner has labelled, for agents. FromUnreviewedObject EffectiveOrigin = "unreviewed-object" )
type Event ¶
type Event struct {
Type string `json:"type"`
Actor Actor `json:"actor"`
Target Target `json:"target"`
Before *Label `json:"before,omitempty"`
After *Label `json:"after,omitempty"`
Reason string `json:"reason,omitempty"`
At time.Time `json:"at"`
// Loosens marks a change that removes or weakens protection.
Loosens bool `json:"loosens,omitempty"`
}
Event is the audit record of one applied change.
type Label ¶
type Label struct {
Target Target `json:"target"`
Class Class `json:"class"`
Kind Kind `json:"kind,omitempty"`
NonRevealable bool `json:"nonRevealable,omitempty"`
State State `json:"state"`
Origin Origin `json:"origin"`
By string `json:"by,omitempty"`
At time.Time `json:"at"`
Reason string `json:"reason,omitempty"`
}
Label is one stored label.
type Plan ¶
type Plan struct {
Masked map[string]ColumnLabel
}
Plan says which columns of one table the boundary must not fetch.
func NewPlan ¶
func NewPlan(labels []ColumnLabel, revealed []string) Plan
NewPlan returns the masking plan of one table: every protected column is masked unless revealed names it and it is revealable. Revealed holds column names (any case); non-revealable columns stay masked whatever it says.
func (Plan) CheckReferenced ¶
CheckReferenced refuses a query whose filter, sort, grouping, alias or expression names a masked column: a predicate on a masked value discloses it.
func (Plan) IsMasked ¶
func (p Plan) IsMasked(reference string) (ColumnLabel, bool)
IsMasked reports whether a column is masked. The reference is compared ignoring case, under every spelling it could stand for (see Candidates), so the gate fails closed on qualification, quoting and escapes. One entry is one identifier reference, not an expression.
func (Plan) Protection ¶
func (p Plan) Protection(column string) *Protection
Protection returns the wire protection of a masked column.
type Protection ¶
type Protection struct {
Class Class `json:"class"`
Kind Kind `json:"kind,omitempty"`
State string `json:"state"`
Revealable bool `json:"revealable"`
Origin string `json:"origin,omitempty"`
// Ask tells an agent how to get the value.
Ask string `json:"ask,omitempty"`
}
Protection is the wire description of a masked column.
type Rule ¶
Rule is one published suggestion rule. Pattern runs against a normalized column name: lower case words joined by "_" ("CardNumber" -> "card_number").
func SuggestColumn ¶
SuggestColumn returns the first matching rule for one column, if any.
type Store ¶
type Store interface {
Load(ctx context.Context) (Document, error)
Save(ctx context.Context, doc Document, ifRevision string) error
}
Store loads and saves a project's label document. Save is compare-and-set: ifRevision must be the revision the change was based on ("" for a project with no document yet).
type Suggestion ¶
type Suggestion struct {
Target Target `json:"target"`
Class Class `json:"class"`
Kind Kind `json:"kind"`
Rule string `json:"rule"`
}
Suggestion is a rule's suggestion for one column.
func Suggest ¶
func Suggest(source, table string, columns []Column) []Suggestion
Suggest runs the rule table over a table's columns.
type Target ¶
type Target struct {
Source string `json:"source"`
Table string `json:"table"`
Column string `json:"column,omitempty"`
}
Target is what a label attaches to: a column {source, table, column} or a table {source, table}.
func (Target) Kind ¶
func (t Target) Kind() TargetKind
Kind returns the target's shape, or "" when it is not a valid shape.
type TargetKind ¶
type TargetKind string
TargetKind names a target's shape.
const ( TargetColumn TargetKind = "column" TargetTable TargetKind = "table" )