TraceCanary detects privacy regressions in OTLP/HTTP JSON trace exports using synthetic canaries and explicit, version-pinned contracts.
It is a deterministic offline checker for resource attributes, span attributes, and span-event attributes. It searches for exact synthetic canary values, blocks forbidden telemetry attribute keys and JSON path prefixes, and verifies operational fields that must remain after filtering.
TraceCanary uses only the Python standard library at runtime. It has no network client, credentials, telemetry, account requirement, or production-data fixture.
Supported in v0.1.1:
- OTLP/HTTP JSON traces with
resourceSpans. - Exact synthetic-canary detection anywhere in a supported payload.
- Forbidden attribute keys, key prefixes, and wildcard JSON-pointer path prefixes.
- Required fields at resource, span, and event scope.
- Baseline-to-candidate retained-field count comparison.
- Stable JSON and human-readable reports.
- Bounded directory checks with deterministic JSON, SARIF, and JUnit output.
Not supported in v0.1.1:
- Protobuf, logs, metrics, collector execution, or redaction.
- Generic secret or PII discovery.
- Real production traces or a privacy-law compliance determination.
- A claim that no sensitive data can leak.
Install a local checkout before starting the desktop interface:
python -m pip install .
Then run:
tracecanary-gui
If the installed launcher is unavailable, use the module fallback:
python -m tracecanary.gui
From a fresh checkout without installation, first expose src to Python, then use the fallback:
$env:PYTHONPATH = "src"
python -m tracecanary.guiOn POSIX shells, use PYTHONPATH=src python -m tracecanary.gui. From a checkout on Windows, double-click TraceCanary.pyw instead. The first screen provides file selectors for a contract, input, baseline, and candidate; Validate, Check, and Diff actions; an explicit pass, regression, or unresolved status; human and JSON report views; and a Save Report action. Reports are written only through Save Report after the user chooses a file path; synthetic files are written only through the explicit starter-files action after the user chooses an empty directory.
Run Built-in Demo performs a safe synthetic check entirely in memory, so it works after installation without repository fixture files. Create Synthetic Starter Files requires a directory selected by the user, writes only the existing fictional fixture bundle to an empty directory, and then prepares the selectors for a safe baseline and a retention-regression candidate. The GUI calls TraceCanary library functions directly and never launches a subprocess.
For a headless installation check that does not create a window:
tracecanary-gui --smoke-test
From a checkout, use PYTHONPATH=src python -m tracecanary.gui --smoke-test on POSIX or set $env:PYTHONPATH = "src" first in PowerShell.
From a checkout, use the source tree directly:
$env:PYTHONPATH = "src"
python -m tracecanary validate fixtures/v1/contract.json
python -m tracecanary check --contract fixtures/v1/contract.json --input fixtures/v1/safe-export.json --format json
python -m tracecanary diff --contract fixtures/v1/contract.json --baseline fixtures/v1/safe-export.json --candidate fixtures/v1/missing-operational-fields.jsonOn POSIX shells, replace the first line with PYTHONPATH=src before each command or export it for the session. Installing the package also provides the tracecanary and tracecanary-gui commands.
After local installation, the synthetic fixture writer creates an empty, self-contained fixture directory:
tracecanary fixture create --output example
It refuses a non-empty output directory. From a fresh checkout, set PYTHONPATH=src before using python -m tracecanary fixture create --output example. All generated values are fictional.
After installation, use:
tracecanary validate contract.json
tracecanary check --contract contract.json --input export.json
tracecanary diff --contract contract.json --baseline safe.json --candidate changed.json
tracecanary batch --contract contract.json --input-dir exports --format sarif
tracecanary fixture create --output example/
tracecanary-gui
From a fresh checkout, set PYTHONPATH=src and replace tracecanary with python -m tracecanary; use python -m tracecanary.gui for the GUI. 0 means the contract is satisfied. 1 means a privacy or retention regression was detected. 2 means invalid input, an unsupported version, or an unresolved comparison. Reports identify the canary label, category, key, scope, and JSON path when relevant, but never print the matched canary value.
The JSON contract is strict. Unknown fields, duplicate keys, unsupported versions, empty canary sets, and malformed limits are rejected. The supported identifiers are tracecanary/v1 and opentelemetry/semconv/1.43.0.
{
"contract_version": "tracecanary/v1",
"semantic_conventions_version": "opentelemetry/semconv/1.43.0",
"canaries": [{"label": "test-prompt", "category": "prompt", "value": "TCANARY_EXAMPLE_123"}],
"forbidden_attribute_keys": ["gen_ai.prompt"],
"forbidden_attribute_key_prefixes": ["enduser."],
"forbidden_path_prefixes": ["/resourceSpans/*/scopeSpans/*/spans/*/attributes/*/value/bytesValue"],
"required_retained_fields": [{"scope": "resource", "key": "service.name"}]
}* matches one JSON-pointer path segment. A path prefix is checked only when it reaches a scalar value. Exact canaries are checked against every string scalar in the validated trace payload.
See the contract schema, method, threat model, limitations, and specification.
src/tracecanary/contains the CLI, contract checker, reports, fixture bundle, and GUI controller/window modules.TraceCanary.pywis the Windows double-click checkout launcher.fixtures/v1/contains synthetic contracts, trace inputs, and expected reports.tests/contains standard-library unit and controller tests.schemas/anddocs/contain the contract schema and method boundaries.
After local installation, or after setting PYTHONPATH=src in a checkout, run:
python -m unittest discover -s tests -v
python -m compileall -q src
python -m tracecanary.gui --smoke-test
The GitHub Actions workflow runs the suite on Windows and Linux, installs the local package without runtime dependencies, checks the CLI, and runs the GUI smoke test.
Apache-2.0. See LICENSE.