llm-redact-proxy 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- llm_redact_proxy-1.0.0/.claude/settings.json +7 -0
- llm_redact_proxy-1.0.0/.claude-plugin/marketplace.json +14 -0
- llm_redact_proxy-1.0.0/.dockerignore +12 -0
- llm_redact_proxy-1.0.0/.github/ISSUE_TEMPLATE/bug.yml +50 -0
- llm_redact_proxy-1.0.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- llm_redact_proxy-1.0.0/.github/ISSUE_TEMPLATE/feature.yml +36 -0
- llm_redact_proxy-1.0.0/.github/dependabot.yml +12 -0
- llm_redact_proxy-1.0.0/.github/pull_request_template.md +15 -0
- llm_redact_proxy-1.0.0/.github/workflows/ci.yml +439 -0
- llm_redact_proxy-1.0.0/.github/workflows/live.yml +63 -0
- llm_redact_proxy-1.0.0/.github/workflows/release.yml +161 -0
- llm_redact_proxy-1.0.0/.github/workflows/scorecard.yml +51 -0
- llm_redact_proxy-1.0.0/.gitignore +227 -0
- llm_redact_proxy-1.0.0/CHANGELOG.md +81 -0
- llm_redact_proxy-1.0.0/CLAUDE.md +89 -0
- llm_redact_proxy-1.0.0/Dockerfile +51 -0
- llm_redact_proxy-1.0.0/Formula/llm-redact.rb +79 -0
- llm_redact_proxy-1.0.0/LICENSE +661 -0
- llm_redact_proxy-1.0.0/PKG-INFO +526 -0
- llm_redact_proxy-1.0.0/README.md +487 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/MANIFEST.toml +109 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/README.md +36 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/gutenberg_prose.txt +3384 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/rfc_excerpt.txt +227 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/sqlite_excerpt.c +2262 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/synthetic_agentstack.env +15 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/synthetic_app.log +23 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/synthetic_bigint.log +11 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/synthetic_code.py +95 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/synthetic_config.yaml +67 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/synthetic_eu_document.txt +49 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/synthetic_k8s.yaml +81 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/synthetic_natids_r10.log +28 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/synthetic_netdebug.log +43 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/synthetic_runbook.md +49 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/synthetic_terraform.tf +46 -0
- llm_redact_proxy-1.0.0/bench/fp_corpus/synthetic_web3.ts +33 -0
- llm_redact_proxy-1.0.0/compose.yaml +33 -0
- llm_redact_proxy-1.0.0/config.example.toml +449 -0
- llm_redact_proxy-1.0.0/deploy/grafana-dashboard.json +178 -0
- llm_redact_proxy-1.0.0/deploy/helm/llm-redact/.helmignore +8 -0
- llm_redact_proxy-1.0.0/deploy/helm/llm-redact/Chart.yaml +23 -0
- llm_redact_proxy-1.0.0/deploy/helm/llm-redact/templates/NOTES.txt +71 -0
- llm_redact_proxy-1.0.0/deploy/helm/llm-redact/templates/_helpers.tpl +172 -0
- llm_redact_proxy-1.0.0/deploy/helm/llm-redact/templates/configmap.yaml +9 -0
- llm_redact_proxy-1.0.0/deploy/helm/llm-redact/templates/deployment.yaml +50 -0
- llm_redact_proxy-1.0.0/deploy/helm/llm-redact/templates/hpa.yaml +32 -0
- llm_redact_proxy-1.0.0/deploy/helm/llm-redact/templates/networkpolicy.yaml +31 -0
- llm_redact_proxy-1.0.0/deploy/helm/llm-redact/templates/pdb.yaml +13 -0
- llm_redact_proxy-1.0.0/deploy/helm/llm-redact/templates/service.yaml +17 -0
- llm_redact_proxy-1.0.0/deploy/helm/llm-redact/templates/serviceaccount.yaml +12 -0
- llm_redact_proxy-1.0.0/deploy/helm/llm-redact/templates/servicemonitor.yaml +16 -0
- llm_redact_proxy-1.0.0/deploy/helm/llm-redact/values.yaml +166 -0
- llm_redact_proxy-1.0.0/deploy/k8s-sidecar.yaml +101 -0
- llm_redact_proxy-1.0.0/deploy/prometheus-alerts.yml +78 -0
- llm_redact_proxy-1.0.0/deploy/prometheus-scrape.yml +22 -0
- llm_redact_proxy-1.0.0/docs/CLA.md +61 -0
- llm_redact_proxy-1.0.0/docs/CONTRIBUTING.md +144 -0
- llm_redact_proxy-1.0.0/docs/README.md +83 -0
- llm_redact_proxy-1.0.0/docs/RELEASING.md +104 -0
- llm_redact_proxy-1.0.0/docs/SECURITY.md +60 -0
- llm_redact_proxy-1.0.0/docs/api-coverage.md +185 -0
- llm_redact_proxy-1.0.0/docs/assurance.md +198 -0
- llm_redact_proxy-1.0.0/docs/coding-standards.md +126 -0
- llm_redact_proxy-1.0.0/docs/compaction-relink.md +64 -0
- llm_redact_proxy-1.0.0/docs/dashboard.md +93 -0
- llm_redact_proxy-1.0.0/docs/dependencies.md +56 -0
- llm_redact_proxy-1.0.0/docs/deployment.md +207 -0
- llm_redact_proxy-1.0.0/docs/detection.md +129 -0
- llm_redact_proxy-1.0.0/docs/diagrams/architecture.mmd +36 -0
- llm_redact_proxy-1.0.0/docs/diagrams/architecture.png +0 -0
- llm_redact_proxy-1.0.0/docs/diagrams/security-gates.mmd +42 -0
- llm_redact_proxy-1.0.0/docs/diagrams/security-gates.png +0 -0
- llm_redact_proxy-1.0.0/docs/diagrams/sequence-chat.mmd +24 -0
- llm_redact_proxy-1.0.0/docs/diagrams/sequence-chat.png +0 -0
- llm_redact_proxy-1.0.0/docs/diagrams/sequence-streaming.mmd +22 -0
- llm_redact_proxy-1.0.0/docs/diagrams/sequence-streaming.png +0 -0
- llm_redact_proxy-1.0.0/docs/editions.md +91 -0
- llm_redact_proxy-1.0.0/docs/fips.md +68 -0
- llm_redact_proxy-1.0.0/docs/history-hygiene.md +53 -0
- llm_redact_proxy-1.0.0/docs/how-it-works.md +183 -0
- llm_redact_proxy-1.0.0/docs/ner-landscape.md +103 -0
- llm_redact_proxy-1.0.0/docs/observability.md +54 -0
- llm_redact_proxy-1.0.0/docs/plugins.md +221 -0
- llm_redact_proxy-1.0.0/docs/providers.md +137 -0
- llm_redact_proxy-1.0.0/docs/quickstart.md +97 -0
- llm_redact_proxy-1.0.0/docs/resilience.md +105 -0
- llm_redact_proxy-1.0.0/docs/screenshots/config-editor.png +0 -0
- llm_redact_proxy-1.0.0/docs/screenshots/dashboard.png +0 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/audit.svg +11 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/config-edit-allowlist.svg +36 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/config-edit-block.svg +33 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/config-edit-languages.svg +45 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/config-edit.svg +47 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/config-show.svg +70 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/doctor.svg +21 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/guide.svg +24 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/install.svg +15 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/preview.svg +13 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/recent.svg +40 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/sessions.svg +11 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/status.svg +26 -0
- llm_redact_proxy-1.0.0/docs/screenshots/plugins/users.svg +11 -0
- llm_redact_proxy-1.0.0/docs/screenshots/preview.png +0 -0
- llm_redact_proxy-1.0.0/docs/security-dataflows.md +73 -0
- llm_redact_proxy-1.0.0/docs/security-review-3.1.md +121 -0
- llm_redact_proxy-1.0.0/docs/security-testing.md +68 -0
- llm_redact_proxy-1.0.0/docs/threat-model.md +241 -0
- llm_redact_proxy-1.0.0/docs/troubleshooting.md +118 -0
- llm_redact_proxy-1.0.0/docs/versioning.md +49 -0
- llm_redact_proxy-1.0.0/examples/compose-config.toml +7 -0
- llm_redact_proxy-1.0.0/plugins/llm-redact/.claude-plugin/plugin.json +18 -0
- llm_redact_proxy-1.0.0/plugins/llm-redact/commands/audit.md +23 -0
- llm_redact_proxy-1.0.0/plugins/llm-redact/commands/config-edit.md +47 -0
- llm_redact_proxy-1.0.0/plugins/llm-redact/commands/config-show.md +24 -0
- llm_redact_proxy-1.0.0/plugins/llm-redact/commands/doctor.md +24 -0
- llm_redact_proxy-1.0.0/plugins/llm-redact/commands/guide.md +25 -0
- llm_redact_proxy-1.0.0/plugins/llm-redact/commands/preview.md +28 -0
- llm_redact_proxy-1.0.0/plugins/llm-redact/commands/recent.md +28 -0
- llm_redact_proxy-1.0.0/plugins/llm-redact/commands/sessions.md +25 -0
- llm_redact_proxy-1.0.0/plugins/llm-redact/commands/status.md +35 -0
- llm_redact_proxy-1.0.0/plugins/llm-redact/commands/users.md +35 -0
- llm_redact_proxy-1.0.0/pyproject.toml +196 -0
- llm_redact_proxy-1.0.0/scripts/capture_plugin_screenshots.py +469 -0
- llm_redact_proxy-1.0.0/scripts/capture_screenshots.py +138 -0
- llm_redact_proxy-1.0.0/scripts/complexity_allowlist.py +13 -0
- llm_redact_proxy-1.0.0/scripts/complexity_gate.py +204 -0
- llm_redact_proxy-1.0.0/scripts/container_smoke.sh +72 -0
- llm_redact_proxy-1.0.0/scripts/dogfood_claude.py +261 -0
- llm_redact_proxy-1.0.0/scripts/fake_upstream.py +301 -0
- llm_redact_proxy-1.0.0/scripts/history_sweep.py +104 -0
- llm_redact_proxy-1.0.0/scripts/live_smoke.py +63 -0
- llm_redact_proxy-1.0.0/scripts/mutation_equivalents.py +905 -0
- llm_redact_proxy-1.0.0/scripts/mutation_gate.py +75 -0
- llm_redact_proxy-1.0.0/scripts/oracle_smoke.sh +43 -0
- llm_redact_proxy-1.0.0/scripts/plugin_e2e.py +75 -0
- llm_redact_proxy-1.0.0/scripts/render_diagrams.sh +32 -0
- llm_redact_proxy-1.0.0/scripts/render_plugins.py +39 -0
- llm_redact_proxy-1.0.0/scripts/render_user_guide.py +127 -0
- llm_redact_proxy-1.0.0/scripts/update_formula.py +47 -0
- llm_redact_proxy-1.0.0/src/llm_redact/__init__.py +3 -0
- llm_redact_proxy-1.0.0/src/llm_redact/__main__.py +4 -0
- llm_redact_proxy-1.0.0/src/llm_redact/audit.py +135 -0
- llm_redact_proxy-1.0.0/src/llm_redact/audit_s3.py +97 -0
- llm_redact_proxy-1.0.0/src/llm_redact/bench/__init__.py +6 -0
- llm_redact_proxy-1.0.0/src/llm_redact/bench/__main__.py +110 -0
- llm_redact_proxy-1.0.0/src/llm_redact/bench/corpus.py +968 -0
- llm_redact_proxy-1.0.0/src/llm_redact/bench/fp_scan.py +129 -0
- llm_redact_proxy-1.0.0/src/llm_redact/bench/latency.py +365 -0
- llm_redact_proxy-1.0.0/src/llm_redact/bench/metrics.py +124 -0
- llm_redact_proxy-1.0.0/src/llm_redact/cli.py +753 -0
- llm_redact_proxy-1.0.0/src/llm_redact/cloud_detect.py +92 -0
- llm_redact_proxy-1.0.0/src/llm_redact/completions.py +117 -0
- llm_redact_proxy-1.0.0/src/llm_redact/config.py +1023 -0
- llm_redact_proxy-1.0.0/src/llm_redact/config_write.py +314 -0
- llm_redact_proxy-1.0.0/src/llm_redact/dashboard.html +1218 -0
- llm_redact_proxy-1.0.0/src/llm_redact/detection/__init__.py +4 -0
- llm_redact_proxy-1.0.0/src/llm_redact/detection/base.py +24 -0
- llm_redact_proxy-1.0.0/src/llm_redact/detection/deny.py +57 -0
- llm_redact_proxy-1.0.0/src/llm_redact/detection/engine.py +345 -0
- llm_redact_proxy-1.0.0/src/llm_redact/detection/gliner_ner.py +73 -0
- llm_redact_proxy-1.0.0/src/llm_redact/detection/hf_ner.py +85 -0
- llm_redact_proxy-1.0.0/src/llm_redact/detection/ner.py +76 -0
- llm_redact_proxy-1.0.0/src/llm_redact/detection/presidio_ner.py +123 -0
- llm_redact_proxy-1.0.0/src/llm_redact/detection/regex_rules.py +1647 -0
- llm_redact_proxy-1.0.0/src/llm_redact/detection/stanza_ner.py +76 -0
- llm_redact_proxy-1.0.0/src/llm_redact/detection/validators.py +114 -0
- llm_redact_proxy-1.0.0/src/llm_redact/detection/wallet_checksums.py +264 -0
- llm_redact_proxy-1.0.0/src/llm_redact/doctor_cli.py +687 -0
- llm_redact_proxy-1.0.0/src/llm_redact/eventstream.py +216 -0
- llm_redact_proxy-1.0.0/src/llm_redact/fips.py +77 -0
- llm_redact_proxy-1.0.0/src/llm_redact/free_defaults.py +80 -0
- llm_redact_proxy-1.0.0/src/llm_redact/init_cli.py +147 -0
- llm_redact_proxy-1.0.0/src/llm_redact/jsonwalk.py +82 -0
- llm_redact_proxy-1.0.0/src/llm_redact/license_cli.py +94 -0
- llm_redact_proxy-1.0.0/src/llm_redact/licensing.py +133 -0
- llm_redact_proxy-1.0.0/src/llm_redact/log.py +47 -0
- llm_redact_proxy-1.0.0/src/llm_redact/metrics.py +154 -0
- llm_redact_proxy-1.0.0/src/llm_redact/multipart.py +116 -0
- llm_redact_proxy-1.0.0/src/llm_redact/ndjson.py +25 -0
- llm_redact_proxy-1.0.0/src/llm_redact/placeholders.py +96 -0
- llm_redact_proxy-1.0.0/src/llm_redact/plugin_api.py +92 -0
- llm_redact_proxy-1.0.0/src/llm_redact/plugin_assets.py +398 -0
- llm_redact_proxy-1.0.0/src/llm_redact/plugin_cli.py +298 -0
- llm_redact_proxy-1.0.0/src/llm_redact/providers/__init__.py +46 -0
- llm_redact_proxy-1.0.0/src/llm_redact/providers/anthropic.py +238 -0
- llm_redact_proxy-1.0.0/src/llm_redact/providers/azure_openai.py +83 -0
- llm_redact_proxy-1.0.0/src/llm_redact/providers/base.py +290 -0
- llm_redact_proxy-1.0.0/src/llm_redact/providers/bedrock.py +269 -0
- llm_redact_proxy-1.0.0/src/llm_redact/providers/claude_vertex.py +52 -0
- llm_redact_proxy-1.0.0/src/llm_redact/providers/cohere.py +204 -0
- llm_redact_proxy-1.0.0/src/llm_redact/providers/custom.py +105 -0
- llm_redact_proxy-1.0.0/src/llm_redact/providers/gemini.py +255 -0
- llm_redact_proxy-1.0.0/src/llm_redact/providers/ollama.py +129 -0
- llm_redact_proxy-1.0.0/src/llm_redact/providers/openai.py +371 -0
- llm_redact_proxy-1.0.0/src/llm_redact/providers/openai_responses.py +271 -0
- llm_redact_proxy-1.0.0/src/llm_redact/providers/vertex.py +50 -0
- llm_redact_proxy-1.0.0/src/llm_redact/proxy.py +2398 -0
- llm_redact_proxy-1.0.0/src/llm_redact/py.typed +0 -0
- llm_redact_proxy-1.0.0/src/llm_redact/realtime.py +861 -0
- llm_redact_proxy-1.0.0/src/llm_redact/redactor.py +124 -0
- llm_redact_proxy-1.0.0/src/llm_redact/registry.py +142 -0
- llm_redact_proxy-1.0.0/src/llm_redact/rehydrate.py +270 -0
- llm_redact_proxy-1.0.0/src/llm_redact/run_cli.py +215 -0
- llm_redact_proxy-1.0.0/src/llm_redact/service_cli.py +199 -0
- llm_redact_proxy-1.0.0/src/llm_redact/sessions.py +72 -0
- llm_redact_proxy-1.0.0/src/llm_redact/sse.py +100 -0
- llm_redact_proxy-1.0.0/src/llm_redact/user_guide.html +73 -0
- llm_redact_proxy-1.0.0/src/llm_redact/user_guide.md +124 -0
- llm_redact_proxy-1.0.0/src/llm_redact/users.py +162 -0
- llm_redact_proxy-1.0.0/src/llm_redact/vault.py +715 -0
- llm_redact_proxy-1.0.0/src/llm_redact/vault_cli.py +673 -0
- llm_redact_proxy-1.0.0/src/llm_redact/vault_crypto.py +104 -0
- llm_redact_proxy-1.0.0/src/llm_redact/vault_rdbms.py +891 -0
- llm_redact_proxy-1.0.0/tests/conftest.py +38 -0
- llm_redact_proxy-1.0.0/tests/fake_cipher.py +45 -0
- llm_redact_proxy-1.0.0/tests/license_fixtures.py +45 -0
- llm_redact_proxy-1.0.0/tests/test_api_coverage.py +121 -0
- llm_redact_proxy-1.0.0/tests/test_audit_required.py +241 -0
- llm_redact_proxy-1.0.0/tests/test_bench.py +76 -0
- llm_redact_proxy-1.0.0/tests/test_canary_leak.py +139 -0
- llm_redact_proxy-1.0.0/tests/test_cli_status.py +182 -0
- llm_redact_proxy-1.0.0/tests/test_cli_tools.py +228 -0
- llm_redact_proxy-1.0.0/tests/test_cli_vault.py +204 -0
- llm_redact_proxy-1.0.0/tests/test_cloud_detect.py +62 -0
- llm_redact_proxy-1.0.0/tests/test_codec_fuzz.py +105 -0
- llm_redact_proxy-1.0.0/tests/test_codec_mutation_kills.py +291 -0
- llm_redact_proxy-1.0.0/tests/test_complexity_gate.py +174 -0
- llm_redact_proxy-1.0.0/tests/test_config.py +177 -0
- llm_redact_proxy-1.0.0/tests/test_config_endpoint.py +561 -0
- llm_redact_proxy-1.0.0/tests/test_config_write.py +256 -0
- llm_redact_proxy-1.0.0/tests/test_coverage_gaps.py +148 -0
- llm_redact_proxy-1.0.0/tests/test_coverage_tail.py +196 -0
- llm_redact_proxy-1.0.0/tests/test_custom_providers.py +187 -0
- llm_redact_proxy-1.0.0/tests/test_custom_validators.py +134 -0
- llm_redact_proxy-1.0.0/tests/test_dashboard.py +243 -0
- llm_redact_proxy-1.0.0/tests/test_deny.py +217 -0
- llm_redact_proxy-1.0.0/tests/test_dependencies_doc.py +40 -0
- llm_redact_proxy-1.0.0/tests/test_deploy_assets.py +303 -0
- llm_redact_proxy-1.0.0/tests/test_detection_scope.py +354 -0
- llm_redact_proxy-1.0.0/tests/test_detectors.py +764 -0
- llm_redact_proxy-1.0.0/tests/test_docs_index.py +16 -0
- llm_redact_proxy-1.0.0/tests/test_doctor.py +396 -0
- llm_redact_proxy-1.0.0/tests/test_events_endpoint.py +143 -0
- llm_redact_proxy-1.0.0/tests/test_eventstream.py +180 -0
- llm_redact_proxy-1.0.0/tests/test_fips_posture.py +73 -0
- llm_redact_proxy-1.0.0/tests/test_free_alone.py +126 -0
- llm_redact_proxy-1.0.0/tests/test_gliner.py +127 -0
- llm_redact_proxy-1.0.0/tests/test_jsonwalk.py +73 -0
- llm_redact_proxy-1.0.0/tests/test_language_scope.py +214 -0
- llm_redact_proxy-1.0.0/tests/test_latency_bench.py +61 -0
- llm_redact_proxy-1.0.0/tests/test_licensing.py +86 -0
- llm_redact_proxy-1.0.0/tests/test_live.py +589 -0
- llm_redact_proxy-1.0.0/tests/test_log.py +65 -0
- llm_redact_proxy-1.0.0/tests/test_mcp_connector.py +148 -0
- llm_redact_proxy-1.0.0/tests/test_metrics.py +63 -0
- llm_redact_proxy-1.0.0/tests/test_modes.py +151 -0
- llm_redact_proxy-1.0.0/tests/test_multipart.py +111 -0
- llm_redact_proxy-1.0.0/tests/test_mutation_hardening.py +476 -0
- llm_redact_proxy-1.0.0/tests/test_ndjson.py +27 -0
- llm_redact_proxy-1.0.0/tests/test_ner.py +109 -0
- llm_redact_proxy-1.0.0/tests/test_ner_multibackend.py +171 -0
- llm_redact_proxy-1.0.0/tests/test_ner_stanza_hf.py +172 -0
- llm_redact_proxy-1.0.0/tests/test_no_gates.py +89 -0
- llm_redact_proxy-1.0.0/tests/test_no_op_forward.py +65 -0
- llm_redact_proxy-1.0.0/tests/test_open_core_free_coverage.py +288 -0
- llm_redact_proxy-1.0.0/tests/test_placeholders.py +101 -0
- llm_redact_proxy-1.0.0/tests/test_plugin_cli.py +247 -0
- llm_redact_proxy-1.0.0/tests/test_plugins.py +145 -0
- llm_redact_proxy-1.0.0/tests/test_prefilter.py +161 -0
- llm_redact_proxy-1.0.0/tests/test_presidio.py +217 -0
- llm_redact_proxy-1.0.0/tests/test_preview.py +119 -0
- llm_redact_proxy-1.0.0/tests/test_properties.py +595 -0
- llm_redact_proxy-1.0.0/tests/test_provider_anthropic.py +116 -0
- llm_redact_proxy-1.0.0/tests/test_provider_anthropic_batches.py +212 -0
- llm_redact_proxy-1.0.0/tests/test_provider_azure.py +132 -0
- llm_redact_proxy-1.0.0/tests/test_provider_cohere.py +192 -0
- llm_redact_proxy-1.0.0/tests/test_provider_gemini.py +288 -0
- llm_redact_proxy-1.0.0/tests/test_provider_ollama.py +277 -0
- llm_redact_proxy-1.0.0/tests/test_provider_openai.py +230 -0
- llm_redact_proxy-1.0.0/tests/test_provider_openai_files.py +280 -0
- llm_redact_proxy-1.0.0/tests/test_provider_openai_media.py +330 -0
- llm_redact_proxy-1.0.0/tests/test_provider_openai_responses.py +235 -0
- llm_redact_proxy-1.0.0/tests/test_proxy_integration.py +957 -0
- llm_redact_proxy-1.0.0/tests/test_realtime_gemini.py +185 -0
- llm_redact_proxy-1.0.0/tests/test_realtime_openai.py +318 -0
- llm_redact_proxy-1.0.0/tests/test_realtime_relay.py +218 -0
- llm_redact_proxy-1.0.0/tests/test_redactor.py +129 -0
- llm_redact_proxy-1.0.0/tests/test_registry.py +215 -0
- llm_redact_proxy-1.0.0/tests/test_rehydrate.py +214 -0
- llm_redact_proxy-1.0.0/tests/test_reload.py +172 -0
- llm_redact_proxy-1.0.0/tests/test_restart_only_docs.py +36 -0
- llm_redact_proxy-1.0.0/tests/test_run_cli.py +248 -0
- llm_redact_proxy-1.0.0/tests/test_screenshot_assets.py +45 -0
- llm_redact_proxy-1.0.0/tests/test_security_boundaries.py +510 -0
- llm_redact_proxy-1.0.0/tests/test_serve_check.py +118 -0
- llm_redact_proxy-1.0.0/tests/test_session_ttl.py +69 -0
- llm_redact_proxy-1.0.0/tests/test_sessions.py +52 -0
- llm_redact_proxy-1.0.0/tests/test_sessions_endpoint.py +164 -0
- llm_redact_proxy-1.0.0/tests/test_soak_concurrency.py +33 -0
- llm_redact_proxy-1.0.0/tests/test_sse.py +70 -0
- llm_redact_proxy-1.0.0/tests/test_stream_truncation.py +162 -0
- llm_redact_proxy-1.0.0/tests/test_tls.py +222 -0
- llm_redact_proxy-1.0.0/tests/test_upstream_faults.py +241 -0
- llm_redact_proxy-1.0.0/tests/test_user_guide.py +85 -0
- llm_redact_proxy-1.0.0/tests/test_vault.py +29 -0
- llm_redact_proxy-1.0.0/tests/test_vault_crypto_free.py +148 -0
- llm_redact_proxy-1.0.0/tests/test_vault_faults.py +131 -0
- llm_redact_proxy-1.0.0/tests/test_vault_rdbms.py +816 -0
- llm_redact_proxy-1.0.0/tests/test_vault_sqlite.py +276 -0
- llm_redact_proxy-1.0.0/tests/test_wallet_checksums.py +97 -0
- llm_redact_proxy-1.0.0/uv.lock +3434 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "llm-redact",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "llm-redact",
|
|
5
|
+
"url": "https://github.com/asanderson/llm-redact"
|
|
6
|
+
},
|
|
7
|
+
"plugins": [
|
|
8
|
+
{
|
|
9
|
+
"name": "llm-redact",
|
|
10
|
+
"source": "./plugins/llm-redact",
|
|
11
|
+
"description": "llm-redact proxy control: status, live traffic, sessions, redaction preview, audit verification, and guarded config editing as slash commands"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something misbehaves — a redaction miss on a covered shape, a mangled response, a broken tool.
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
**Never paste real secrets, vault contents, or raw request/response
|
|
9
|
+
bodies containing private values.** Reproduce with secret-shaped
|
|
10
|
+
fakes (`AKIAIOSFODNN7EXAMPLE`, `jane@corp.example`) — the detectors
|
|
11
|
+
treat them identically. Suspected security vulnerabilities go
|
|
12
|
+
through [private reporting](../../security/policy), not issues.
|
|
13
|
+
- type: input
|
|
14
|
+
id: version
|
|
15
|
+
attributes:
|
|
16
|
+
label: llm-redact version
|
|
17
|
+
description: "`llm-redact --version` (also note the install method: pip/uvx, container, source)"
|
|
18
|
+
placeholder: "1.4.0, via uvx"
|
|
19
|
+
validations:
|
|
20
|
+
required: true
|
|
21
|
+
- type: input
|
|
22
|
+
id: tool
|
|
23
|
+
attributes:
|
|
24
|
+
label: Agentic tool and provider
|
|
25
|
+
description: What talks through the proxy, and to which provider/endpoint?
|
|
26
|
+
placeholder: "Claude Code → Anthropic /v1/messages (streaming)"
|
|
27
|
+
validations:
|
|
28
|
+
required: true
|
|
29
|
+
- type: textarea
|
|
30
|
+
id: repro
|
|
31
|
+
attributes:
|
|
32
|
+
label: Reproduction
|
|
33
|
+
description: Smallest input/config that shows the problem. Redact your config's allowlist/deny values if they are themselves sensitive.
|
|
34
|
+
placeholder: |
|
|
35
|
+
1. serve with the config below
|
|
36
|
+
2. send this request (fake values)
|
|
37
|
+
3. observe ...
|
|
38
|
+
validations:
|
|
39
|
+
required: true
|
|
40
|
+
- type: textarea
|
|
41
|
+
id: expected
|
|
42
|
+
attributes:
|
|
43
|
+
label: Expected vs actual
|
|
44
|
+
validations:
|
|
45
|
+
required: true
|
|
46
|
+
- type: textarea
|
|
47
|
+
id: logs
|
|
48
|
+
attributes:
|
|
49
|
+
label: Proxy log lines
|
|
50
|
+
description: Proxy logs carry only paths, statuses, and detection counts by design — safe to paste as-is.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
blank_issues_enabled: true
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Report a security vulnerability
|
|
4
|
+
url: https://github.com/asanderson/llm-redact/security/policy
|
|
5
|
+
about: Suspected vulnerabilities go through GitHub private vulnerability reporting — never public issues. See docs/SECURITY.md for scope.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: A new capability, provider, or detection rule.
|
|
3
|
+
labels: [enhancement]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: Problem
|
|
9
|
+
description: What can't you do today, or what leaks that shouldn't?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: proposal
|
|
14
|
+
attributes:
|
|
15
|
+
label: Proposed behavior
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: markdown
|
|
19
|
+
attributes:
|
|
20
|
+
value: |
|
|
21
|
+
For **new detection rules**, note the bars up front (they are why
|
|
22
|
+
some obvious-seeming rules are deliberately absent — see the
|
|
23
|
+
"Known limitations" section of the README):
|
|
24
|
+
- vendor tokens need a distinctive **prefix** to anchor on;
|
|
25
|
+
- national ids need a **grouped display form plus a checksum**
|
|
26
|
+
(bare digit runs never fire — too collision-prone);
|
|
27
|
+
- the rule must pass the false-positive corpus gate.
|
|
28
|
+
|
|
29
|
+
For **new providers**: the proxy operates on raw bytes and must
|
|
30
|
+
forward unknown fields verbatim; a link to the provider's wire
|
|
31
|
+
format docs (streaming included) makes triage much faster.
|
|
32
|
+
- type: textarea
|
|
33
|
+
id: alternatives
|
|
34
|
+
attributes:
|
|
35
|
+
label: Alternatives considered
|
|
36
|
+
description: Custom rules (`[[detection.custom_rules]]`), deny strings, an existing provider's compat endpoint, ...
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Keep the SHA-pinned GitHub Actions current: dependabot updates the pinned
|
|
2
|
+
# SHA and its trailing version comment together. Python deps are handled by
|
|
3
|
+
# uv.lock plus the weekly gating pip-audit job, so only actions are watched.
|
|
4
|
+
version: 2
|
|
5
|
+
updates:
|
|
6
|
+
- package-ecosystem: github-actions
|
|
7
|
+
directory: /
|
|
8
|
+
schedule:
|
|
9
|
+
interval: weekly
|
|
10
|
+
groups:
|
|
11
|
+
actions:
|
|
12
|
+
patterns: ["*"]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!-- Never include real secrets anywhere in a PR — use secret-shaped fakes
|
|
2
|
+
(vendors' canonical examples, alphabet runs, corp.example domains). -->
|
|
3
|
+
|
|
4
|
+
## What & why
|
|
5
|
+
|
|
6
|
+
## Checklist
|
|
7
|
+
|
|
8
|
+
- [ ] All gates pass locally: `ruff check` + `ruff format --check`,
|
|
9
|
+
`pytest`, `mypy`, `python -m llm_redact.bench --check`
|
|
10
|
+
- [ ] `CHANGELOG.md` entry under `[Unreleased]` (user-visible changes)
|
|
11
|
+
- [ ] Touched `rehydrate.py`/`sse.py`/adapter event handling → extended the
|
|
12
|
+
split-at-every-offset sweeps (not just single-case tests)
|
|
13
|
+
- [ ] New detection rule → generator in `bench/corpus.py`, fp-corpus gate
|
|
14
|
+
run, `MANIFEST.toml` updated with justification if counts changed
|
|
15
|
+
- [ ] No new runtime dependencies (extras are fine)
|
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
# Weekly run so new dependency advisories (the audit job) surface on main
|
|
8
|
+
# without waiting for the next push.
|
|
9
|
+
schedule:
|
|
10
|
+
- cron: "17 6 * * 1"
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
test:
|
|
21
|
+
name: test (py${{ matrix.python }})
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
strategy:
|
|
24
|
+
fail-fast: false
|
|
25
|
+
matrix:
|
|
26
|
+
python: ["3.11", "3.12", "3.13", "3.14"]
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
29
|
+
with:
|
|
30
|
+
persist-credentials: false
|
|
31
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
32
|
+
with:
|
|
33
|
+
python-version: ${{ matrix.python }}
|
|
34
|
+
enable-cache: true
|
|
35
|
+
cache-dependency-glob: uv.lock
|
|
36
|
+
- run: uv sync --frozen
|
|
37
|
+
- run: uv run pytest
|
|
38
|
+
# The concurrency/soak checks are deselected from the default run; run
|
|
39
|
+
# them explicitly so the never-wrong-value-under-load invariants stay live.
|
|
40
|
+
- run: uv run pytest -m soak
|
|
41
|
+
- run: uv run ruff check .
|
|
42
|
+
- run: uv run ruff format --check .
|
|
43
|
+
- run: uv run mypy
|
|
44
|
+
|
|
45
|
+
test-macos:
|
|
46
|
+
# Both macOS architectures, one Python each: the platform-sensitive
|
|
47
|
+
# surface (kqueue event loop, APFS os.replace, explicit 0600/0700
|
|
48
|
+
# modes, sqlite WAL, SIGHUP) does not vary by Python minor, and macOS
|
|
49
|
+
# runners bill ~10x Linux. macos-15 is Apple silicon (arm64);
|
|
50
|
+
# macos-15-intel is GitHub's x86_64 runner (supported into 2027) —
|
|
51
|
+
# the wheel is pure-Python, so these jobs ARE the x86_64/arm64 macOS
|
|
52
|
+
# support verification.
|
|
53
|
+
name: test (macOS ${{ matrix.arch }}, py3.13)
|
|
54
|
+
strategy:
|
|
55
|
+
fail-fast: false
|
|
56
|
+
matrix:
|
|
57
|
+
include:
|
|
58
|
+
- runner: macos-15
|
|
59
|
+
arch: arm64
|
|
60
|
+
- runner: macos-15-intel
|
|
61
|
+
arch: x86_64
|
|
62
|
+
runs-on: ${{ matrix.runner }}
|
|
63
|
+
steps:
|
|
64
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
65
|
+
with:
|
|
66
|
+
persist-credentials: false
|
|
67
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
68
|
+
with:
|
|
69
|
+
python-version: "3.13"
|
|
70
|
+
enable-cache: true
|
|
71
|
+
cache-dependency-glob: uv.lock
|
|
72
|
+
- run: uv sync --frozen
|
|
73
|
+
- run: uv run pytest
|
|
74
|
+
|
|
75
|
+
test-windows:
|
|
76
|
+
# Phase 26: the supported Windows scope is the Free tier + agent
|
|
77
|
+
# plugins, and this job is its verification — the FULL suite runs, with
|
|
78
|
+
# only narrow, pinned platform gates (POSIX mode assertions become
|
|
79
|
+
# conditional; doctor/service take their win32 branches). PYTHONUTF8
|
|
80
|
+
# keeps the guillemet placeholders printable on a cp1252 console.
|
|
81
|
+
name: test (Windows, py3.13)
|
|
82
|
+
runs-on: windows-latest
|
|
83
|
+
env:
|
|
84
|
+
PYTHONUTF8: "1"
|
|
85
|
+
steps:
|
|
86
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
87
|
+
with:
|
|
88
|
+
persist-credentials: false
|
|
89
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
90
|
+
with:
|
|
91
|
+
python-version: "3.13"
|
|
92
|
+
enable-cache: true
|
|
93
|
+
cache-dependency-glob: uv.lock
|
|
94
|
+
- run: uv sync --frozen
|
|
95
|
+
- run: uv run pytest
|
|
96
|
+
|
|
97
|
+
plugins:
|
|
98
|
+
name: agent plugins (install e2e + validate)
|
|
99
|
+
runs-on: ubuntu-latest
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
102
|
+
with:
|
|
103
|
+
persist-credentials: false
|
|
104
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
105
|
+
with:
|
|
106
|
+
python-version: "3.13"
|
|
107
|
+
enable-cache: true
|
|
108
|
+
cache-dependency-glob: uv.lock
|
|
109
|
+
- run: uv sync --frozen
|
|
110
|
+
# The rendered plugin tree + marketplace must be in sync with
|
|
111
|
+
# plugin_assets.py (also pinned by test, but re-render here so a
|
|
112
|
+
# stale checked-in file fails loudly).
|
|
113
|
+
- run: uv run python scripts/render_plugins.py && git diff --exit-code plugins .claude-plugin
|
|
114
|
+
# Install into a throwaway HOME and prove the command↔CLI contract.
|
|
115
|
+
- run: uv run python scripts/plugin_e2e.py
|
|
116
|
+
# Structural validation of the Claude Code plugin manifest, when the
|
|
117
|
+
# CLI is available (best-effort — never blocks the job if absent).
|
|
118
|
+
- name: claude plugin validate (best-effort)
|
|
119
|
+
run: |
|
|
120
|
+
if command -v claude >/dev/null 2>&1; then
|
|
121
|
+
claude plugin validate --strict plugins/llm-redact || exit 1
|
|
122
|
+
else
|
|
123
|
+
echo "claude CLI not present on the runner; skipping structural validate"
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
helm:
|
|
127
|
+
# The Helm chart (deploy/helm/llm-redact) rendered for real: `helm lint`
|
|
128
|
+
# plus the helm-gated tests in test_deploy_assets.py, which render both
|
|
129
|
+
# value presets (sidecar; standalone+autoscaling) and assert the
|
|
130
|
+
# never-wrong-value guardrail {{ fail }}s a per-pod-vault autoscaled render.
|
|
131
|
+
# helm is installed from the official release with a PINNED version +
|
|
132
|
+
# SHA256 checksum (no marketplace action in the supply chain); the base
|
|
133
|
+
# `test` job already runs the stdlib needle/appVersion tests, which skip
|
|
134
|
+
# the helm-gated ones when helm is absent.
|
|
135
|
+
name: helm chart (lint + render both modes)
|
|
136
|
+
runs-on: ubuntu-latest
|
|
137
|
+
env:
|
|
138
|
+
HELM_VERSION: v3.16.3
|
|
139
|
+
HELM_SHA256: f5355c79190951eed23c5432a3b920e071f4c00a64f75e077de0dd4cb7b294ea
|
|
140
|
+
steps:
|
|
141
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
142
|
+
with:
|
|
143
|
+
persist-credentials: false
|
|
144
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
145
|
+
with:
|
|
146
|
+
python-version: "3.13"
|
|
147
|
+
enable-cache: true
|
|
148
|
+
cache-dependency-glob: uv.lock
|
|
149
|
+
- run: uv sync --frozen
|
|
150
|
+
- name: install helm (pinned + checksum-verified)
|
|
151
|
+
run: |
|
|
152
|
+
set -euo pipefail
|
|
153
|
+
tarball="helm-${HELM_VERSION}-linux-amd64.tar.gz"
|
|
154
|
+
curl -fsSL "https://get.helm.sh/${tarball}" -o "$tarball"
|
|
155
|
+
echo "${HELM_SHA256} ${tarball}" | sha256sum -c -
|
|
156
|
+
tar xzf "$tarball"
|
|
157
|
+
sudo install -m 0755 linux-amd64/helm /usr/local/bin/helm
|
|
158
|
+
helm version
|
|
159
|
+
- name: helm lint
|
|
160
|
+
run: helm lint deploy/helm/llm-redact
|
|
161
|
+
- name: chart tests (renders both presets + guardrail-fires)
|
|
162
|
+
run: uv run pytest tests/test_deploy_assets.py -v
|
|
163
|
+
- name: guardrail fails an autoscaled per-pod-vault render
|
|
164
|
+
run: |
|
|
165
|
+
set -euo pipefail
|
|
166
|
+
if helm template rel deploy/helm/llm-redact \
|
|
167
|
+
--set mode=standalone --set autoscaling.enabled=true \
|
|
168
|
+
--set vault.backend=sqlite >/dev/null 2>err.txt; then
|
|
169
|
+
echo "FAIL: guardrail did not fire for standalone+sqlite+autoscaling"; exit 1
|
|
170
|
+
fi
|
|
171
|
+
grep -q "SHARED vault" err.txt
|
|
172
|
+
|
|
173
|
+
audit:
|
|
174
|
+
name: dependency audit (pip-audit)
|
|
175
|
+
runs-on: ubuntu-latest
|
|
176
|
+
steps:
|
|
177
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
178
|
+
with:
|
|
179
|
+
persist-credentials: false
|
|
180
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
181
|
+
with:
|
|
182
|
+
python-version: "3.13"
|
|
183
|
+
enable-cache: true
|
|
184
|
+
cache-dependency-glob: uv.lock
|
|
185
|
+
# Runtime closure only (no dev tools): what a `pip install
|
|
186
|
+
# llm-redact-proxy` user actually gets. Gating on purpose — the
|
|
187
|
+
# closure is tiny (httpx/starlette/uvicorn). If an advisory has no
|
|
188
|
+
# fix released yet, add `--ignore-vuln GHSA-...` with a comment and
|
|
189
|
+
# an issue link, and remove it when the fix ships.
|
|
190
|
+
- run: >
|
|
191
|
+
uv export --frozen --no-dev --no-emit-project --no-hashes
|
|
192
|
+
-o requirements-audit.txt
|
|
193
|
+
- run: uvx pip-audit --strict --no-deps -r requirements-audit.txt
|
|
194
|
+
|
|
195
|
+
dependency-review:
|
|
196
|
+
# Blocks a PR that introduces a dependency with a known vulnerability or a
|
|
197
|
+
# disallowed licence, using GitHub's Dependency Graph diff. The graph is
|
|
198
|
+
# available on public repos (and private repos with Advanced Security), so
|
|
199
|
+
# the job self-skips while this repo is private — it arms on go-public,
|
|
200
|
+
# the same switch as PyPI publishing and build attestations. pip-audit
|
|
201
|
+
# (the `audit` job) covers the runtime closure meanwhile.
|
|
202
|
+
name: dependency review
|
|
203
|
+
runs-on: ubuntu-latest
|
|
204
|
+
if: ${{ github.event_name == 'pull_request' && github.event.repository.private == false }}
|
|
205
|
+
steps:
|
|
206
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
207
|
+
with:
|
|
208
|
+
persist-credentials: false
|
|
209
|
+
- uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
|
|
210
|
+
with:
|
|
211
|
+
fail-on-severity: high
|
|
212
|
+
# Copyleft licences would complicate the MIT distribution; flag them
|
|
213
|
+
# for a human decision rather than silently pulling them in.
|
|
214
|
+
deny-licenses: GPL-2.0, GPL-3.0, AGPL-3.0
|
|
215
|
+
|
|
216
|
+
ner:
|
|
217
|
+
name: ner extras (spaCy model + presidio)
|
|
218
|
+
runs-on: ubuntu-latest
|
|
219
|
+
steps:
|
|
220
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
221
|
+
with:
|
|
222
|
+
persist-credentials: false
|
|
223
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
224
|
+
with:
|
|
225
|
+
python-version: "3.13"
|
|
226
|
+
enable-cache: true
|
|
227
|
+
cache-dependency-glob: uv.lock
|
|
228
|
+
- run: uv sync --frozen --extra ner --extra presidio
|
|
229
|
+
# Direct wheel URL: `spacy download` shells out to pip, which does not
|
|
230
|
+
# exist in uv-managed venvs. One model serves both backends (the
|
|
231
|
+
# presidio detector pins en_core_web_sm too).
|
|
232
|
+
- run: uv pip install https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl
|
|
233
|
+
# test_presidio.py includes the real-AnalyzerEngine smoke test, which
|
|
234
|
+
# only runs when the extra and the model are both present — i.e. here.
|
|
235
|
+
- run: uv run pytest tests/test_ner.py tests/test_presidio.py -v
|
|
236
|
+
|
|
237
|
+
# NOTE (R4 open-core split): the real-PostgreSQL+MySQL RDBMS-vault job moved
|
|
238
|
+
# to the private llm-redact-pro repo's CI (the server RDBMS vault is a Pro
|
|
239
|
+
# feature). The Free `test` job still runs test_vault_rdbms.py's fake-driver
|
|
240
|
+
# battery over stdlib sqlite3-as-dbapi, which proves the portable dialect SQL.
|
|
241
|
+
|
|
242
|
+
bench:
|
|
243
|
+
name: detection bench (report artifact)
|
|
244
|
+
runs-on: ubuntu-latest
|
|
245
|
+
steps:
|
|
246
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
247
|
+
with:
|
|
248
|
+
persist-credentials: false
|
|
249
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
250
|
+
with:
|
|
251
|
+
python-version: "3.13"
|
|
252
|
+
enable-cache: true
|
|
253
|
+
cache-dependency-glob: uv.lock
|
|
254
|
+
- run: uv sync --frozen
|
|
255
|
+
- run: uv run python -m llm_redact.bench --latency --out bench-report --check
|
|
256
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
257
|
+
with:
|
|
258
|
+
name: bench-report
|
|
259
|
+
path: bench-report/
|
|
260
|
+
|
|
261
|
+
complexity:
|
|
262
|
+
# Every function with cyclomatic complexity > 1 must be EXECUTED by the
|
|
263
|
+
# suite (scripts/complexity_gate.py). Report-only through 3.1.1; gated
|
|
264
|
+
# here from 3.1.2 — an uncovered branching function fails unless recorded
|
|
265
|
+
# in scripts/complexity_allowlist.py with a justification, and a stale
|
|
266
|
+
# allowlist entry fails too (same discipline as the mutation gate).
|
|
267
|
+
name: complexity coverage (assurance gate)
|
|
268
|
+
runs-on: ubuntu-latest
|
|
269
|
+
steps:
|
|
270
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
271
|
+
with:
|
|
272
|
+
persist-credentials: false
|
|
273
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
274
|
+
with:
|
|
275
|
+
python-version: "3.13"
|
|
276
|
+
enable-cache: true
|
|
277
|
+
cache-dependency-glob: uv.lock
|
|
278
|
+
- run: uv sync --frozen
|
|
279
|
+
- name: run the suite under coverage
|
|
280
|
+
run: uv run coverage run -m pytest -q
|
|
281
|
+
- name: gate on CC>1 execution (Free core)
|
|
282
|
+
run: uv run python scripts/complexity_gate.py --check
|
|
283
|
+
# The paid package's own complexity gate runs in the llm-redact-pro repo's
|
|
284
|
+
# CI (R4 physical split) — it is no longer in this tree.
|
|
285
|
+
|
|
286
|
+
# NOTE (R4 open-core split): the `free-alone` job (which hid the co-located
|
|
287
|
+
# src/llm_redact_pro to simulate a Free-only install) and the `enforcement-ext`
|
|
288
|
+
# job (which compiled the pro Cython enforcement core) both moved to the
|
|
289
|
+
# llm-redact-pro repo. This repo IS the Free-only install now — test_free_alone.py
|
|
290
|
+
# runs in the normal `test` job (the pro package is genuinely absent), and the
|
|
291
|
+
# keyless-boot / paid-config-fails-closed assertions ride there.
|
|
292
|
+
|
|
293
|
+
mutation:
|
|
294
|
+
# Assurance: mutation testing proves the suites KILL a weakened guard or a
|
|
295
|
+
# broken checksum, not just that they pass. Scoped to the load-bearing
|
|
296
|
+
# correctness core ([tool.mutmut] in pyproject). GATING via
|
|
297
|
+
# scripts/mutation_gate.py: a surviving mutant fails unless recorded in
|
|
298
|
+
# scripts/mutation_equivalents.py with a reviewed justification, and a
|
|
299
|
+
# stale allow-list entry fails too — nothing survives silently in either
|
|
300
|
+
# direction (see docs/assurance.md). Baseline: 968/1100 killed, 130
|
|
301
|
+
# reviewed equivalents.
|
|
302
|
+
name: mutation testing (assurance gate)
|
|
303
|
+
runs-on: ubuntu-latest
|
|
304
|
+
steps:
|
|
305
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
306
|
+
with:
|
|
307
|
+
persist-credentials: false
|
|
308
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
309
|
+
with:
|
|
310
|
+
python-version: "3.13"
|
|
311
|
+
enable-cache: true
|
|
312
|
+
cache-dependency-glob: uv.lock
|
|
313
|
+
- run: uv sync --frozen
|
|
314
|
+
# mutmut exits non-zero when ANY mutant survives — including the 130
|
|
315
|
+
# reviewed equivalents — so the run itself must not gate; the gate
|
|
316
|
+
# script right after it is the pass/fail arbiter.
|
|
317
|
+
- name: run mutation testing
|
|
318
|
+
run: uv run mutmut run || true
|
|
319
|
+
- name: gate against the equivalents allow-list
|
|
320
|
+
run: uv run python scripts/mutation_gate.py
|
|
321
|
+
- name: summarize survivors
|
|
322
|
+
if: always()
|
|
323
|
+
run: uv run mutmut results | tee mutmut-results.txt
|
|
324
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
325
|
+
if: always()
|
|
326
|
+
with:
|
|
327
|
+
name: mutation-results
|
|
328
|
+
path: mutmut-results.txt
|
|
329
|
+
|
|
330
|
+
history-hygiene:
|
|
331
|
+
# Non-gating: runs the production detectors over ALL git history and
|
|
332
|
+
# uploads the HISTORY-ONLY report. This is the go-public review signal —
|
|
333
|
+
# flipping the repo public exposes every past commit at once, so the
|
|
334
|
+
# report must be reviewed clean before that (see docs/history-hygiene.md).
|
|
335
|
+
# Not a hard gate: 17 phases carry many benign secret-SHAPED test fixtures.
|
|
336
|
+
name: history hygiene (report artifact)
|
|
337
|
+
runs-on: ubuntu-latest
|
|
338
|
+
steps:
|
|
339
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
340
|
+
with:
|
|
341
|
+
persist-credentials: false
|
|
342
|
+
fetch-depth: 0 # full history for the sweep
|
|
343
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
344
|
+
with:
|
|
345
|
+
python-version: "3.13"
|
|
346
|
+
enable-cache: true
|
|
347
|
+
cache-dependency-glob: uv.lock
|
|
348
|
+
- run: uv sync --frozen
|
|
349
|
+
- run: uv run python scripts/history_sweep.py | tee history-sweep.txt
|
|
350
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
351
|
+
if: always()
|
|
352
|
+
with:
|
|
353
|
+
name: history-sweep
|
|
354
|
+
path: history-sweep.txt
|
|
355
|
+
|
|
356
|
+
build:
|
|
357
|
+
name: build distribution
|
|
358
|
+
runs-on: ubuntu-latest
|
|
359
|
+
steps:
|
|
360
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
361
|
+
with:
|
|
362
|
+
persist-credentials: false
|
|
363
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
364
|
+
with:
|
|
365
|
+
python-version: "3.13"
|
|
366
|
+
- run: uv build
|
|
367
|
+
- run: uvx twine check dist/*
|
|
368
|
+
# twine cannot catch missing package data; assert the dashboard, the
|
|
369
|
+
# user guide, and the license text ship in both distributions.
|
|
370
|
+
- name: check package data
|
|
371
|
+
run: |
|
|
372
|
+
python -m zipfile -l dist/*.whl | grep 'llm_redact/dashboard.html'
|
|
373
|
+
tar -tzf dist/*.tar.gz | grep 'src/llm_redact/dashboard.html'
|
|
374
|
+
python -m zipfile -l dist/*.whl | grep 'llm_redact/user_guide.md'
|
|
375
|
+
python -m zipfile -l dist/*.whl | grep 'llm_redact/user_guide.html'
|
|
376
|
+
tar -tzf dist/*.tar.gz | grep 'src/llm_redact/user_guide.md'
|
|
377
|
+
tar -tzf dist/*.tar.gz | grep 'src/llm_redact/user_guide.html'
|
|
378
|
+
python -m zipfile -l dist/*.whl | grep 'licenses/LICENSE'
|
|
379
|
+
tar -tzf dist/*.tar.gz | grep -x '[^/]*/LICENSE'
|
|
380
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
381
|
+
with:
|
|
382
|
+
name: dist
|
|
383
|
+
path: dist/
|
|
384
|
+
|
|
385
|
+
reproducible-build:
|
|
386
|
+
# Supply-chain assurance: two builds from the same tree with a pinned
|
|
387
|
+
# SOURCE_DATE_EPOCH must be byte-identical — a divergence means embedded
|
|
388
|
+
# timestamps/ordering crept in and the provenance story weakens. Out-dirs
|
|
389
|
+
# live OUTSIDE the workspace: the sdist packs the working tree, so a
|
|
390
|
+
# first build left inside it would poison the second (found the hard way).
|
|
391
|
+
name: reproducible build
|
|
392
|
+
runs-on: ubuntu-latest
|
|
393
|
+
steps:
|
|
394
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
395
|
+
with:
|
|
396
|
+
persist-credentials: false
|
|
397
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
398
|
+
with:
|
|
399
|
+
python-version: "3.13"
|
|
400
|
+
- name: build twice with a pinned epoch and compare byte-for-byte
|
|
401
|
+
run: |
|
|
402
|
+
export SOURCE_DATE_EPOCH=1704067200
|
|
403
|
+
uv build --out-dir "$RUNNER_TEMP/build-a"
|
|
404
|
+
uv build --out-dir "$RUNNER_TEMP/build-b"
|
|
405
|
+
status=0
|
|
406
|
+
for f in "$RUNNER_TEMP"/build-a/*; do
|
|
407
|
+
name="$(basename "$f")"
|
|
408
|
+
if cmp -s "$f" "$RUNNER_TEMP/build-b/$name"; then
|
|
409
|
+
echo "IDENTICAL: $name"
|
|
410
|
+
else
|
|
411
|
+
echo "DIFFERS: $name"
|
|
412
|
+
status=1
|
|
413
|
+
fi
|
|
414
|
+
done
|
|
415
|
+
exit "$status"
|
|
416
|
+
|
|
417
|
+
container-docker:
|
|
418
|
+
name: container (docker)
|
|
419
|
+
runs-on: ubuntu-latest
|
|
420
|
+
needs: test
|
|
421
|
+
steps:
|
|
422
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
423
|
+
with:
|
|
424
|
+
persist-credentials: false
|
|
425
|
+
- run: docker build --target runtime -t llm-redact:ci .
|
|
426
|
+
- run: docker build --target fake-upstream -t llm-redact-fake:ci .
|
|
427
|
+
- run: ./scripts/container_smoke.sh docker llm-redact:ci llm-redact-fake:ci
|
|
428
|
+
|
|
429
|
+
container-podman:
|
|
430
|
+
name: container (podman, rootless)
|
|
431
|
+
runs-on: ubuntu-latest
|
|
432
|
+
needs: test
|
|
433
|
+
steps:
|
|
434
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
435
|
+
with:
|
|
436
|
+
persist-credentials: false
|
|
437
|
+
- run: podman build --target runtime -t llm-redact:ci .
|
|
438
|
+
- run: podman build --target fake-upstream -t llm-redact-fake:ci .
|
|
439
|
+
- run: ./scripts/container_smoke.sh podman llm-redact:ci llm-redact-fake:ci
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: Live API smoke
|
|
2
|
+
|
|
3
|
+
# Manual only: sends real provider requests and spends API credits.
|
|
4
|
+
# Requires repo secrets ANTHROPIC_API_KEY and/or OPENAI_API_KEY.
|
|
5
|
+
# Never runs on pushes or pull requests.
|
|
6
|
+
on:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
dogfood:
|
|
10
|
+
description: "also run scripts/dogfood_claude.py (real claude CLI through the proxy)"
|
|
11
|
+
type: boolean
|
|
12
|
+
default: false
|
|
13
|
+
# Enable a weekly drift check after the first successful manual run:
|
|
14
|
+
# schedule:
|
|
15
|
+
# - cron: "17 6 * * 1"
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
live:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
25
|
+
with:
|
|
26
|
+
persist-credentials: false
|
|
27
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
28
|
+
with:
|
|
29
|
+
python-version: "3.13"
|
|
30
|
+
enable-cache: true
|
|
31
|
+
cache-dependency-glob: uv.lock
|
|
32
|
+
- run: uv sync --frozen
|
|
33
|
+
- run: uv run pytest -m live -rA tests/test_live.py
|
|
34
|
+
env:
|
|
35
|
+
LLM_REDACT_LIVE: "1"
|
|
36
|
+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
37
|
+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
38
|
+
|
|
39
|
+
dogfood:
|
|
40
|
+
# The full production loop: the real claude CLI driven through a real
|
|
41
|
+
# proxy subprocess. Opt-in via the dispatch input; needs ANTHROPIC_API_KEY.
|
|
42
|
+
if: inputs.dogfood
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
46
|
+
with:
|
|
47
|
+
persist-credentials: false
|
|
48
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
49
|
+
with:
|
|
50
|
+
python-version: "3.13"
|
|
51
|
+
enable-cache: true
|
|
52
|
+
cache-dependency-glob: uv.lock
|
|
53
|
+
- uses: actions/setup-node@395ad3262231945d0d5e35de6a4a55fcec1502e4 # v6
|
|
54
|
+
with:
|
|
55
|
+
node-version: 22
|
|
56
|
+
# Pinned to the version the harness was verified against; bump
|
|
57
|
+
# deliberately. (Manual opt-in job, so no lockfile to anchor to.)
|
|
58
|
+
- run: npm install -g @anthropic-ai/claude-code@2.1.203
|
|
59
|
+
- run: uv sync --frozen
|
|
60
|
+
- run: uv run python scripts/dogfood_claude.py
|
|
61
|
+
env:
|
|
62
|
+
LLM_REDACT_DOGFOOD: "1"
|
|
63
|
+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|