mask

package
v1.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 12, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package mask anonymizes a real data export: it replaces personal data with synthetic values while preserving the FORMAT and the referential structure of the original, so the result still exercises the same code paths.

This is the GDPR path — take a production dump, hand back something safe to share with developers. Synth reads and writes files only; it never connects to a database, so the dump you feed it is one you exported yourself.

Guarantees:

  • Consistency: the same input value always maps to the same replacement (within one run), so joins and foreign keys still line up.
  • Format preservation: an email stays an email, a card stays Luhn-valid at the same length, digits stay digits, letter case is kept.
  • Irreversibility: replacements are drawn from a keyed hash of the input, not an encoding of it, so the original cannot be recovered from output.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Masker

type Masker struct {
	// contains filtered or unexported fields
}

Masker rewrites values according to its rules.

func New

func New(key string, localeName string) *Masker

New returns a Masker. The key makes replacements deterministic across runs for the same input — use the same key when masking related dumps so foreign keys still match; use a fresh key to make runs unlinkable.

func (*Masker) CSV

func (m *Masker) CSV(r io.Reader, w io.Writer) (*Report, error)

CSV masks a CSV stream whose first row is a header. File is the same thing for two paths; callers that must not touch the filesystem — the MCP server is one — use this, and File delegates to it so the two cannot drift apart.

func (*Masker) File

func (m *Masker) File(in, out string) (*Report, error)

File masks a CSV or JSONL export and writes the anonymized result. The format is chosen by the input extension.

func (*Masker) JSONL

func (m *Masker) JSONL(r io.Reader, w io.Writer) (*Report, error)

JSONL masks a stream of one JSON object per line.

func (*Masker) Rule

func (m *Masker) Rule(r Rule)

Rule registers how a column is handled.

func (*Masker) Value

func (m *Masker) Value(column, value string) string

Value masks one cell of a column.

type Report

type Report struct {
	Rows      int
	Columns   []string
	Masked    map[string]int // column -> values replaced
	Untouched []string
}

Report summarizes what a masking run changed, so you can prove which columns were anonymized before sharing a dump.

type Rule

type Rule struct {
	Column   string
	Strategy Strategy
	// Kind is what Fake should generate. When empty it is inferred from the
	// column name and the observed value's format.
	Kind schema.Kind
	// Epsilon is the per-column privacy budget for the DP strategy: smaller
	// means more noise. Sensitivity is how much one record can move the value
	// (for a released numeric column, its plausible range). Both are required
	// for DP; the noise scale is Sensitivity/Epsilon.
	Epsilon, Sensitivity float64
}

Rule binds a column to a strategy (and, for Fake, to a kind).

type Strategy

type Strategy string

Strategy decides how a column's values are replaced.

const (
	// Keep leaves the column untouched (non-personal data).
	Keep Strategy = "keep"
	// Fake replaces values with synthetic ones of the same kind, consistently.
	Fake Strategy = "fake"
	// Redact replaces every character with a fixed mask, keeping the shape.
	Redact Strategy = "redact"
	// Drop blanks the column entirely.
	Drop Strategy = "drop"
	// DP adds Laplace noise to a numeric value, calibrated to an epsilon
	// budget — the Laplace mechanism of differential privacy. It bounds how
	// much any single record shows through the released number.
	DP Strategy = "dp"
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL