Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
bf395d9
Add Privacy Guard v0
johnnygreco Jul 22, 2026
3b36f68
Refine Privacy Guard structure and examples
johnnygreco Jul 22, 2026
cef0e9b
Add configurable Privacy Guard regex scanner
johnnygreco Jul 22, 2026
61330d8
Harden regex scanner configuration loading
johnnygreco Jul 22, 2026
fe8e84a
Improve Privacy Guard operator guidance
johnnygreco Jul 22, 2026
c1a9a1d
Clarify regex scanner CLI configuration
johnnygreco Jul 22, 2026
e8d0abf
Separate scanner-specific CLI options
johnnygreco Jul 22, 2026
b4a4a38
Address scanner CLI review feedback
johnnygreco Jul 22, 2026
d7e2510
Adopt Typer for Privacy Guard CLI
johnnygreco Jul 22, 2026
9e3d14a
Make built-in scanner help self-contained
johnnygreco Jul 22, 2026
20f69ee
Rename built-in scanner config option
johnnygreco Jul 22, 2026
cfc086a
Harden Privacy Guard CLI bind failures
johnnygreco Jul 22, 2026
92dbf86
Add end-to-end regex scanner walkthrough
johnnygreco Jul 23, 2026
e5233cb
Standardize Privacy Guard example setup
johnnygreco Jul 23, 2026
fd54837
Simplify example gateway setup
johnnygreco Jul 23, 2026
f91bf49
Use OpenShell host alias in examples
johnnygreco Jul 23, 2026
fe422d9
Log Privacy Guard CLI startup
johnnygreco Jul 23, 2026
05d66fe
Fix example middleware endpoint
johnnygreco Jul 23, 2026
1a295e8
Document local gateway registration
johnnygreco Jul 23, 2026
bd2e32a
Make example middleware reachable from sandboxes
johnnygreco Jul 23, 2026
d008566
Disable telemetry in regex walkthrough
johnnygreco Jul 23, 2026
786c1ff
Add request pipeline debug logging
johnnygreco Jul 23, 2026
a66f2b2
Merge remote-tracking branch 'origin/main' into johnny/feat/privacy-g…
johnnygreco Jul 23, 2026
d9482b2
Polish Privacy Guard documentation and workflows
johnnygreco Jul 23, 2026
82898da
Fix Privacy Guard CI runner paths
johnnygreco Jul 23, 2026
be6af12
Make Privacy Guard CLI tests ANSI-safe
johnnygreco Jul 23, 2026
8a71697
Merge remote-tracking branch 'origin/main' into johnny/feat/privacy-g…
johnnygreco Jul 23, 2026
328fedd
Merge remote-tracking branch 'origin/main' into johnny/feat/privacy-g…
johnnygreco Jul 23, 2026
5e4924f
Update Privacy Guard middleware manifest
johnnygreco Jul 24, 2026
ce3a801
Refactor Privacy Guard around entity processing engines
johnnygreco Jul 24, 2026
e125079
Refresh Privacy Guard guidance and examples
johnnygreco Jul 24, 2026
1e406bd
Rewrite Privacy Guard architecture documentation
johnnygreco Jul 24, 2026
389e1a0
Model engine strategies as independent support
johnnygreco Jul 24, 2026
8df3bce
Make custom entity processing engines first-class
johnnygreco Jul 24, 2026
5123ba9
Centralize Privacy Guard errors
johnnygreco Jul 24, 2026
3cada67
Complete the custom engine deployment example
johnnygreco Jul 24, 2026
ebf7163
Support file-backed regex pattern catalogs
johnnygreco Jul 24, 2026
dad5316
Harden regex catalog preparation
johnnygreco Jul 25, 2026
1dcc465
Bound custom engine example results
johnnygreco Jul 25, 2026
2221fa6
Separate Privacy Guard application boundaries
johnnygreco Jul 25, 2026
633020d
Simplify custom engine authoring
johnnygreco Jul 25, 2026
a516e63
Allow custom registries to include built-ins
johnnygreco Jul 25, 2026
03f8dac
Clarify Privacy Guard model types
johnnygreco Jul 25, 2026
907632b
Reduce Privacy Guard abstraction overhead
johnnygreco Jul 25, 2026
a18291c
Standardize Privacy Guard error names
johnnygreco Jul 25, 2026
f7d28bd
Move engine registry into engine package
johnnygreco Jul 25, 2026
ebfbe1f
Clarify engine result enforcement boundary
johnnygreco Jul 25, 2026
8ca3e75
Simplify lazy detection bounding
johnnygreco Jul 25, 2026
68a842b
Clarify overlapping regex matches
johnnygreco Jul 26, 2026
d314ba8
Add timeout translation context manager
johnnygreco Jul 26, 2026
b84153c
Rename timeout enforcement context
johnnygreco Jul 26, 2026
4f8815a
Make timeout failures actionable
johnnygreco Jul 26, 2026
b278e8c
Make Privacy Guard errors actionable
johnnygreco Jul 26, 2026
9035335
Clarify Privacy Guard recovery guidance
johnnygreco Jul 26, 2026
bd5d399
Correlate Privacy Guard limit diagnostics
johnnygreco Jul 26, 2026
5cd3300
Simplify Privacy Guard error and command surfaces
johnnygreco Jul 26, 2026
ce31a2c
Clarify Privacy Guard limit and startup diagnostics
johnnygreco Jul 26, 2026
b4a4e46
Unify Privacy Guard logging configuration
johnnygreco Jul 26, 2026
6cff82d
Route Privacy Guard loggers through shared module
johnnygreco Jul 26, 2026
3a10551
Add clear colored logging defaults
johnnygreco Jul 26, 2026
5f09d5d
Make logging color policy explicit
johnnygreco Jul 26, 2026
9eecfe6
test(privacy-guard): cover loopback gRPC flow (PG-014)
johnnygreco Jul 27, 2026
4cc4d7e
fix(privacy-guard): accelerate scalar validation (PG-001)
johnnygreco Jul 27, 2026
aa3d455
fix(privacy-guard): bound and normalize transport config (PG-002 PG-003)
johnnygreco Jul 27, 2026
d69d30b
fix(privacy-guard): validate bound listen ports (PG-004)
johnnygreco Jul 27, 2026
e0ea80f
fix(privacy-guard): secure diagnostic identifiers (PG-005)
johnnygreco Jul 27, 2026
a118097
fix(privacy-guard): enforce engine lifecycle hooks (PG-007)
johnnygreco Jul 27, 2026
bb64fa3
fix(privacy-guard): classify zero-width regex config (PG-006)
johnnygreco Jul 27, 2026
30d8572
fix(privacy-guard): single-flight processor builds (PG-008)
johnnygreco Jul 27, 2026
f2bed78
fix(privacy-guard): verify release artifacts (PG-010 PG-011 PG-013)
johnnygreco Jul 27, 2026
12bfe1a
fix(privacy-guard): bound prepared-state caches (PG-009)
johnnygreco Jul 27, 2026
4023108
fix(privacy-guard): audit fixed test toolchain (PG-012)
johnnygreco Jul 27, 2026
a59b06d
fix(privacy-guard): close panel error gaps (PG-002 PG-004 PG-005)
johnnygreco Jul 27, 2026
24cca6d
fix(privacy-guard): resolve panel findings (PG-005 PG-006 PG-009)
johnnygreco Jul 27, 2026
b620d77
fix(privacy-guard): preserve multi-catalog cache budget (PG-009)
johnnygreco Jul 27, 2026
a3d864c
fix(privacy-guard): seed artifact environment (PG-010 PG-012)
johnnygreco Jul 27, 2026
451c859
refactor(privacy-guard): simplify cache ownership (PG-009)
johnnygreco Jul 27, 2026
4bbfb08
refactor(privacy-guard): address review feedback
johnnygreco Jul 27, 2026
96683e1
refactor(privacy-guard): use one active policy (PG-008 PG-009)
johnnygreco Jul 27, 2026
aa0103c
fix(privacy-guard): restore release artifact gate (PG-010 PG-011 PG-013)
johnnygreco Jul 27, 2026
00bc7fa
chore(privacy-guard): keep release checks streamlined
johnnygreco Jul 27, 2026
8b6e89d
refactor(privacy-guard): call regex entries rules
johnnygreco Jul 27, 2026
a9ca19c
feat(privacy-guard): configure OpenShell gateway
johnnygreco Jul 27, 2026
a05914b
refactor(privacy-guard): simplify regex catalog loading
johnnygreco Jul 27, 2026
127c48a
ci(docs): require manual production publish
johnnygreco Jul 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
- name: Upload production documentation
if: >-
github.ref == 'refs/heads/main' &&
(github.event_name == 'push' || github.event_name == 'workflow_dispatch')
github.event_name == 'workflow_dispatch'
uses: actions/upload-artifact@v7
with:
name: production-docs-${{ github.run_id }}
Expand All @@ -71,7 +71,7 @@ jobs:
name: Deploy documentation
if: >-
github.ref == 'refs/heads/main' &&
(github.event_name == 'push' || github.event_name == 'workflow_dispatch')
github.event_name == 'workflow_dispatch'
needs: validate
runs-on: ubuntu-latest
permissions:
Expand Down
51 changes: 51 additions & 0 deletions .github/workflows/privacy-guard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Privacy Guard

