Documentation
¶
Overview ¶
Package datacatalog is a small, dependency-free data catalog: a model for describing which entities and fields an application stores and how each field is classified (visibility, PII, secret, erasure strategy).
The catalog is plain data. It is meant to be authored (in Go or JSON), validated once, and then consumed by query guards, privacy tooling (access and erasure requests), documentation generators and management tooling. Adapters for ORMs and query guards live in their own modules; this package depends only on the standard library.
Typical use:
cat, err := datacatalog.ReadFile("catalog.json")
if err != nil { ... }
if err := cat.Validate(); err != nil { ... } // reports every problem
if cat.AllowedInQuery("account", "email", false) { ... }
Example ¶
package main
import (
"fmt"
"github.com/grokify/datacatalog"
)
func main() {
cat := &datacatalog.Catalog{
Name: "shop",
Entities: []datacatalog.Entity{{
Name: "account",
Owner: "identity",
SubjectKey: "id",
PrivacyScope: true,
Fields: []datacatalog.Field{
{Name: "id", Type: datacatalog.TypeString, Visibility: datacatalog.VisibilityPublic, Export: true},
{Name: "email", Type: datacatalog.TypeString, Visibility: datacatalog.VisibilityPublic,
PII: true, Erasure: datacatalog.ErasureClear, Export: true},
{Name: "password_hash", Type: datacatalog.TypeBytes, Visibility: datacatalog.VisibilityInternal,
Secret: true, Erasure: datacatalog.ErasureShred},
{Name: "is_staff", Type: datacatalog.TypeBool, Visibility: datacatalog.VisibilityInternal},
},
}},
}
if err := cat.Validate(); err != nil {
fmt.Println(err)
return
}
for _, name := range []string{"id", "email", "password_hash", "is_staff"} {
fmt.Printf("%-13s no PII: %-5v PII ok: %v\n", name,
cat.AllowedInQuery("account", name, false), cat.AllowedInQuery("account", name, true))
}
}
Output: id no PII: true PII ok: true email no PII: false PII ok: true password_hash no PII: false PII ok: false is_staff no PII: false PII ok: false
Index ¶
- type Audience
- type Catalog
- func (c *Catalog) AllowedInQuery(entity, field string, allowPII bool) bool
- func (c *Catalog) Clone() *Catalog
- func (c *Catalog) Encode(w io.Writer) error
- func (c *Catalog) Entity(name string) (Entity, bool)
- func (c *Catalog) Field(entity, name string) (Field, bool)
- func (c *Catalog) MarshalJSONIndent() ([]byte, error)
- func (c *Catalog) Normalize()
- func (c *Catalog) PrivacyScopeEntities() []Entity
- func (c *Catalog) RenderMarkdown() string
- func (c *Catalog) Validate() error
- func (c *Catalog) WriteFile(path string) error
- type Entity
- type Erasure
- type Field
- type Problem
- type Rule
- type Type
- type ValidationError
- type Visibility
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Catalog ¶
type Catalog struct {
Name string `json:"name" jsonschema_description:"Catalog name, typically the application or service."`
Entities []Entity `json:"entities,omitempty"`
}
Catalog is a named set of entities.
func Decode ¶
Decode reads a JSON catalog. Unknown fields are rejected so typos in classifications are not silently ignored. Decode does not validate; call Validate on the result.
func Merge ¶
Merge combines catalogs into a new one, for example one catalog per service into an organization-wide view. The merged catalog takes the name of the first catalog that has one. Nil catalogs are skipped.
An entity defined in more than one catalog must be defined identically (the duplicate is then collapsed); otherwise Merge returns an error naming every conflicting entity. The result has entities sorted by name.
func (*Catalog) AllowedInQuery ¶
AllowedInQuery is the default-deny lookup for a query guard: unknown entities and fields are not allowed.
func (*Catalog) MarshalJSONIndent ¶
MarshalJSONIndent returns the catalog as indented JSON with entities sorted by name and a trailing newline, so output is stable and diff-friendly. The receiver is not modified.
func (*Catalog) Normalize ¶
func (c *Catalog) Normalize()
Normalize sorts entities by name, in place. Field order is kept because declaration order is meaningful (it usually mirrors column order).
func (*Catalog) PrivacyScopeEntities ¶
PrivacyScopeEntities returns the entities subject to access and erasure requests, in catalog order.
func (*Catalog) RenderMarkdown ¶
RenderMarkdown renders the catalog as Markdown documentation: one section per entity (sorted by name) with a field table. The receiver is not modified and output is deterministic.
type Entity ¶
type Entity struct {
Name string `json:"name" jsonschema_description:"Entity name; unique within the catalog."`
Owner string `json:"owner,omitempty" jsonschema_description:"Team or component responsible for the entity."`
Description string `json:"description,omitempty"`
// SubjectKey names the field that identifies the data subject.
SubjectKey string `json:"subject_key,omitempty" jsonschema_description:"SubjectKey names the field that identifies the data subject."`
// PrivacyScope marks the entity as subject to access and erasure requests.
PrivacyScope bool `` /* 128-byte string literal not displayed */
// HoldApplicable marks the entity as subject to legal holds. It is an
// entity-level property: holds suspend erasure for whole rows.
HoldApplicable bool `` /* 186-byte string literal not displayed */
// Versioned marks the entity as keeping row history. It is an
// entity-level property: history rows must be erased with their subject.
Versioned bool `` /* 182-byte string literal not displayed */
// Retention is a free-text retention note.
Retention string `json:"retention,omitempty" jsonschema_description:"Retention is a free-text retention note."`
Fields []Field `json:"fields,omitempty"`
}
Entity describes one stored record type (a table, collection or document kind) and its fields.
func (Entity) QueryableFields ¶
QueryableFields returns the fields for which AllowedInQuery(allowPII) holds.
func (Entity) VisibleFields ¶
VisibleFields returns the fields visible to aud, in declaration order.
type Erasure ¶
type Erasure string
Erasure is the strategy applied to a field when its data subject is erased.
const ( // ErasureClear sets the value to its zero value or NULL. ErasureClear Erasure = "clear" // ErasureTombstone replaces the value with a fixed marker. ErasureTombstone Erasure = "tombstone" // ErasureHash replaces the value with a one-way hash. ErasureHash Erasure = "hash" // ErasureDeleteRow removes the whole row. ErasureDeleteRow Erasure = "delete_row" // ErasureShred destroys the key that protects the value (crypto-shredding). ErasureShred Erasure = "shred" // ErasureRetain keeps the value; RetainReason must say why. ErasureRetain Erasure = "retain" )
Erasure strategies.
type Field ¶
type Field struct {
Name string `json:"name" jsonschema_description:"Field (column) name; unique within the entity."`
Description string `json:"description,omitempty"`
Type Type `json:"type,omitempty" jsonschema:"enum=string,enum=number,enum=bool,enum=time,enum=json,enum=bytes"`
Visibility Visibility `` /* 136-byte string literal not displayed */
// PII marks personal data about the data subject.
PII bool `json:"pii,omitempty" jsonschema_description:"PII marks personal data about the data subject."`
// Secret marks credentials and key material; it implies internal visibility.
Secret bool `json:"secret,omitempty" jsonschema_description:"Secret marks credentials and key material; it implies internal visibility."`
// Erasure is the strategy applied when the data subject is erased.
Erasure Erasure `` /* 202-byte string literal not displayed */
// RetainReason is required when Erasure is "retain".
RetainReason string `json:"retain_reason,omitempty" jsonschema_description:"RetainReason is required when Erasure is 'retain'."`
// Export includes the field in data-subject access exports.
Export bool `json:"export,omitempty" jsonschema_description:"Export includes the field in data-subject access exports."`
}
Field describes one stored attribute of an Entity.
func (Field) AllowedInQuery ¶
AllowedInQuery reports whether a query guard may let the field appear in a user-authored query. Internal and secret fields are always blocked; PII fields are blocked unless allowPII is true.
type Problem ¶
type Problem struct {
Entity string `json:"entity,omitempty"`
Field string `json:"field,omitempty"`
Rule Rule `json:"rule"`
Message string `json:"message"`
}
Problem is a single validation finding. Entity and Field are empty when the problem is not about a specific entity or field.
type Rule ¶
type Rule string
Rule identifies a validation rule so callers can react to specific problems without parsing messages.
const ( RuleNameRequired Rule = "name_required" RuleNameUnique Rule = "name_unique" RuleVisibilityRequired Rule = "visibility_required" RuleTypeInvalid Rule = "type_invalid" RuleErasureInvalid Rule = "erasure_invalid" RuleSecretInternal Rule = "secret_internal" RuleSubjectKeyRequired Rule = "subject_key_required" RuleSubjectKeyUnknown Rule = "subject_key_unknown" RulePIIErasureRequired Rule = "pii_erasure_required" RuleRetainReasonMissing Rule = "retain_reason_required" )
Validation rules.
type Type ¶
type Type string
Type is the coarse storage type of a field. It is descriptive, not a database type: adapters map it to whatever the engine needs.
type ValidationError ¶
type ValidationError struct {
Problems []Problem
}
ValidationError carries every problem found by Validate.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
Error lists all problems, one per line.
func (*ValidationError) Has ¶
func (e *ValidationError) Has(r Rule) bool
Has reports whether any problem matches the rule.
type Visibility ¶
type Visibility string
Visibility says who may see a field. There is deliberately no default: the zero value is invalid so that every field is classified explicitly.
const ( // VisibilityPublic fields may be exposed to application code and // user-facing queries. VisibilityPublic Visibility = "public" // VisibilityInternal fields are for the platform only. VisibilityInternal Visibility = "internal" )
Field visibilities.
func (Visibility) Valid ¶
func (v Visibility) Valid() bool
Valid reports whether v is an explicit, known visibility.