spec-kitty / spec-kitty/spec-kitty
Define the shared PII / egress-redaction contract (canonical taxonomy + policy + conformance fixtures)
- Dominant language
- Python
- Stars
- 1.6k
- Forks
- 165
- Avg merge
- 14h 52m
- Merged PRs (30d)
- 303
Description
# Define the shared PII / egress-redaction contract (canonical taxonomy + policy + conformance fixtures)
Child of the egress-controls epic #2997. The epic depends on a **single source of truth** for *what* counts as personal data and *how* it is redacted, that every diagnostic tool — the CLI sanitizer, the analyzer, and an eventual support agent — conforms to. Today each tool defines this independently, so redaction can silently diverge between tools, and divergence is itself a leak. This issue defines that contract; the per-tool implementations are separate children (#2988 for build-lifecycle, `Priivacy-ai/spec-kitty-analyzer#49` for the analyzer).
## Current state (grounded in code)
- **CLI sanitizer** — `src/specify_cli/events/sanitizer.py` already labels a *"PII field registry"* `_PII_FIELDS` = `machine_name`, `hostname`, `workspace_path`, `developer_name`, `developer_email`. Redaction action = **drop the field** (recursive key removal). Scoped today to git-committed log writes.
- **Analyzer scrubber** — `internal/analyzer/scrubber.go` `Scrub()` regex-redacts **secret patterns** (API keys, tokens, private keys, DB URLs, cookies) + email, on **raw text**. It does **not** cover the named PII taxonomy.
- **Personal data outside `_PII_FIELDS`:**
- `TokenUsageRecorded` (`sync/emitter.py`) — `input_tokens`/`output_tokens`/`total_tokens`/`estimated_cost_usd`/`model` tied to an `actor` payload → per-developer productivity & cost.
- `recent_commits` (BuildHeartbeat) — commit subjects; #2988 already flags this for a keep/drop decision.
## The crux: two different redaction *models* must be reconciled
The CLI sanitizer drops **named fields** in **structured events**. The analyzer sees PII as **values in free log text** (a `workspace_path` is a string inside a line, not a keyed field it can drop). A field-name taxonomy cannot be enforced value-side without either value-pattern redaction for each category, or structured ingestion. The contract has to bridge this — it is the central design question, not an afterthought.
## Deliverable (what the contract defines)
1. **Canonical taxonomy** — a single source-of-truth registry of personal-data fields/categories (identity: name/email; machine: hostname/machine_name; location: workspace_path; activity: recent_commits; productivity/cost: token usage + actor), superseding the scattered `_PII_FIELDS` and ad-hoc handling.
2. **Redaction action per category** — drop / mask / hash / pseudonymize — and the default posture (**redact-by-default at egress**; full fidelity locally).
3. **Cross-language consumability** — a machine-readable registry both Python (sanitizer) and Go (analyzer) load or generate from, so the set cannot drift between tools. Reuse across the Go/Python boundary means a shared **contract + fixtures**, not copied code.
4. **Conformance primitive** — generalize #2988's *"the emitted envelope contains no member of `_PII_FIELDS`"* into a shared conformance test each egress boundary runs against the registry.
## Open questions (for whoever picks this up — flag, don't pre-solve)
1. **Model bridge:** how does a value-based tool (analyzer, on free text) enforce a field-name taxonomy — per-category value patterns, structured ingestion, or both?
2. **Scope of productivity/cost data:** is per-developer token/cost (and `actor`) hard PII, or "customer-permitted additional" (epic tier 2)?
3. **`recent_commits`:** drop, or justify as non-personal — coordinate with #2988's decision.
4. **Registry home:** the shared `spec_kitty_events` package (already a published dependency of the CLI and telescope), or a new shared schema artifact?
5. **Action choice:** drop (current) vs mask/hash (preserves shape/correlation for diagnostics without exposing the value)?
## Out of scope
- Policy/legal — what's *required* to egress, controller, retention, purpose limitation — owned by leadership (per #2997).
- The per-tool implementations — #2988 (CLI build-lifecycle), `Priivacy-ai/spec-kitty-analyzer#49` (analyzer). This issue gives them the shared target to conform to.
*Filed with AI assistance (Claude Code); reviewed and approved by Kent Gale (kentonium3) before filing.*
Contributor guide
Research direction
Start by reading src/specify_cli/events/sanitizer.py and internal/analyzer/scrubber.go, then review #2997 and the related decisions in #2988. Define the shared taxonomy, per-category redaction actions, cross-language registry, and conformance fixtures without implementing either tool-specific child. Done means both tools have a common target and can test egress output against it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, python
- Domain
- security, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100