"on":
pull_request:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

concurrency:
group: privacy-guard-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
check:
name: Check Privacy Guard (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version:
- "3.11"
- "3.14"
defaults:
run:
working-directory: projects/privacy-guard
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false

- name: Set up uv and Python
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
version: "0.11.31"
python-version: ${{ matrix.python-version }}

- name: Configure isolated uv paths
run: |
echo "UV_CACHE_DIR=$RUNNER_TEMP/privacy-guard-uv-cache" >> "$GITHUB_ENV"
echo "UV_PROJECT_ENVIRONMENT=$RUNNER_TEMP/privacy-guard-venv" >> "$GITHUB_ENV"

- name: Install locked dependencies
run: uv sync --frozen

- name: Run project checks
run: make check
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ read `docs/development/index.md`.
## Repository rules

- Make the smallest change that satisfies the task and preserve unrelated work.
- Prefer explicit, clear names and language over concise but ambiguous
alternatives. Value concision when it does not reduce clarity.
- Use `uv` for Python dependency management, environments, locking, builds, and
command execution unless a project explicitly documents an exception. Treat
`pyproject.toml` and the committed `uv.lock` as the dependency sources of truth.
Expand Down
15 changes: 9 additions & 6 deletions docs/development/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,12 @@ Dependabot pull requests validate with read-only credentials but do not publish
previews on the production documentation origin.

The `gh-pages` branch stores the composite production site and active previews;
GitHub Pages remains configured with **GitHub Actions** as its publishing source.
Pushes and manual workflow runs from `main` update the production site while
preserving active previews, then deploy the complete branch through the official
Pages artifact workflow. The first production deployment creates `gh-pages`
automatically. To roll back to a revision before preview support, leave the Pages
source set to **GitHub Actions** and rerun the restored documentation workflow.
GitHub Pages remains configured with **GitHub Actions** as its publishing
source. Pushes to `main` validate documentation without publishing it. When the
current documentation is ready for production, manually run the **Docs**
workflow from `main`; that run updates the production site while preserving
active previews, then deploys the complete branch through the official Pages
artifact workflow. The first production deployment creates `gh-pages`
automatically. To roll back to a revision before preview support, leave the
Pages source set to **GitHub Actions** and rerun the restored documentation
workflow.
8 changes: 6 additions & 2 deletions docs/documentation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,9 @@ agent_markdown: true

# Documentation

As Dev Notes introduce reusable software, this section will collect the technical
documentation and references needed to install, use, and reproduce that work.
Technical documentation and references for installing, using, and extending
OpenShell Research projects.

- [Privacy Guard architecture](privacy-guard/architecture/index.md): component
boundaries, request flow, extension interfaces, concurrency, failures, and
limits
149 changes: 149 additions & 0 deletions docs/documentation/privacy-guard/architecture/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
---
title: Configuration and text boundary
description: Runtime configuration ownership and the single-text processing contract.
agent_markdown: true
---

# Configuration and text boundary

Privacy Guard processes the complete request body as one text string. Its
runtime configuration is supplied by OpenShell for each evaluation and
normalized into strict structured models before processing.

## Bytes and text

The service owns the transport boundary:

- it validates the advertised 4 MiB request-body limit
- it allows an empty body without invoking an engine
- it decodes each non-empty body as strict UTF-8
- it passes exactly one `str` to `RequestProcessor`
- detect and block return no body mutation
- replace UTF-8 encodes the final processed text

Because detect and block return no mutation, OpenShell retains the exact
original bytes. Replace returns the final text even when it happens to equal
the input.

Headers and media types do not change this behavior. Privacy Guard does not
parse JSON, select nested values, create document regions, or reconstruct
structured payloads.

## Policy configuration

The OpenShell policy owns:

- ordered entity-processing stages
- each stage's exact engine configuration
- entity definitions and detection settings
- engine-specific replacement recipes
- the final detect, block, or replace action

For example:

```yaml
entity_processing:
stages:
- name: identifiers
config:
engine: regex
pattern_catalog:
entities:
- name: customer-id
rules:
- name: prefixed-eight-digit-id
pattern: '\bCUST-[0-9]{8}\b'
confidence: high
replacement:
strategy: template
template: "[{entity}]"
on_detection:
action: replace
```

`config.engine` is the Pydantic discriminator. `EngineRegistry.finalize()`
builds the complete policy model from the exact config type registered for each
engine. Engine-specific fields therefore validate and serialize without a
generic mapping layer.

Deployment startup owns operational resources rather than privacy behavior:
installed engine implementations, approved model profiles, clients, endpoints,
credentials, and data-egress constraints.

## Regex catalogs

`RegexEngineConfig.pattern_catalog` accepts either a structured
`RegexPatternCatalog` or a relative `.yaml` or `.yml` path:

```yaml
pattern_catalog: patterns.yaml
```

Paths resolve beneath Privacy Guard's working directory. Absolute paths,
traversal, and symlinks are rejected. Catalog files must be bounded UTF-8 YAML
without aliases, duplicate keys, or unsafe tags.

File-backed and inline inputs normalize to the same `RegexPatternCatalog`.
The complete validated configuration contains the structured catalog rather
than its source path. File-backed catalogs are read and validated on each policy
validation. The normalized immutable catalog keys a bounded compiled-rule
cache, so equivalent rules do not need to be recompiled. A content change
produces a different validated configuration and causes the next evaluation to
prepare an active-policy replacement.

Privacy Guard maintains the catalog schema and safety limits but does not ship
an authoritative pattern set. Repository catalogs are examples to copy and
adapt, not presets or runtime defaults.

`ValidateConfig` proves that each Regex pattern has valid syntax and rejects
patterns that immediately match empty input. It cannot prove that every
context-dependent branch consumes text. If a boundary, lookaround, or
alternation produces a zero-width match only when triggering request text is
observed, evaluation rejects the policy as `config_invalid` rather than treating
the result as an internal engine failure. Lookarounds and boundaries remain
valid when the complete match consumes text.

## Current transport constraint

The copied OpenShell protocol carries policy configuration in a
per-evaluation `google.protobuf.Struct` limited to 64 KiB. An inline catalog is
bounded by that transport. A file-backed configuration carries only its bounded
relative path through the protocol and loads the deployment-mounted catalog in
the middleware process.

The service rejects an encoded configuration above that limit before protobuf
conversion or policy validation. A policy may contain at most ten ordered
entity-processing stages. The service validates the complete bounded
configuration and compares it with the single active policy. Equal validated
configurations reuse the active processor; a different valid configuration pays
full engine and processor preparation before atomic replacement. Reuse avoids
repeated engine initialization but does not increase either limit.

`Struct` carries every number as a double. At this transport boundary only,
Privacy Guard converts finite integral values in the safe integer range
`-(2^53 - 1)` through `2^53 - 1` to Python integers before strict policy
validation. Non-integral and out-of-range values remain floats, so integer
fields reject them. Direct Python registry validation remains strict and does
not perform this transport normalization. Custom-engine integer settings must
therefore remain within the safe range when supplied through OpenShell policy.

A future self-contained transport for larger expanded catalogs requires an
upstream OpenShell contract for preparing configuration and referring to it
during evaluation. Privacy Guard must not create a private protocol fork.

## Policy identity

Privacy Guard compares the complete immutable validated configuration,
including every concrete engine field, nested replacement variant, and expanded
Regex catalog. Equal configurations reuse the active processor. A different
configuration is an update candidate and replaces the active policy only after
complete preparation succeeds.

The current protocol carries neither an explicit update operation nor a policy
version. Privacy Guard therefore cannot distinguish an intentional user update
from any other changed per-evaluation configuration. OpenShell must send one
consistent policy stream to a process; interleaved old and new configurations
can repeatedly replace one another. A future protocol can make preparation and
activation explicit and let evaluations refer to a versioned policy.

[Back to the architecture overview](index.md)
Loading
Loading