rag-security-protocol 0.1.1rc1__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.
- rag_security_protocol-0.1.1rc1/.coderabbit.yaml +107 -0
- rag_security_protocol-0.1.1rc1/.gitattributes +5 -0
- rag_security_protocol-0.1.1rc1/.github/workflows/ci.yml +71 -0
- rag_security_protocol-0.1.1rc1/.github/workflows/plugins.yml +191 -0
- rag_security_protocol-0.1.1rc1/.github/workflows/publish.yml +49 -0
- rag_security_protocol-0.1.1rc1/.gitignore +19 -0
- rag_security_protocol-0.1.1rc1/.python-version +1 -0
- rag_security_protocol-0.1.1rc1/AGENTS.md +104 -0
- rag_security_protocol-0.1.1rc1/LICENSE +201 -0
- rag_security_protocol-0.1.1rc1/PKG-INFO +132 -0
- rag_security_protocol-0.1.1rc1/README.md +106 -0
- rag_security_protocol-0.1.1rc1/SPEC.md +362 -0
- rag_security_protocol-0.1.1rc1/WRITING-A-PLUGIN.md +145 -0
- rag_security_protocol-0.1.1rc1/codecov.yml +14 -0
- rag_security_protocol-0.1.1rc1/conformance/README.md +59 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/README.md +47 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/aws-key.json +4 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/clean.json +4 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/non-ascii-prefix.json +4 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/placeholder-is-not-a-secret.json +4 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/span-across-lines.json +4 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/span-on-a-later-line.json +4 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/wrapper-version-in-handshake.json +5 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/handshake.json +15 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-byte-order-mark-is-not-whitespace.json +10 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-doubled-backslash-is-not-an-escape.json +12 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-leading-zero-is-not-a-number.json +10 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-malformed-number-under-an-unread-field.json +10 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-repeated-key-inside-metadata.json +10 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-repeated-key-no-plugin-reads.json +10 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-repeated-key-written-with-an-escape.json +10 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-an-integer-above-the-safe-range-is-refused.json +10 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-an-unpaired-surrogate-in-a-key.json +10 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-an-unpaired-surrogate-is-refused.json +10 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-digits-in-the-content-are-not-numbers.json +12 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-duplicate-keys-are-refused.json +10 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-nan-is-not-a-number.json +10 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-sibling-objects-may-repeat-a-key.json +12 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-the-safe-range-includes-its-edges.json +12 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/metadata-a-plugin-does-not-read.json +12 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/metadata-is-advisory.json +15 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/spans-are-utf8-bytes.json +15 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/spans-multiple-occurrences.json +18 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/stdout-is-protocol-only.json +17 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/unknown-fields-ignored.json +14 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/verdict-allow.json +16 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/verdict-block.json +7 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/verdict-flag.json +7 -0
- rag_security_protocol-0.1.1rc1/conformance/cases/verdict-redact.json +15 -0
- rag_security_protocol-0.1.1rc1/conformance/harness.py +107 -0
- rag_security_protocol-0.1.1rc1/conformance/host/error-a-crash-blocks.json +5 -0
- rag_security_protocol-0.1.1rc1/conformance/host/error-a-flood-blocks.json +5 -0
- rag_security_protocol-0.1.1rc1/conformance/host/error-a-hang-times-out.json +5 -0
- rag_security_protocol-0.1.1rc1/conformance/host/error-noisy-diagnostics-are-not-an-error.json +6 -0
- rag_security_protocol-0.1.1rc1/conformance/host/error-on-error-allow-lets-it-through.json +5 -0
- rag_security_protocol-0.1.1rc1/conformance/host/error-silence-blocks.json +5 -0
- rag_security_protocol-0.1.1rc1/conformance/host/error-unparseable-output-blocks.json +5 -0
- rag_security_protocol-0.1.1rc1/conformance/host/hooks-an-undeclared-hook-is-not-called.json +6 -0
- rag_security_protocol-0.1.1rc1/conformance/host/json-a-bom-is-not-whitespace.json +19 -0
- rag_security_protocol-0.1.1rc1/conformance/host/json-a-host-does-not-send-what-it-refuses.json +23 -0
- rag_security_protocol-0.1.1rc1/conformance/host/json-deep-nesting-is-an-error.json +19 -0
- rag_security_protocol-0.1.1rc1/conformance/host/json-duplicate-keys.json +19 -0
- rag_security_protocol-0.1.1rc1/conformance/host/json-framing-whitespace-is-the-rfc-s.json +19 -0
- rag_security_protocol-0.1.1rc1/conformance/host/json-huge-integers.json +19 -0
- rag_security_protocol-0.1.1rc1/conformance/host/json-lone-surrogates.json +19 -0
- rag_security_protocol-0.1.1rc1/conformance/host/json-nan-is-not-a-number.json +19 -0
- rag_security_protocol-0.1.1rc1/conformance/host/json-number-syntax-is-the-rfc-s.json +19 -0
- rag_security_protocol-0.1.1rc1/conformance/host/spans-adjacent-coalesce.json +5 -0
- rag_security_protocol-0.1.1rc1/conformance/host/spans-every-plugin-sees-the-original.json +46 -0
- rag_security_protocol-0.1.1rc1/conformance/host/spans-inside-a-character-is-refused.json +5 -0
- rag_security_protocol-0.1.1rc1/conformance/host/spans-out-of-range-is-refused.json +5 -0
- rag_security_protocol-0.1.1rc1/conformance/host/spans-overlapping-coalesce.json +5 -0
- rag_security_protocol-0.1.1rc1/conformance/host/spans-the-severest-replacement-wins.json +8 -0
- rag_security_protocol-0.1.1rc1/conformance/host/transport-two-objects-is-not-an-answer.json +18 -0
- rag_security_protocol-0.1.1rc1/conformance/host/verdicts-a-block-carries-its-reason.json +23 -0
- rag_security_protocol-0.1.1rc1/conformance/host/verdicts-an-unknown-severity-ranks-lowest.json +45 -0
- rag_security_protocol-0.1.1rc1/conformance/run.py +90 -0
- rag_security_protocol-0.1.1rc1/demo/README.md +47 -0
- rag_security_protocol-0.1.1rc1/demo/rsp.toml +3 -0
- rag_security_protocol-0.1.1rc1/demo/sample-docs/architecture.md +16 -0
- rag_security_protocol-0.1.1rc1/demo/sample-docs/deploy-notes.md +14 -0
- rag_security_protocol-0.1.1rc1/demo/sample-docs/faq.md +31 -0
- rag_security_protocol-0.1.1rc1/demo/sample-docs/meeting-2026-03-11.md +20 -0
- rag_security_protocol-0.1.1rc1/demo/sample-docs/onboarding.md +21 -0
- rag_security_protocol-0.1.1rc1/demo/sample-docs/runbook-backups.md +22 -0
- rag_security_protocol-0.1.1rc1/demo/sample-docs/runbook-oncall.md +29 -0
- rag_security_protocol-0.1.1rc1/demo/sample-docs/vector-store.md +28 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/Makefile +25 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/README.md +65 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/conformance.json +3 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/gitleaks.c +129 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/gitleaks.h +27 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/main.c +87 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/protocol.c +106 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/protocol.h +24 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/spawn.c +135 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/spawn.h +17 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/strict.c +69 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/strict.h +18 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/test_gitleaks.c +123 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/testdata/delivery.sh +42 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-c/testdata/requests.sh +25 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-go/.gitignore +3 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-go/README.md +30 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-go/conformance.json +3 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-go/gitleaks.go +136 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-go/gitleaks_test.go +76 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-go/go.mod +5 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-go/main.go +35 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-go/protocol.go +76 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-go/protocol_test.go +135 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-go/strictjson.go +159 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-java/Makefile +42 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-java/README.md +61 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-java/conformance.json +3 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-java/src/Gitleaks.java +98 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-java/src/Main.java +24 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-java/src/Protocol.java +70 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-java/src/Spans.java +93 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-java/src/StrictJson.java +134 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-java/test/GitleaksTest.java +85 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-java/testdata/requests.sh +45 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-offsets.json +295 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-offsets.schema.json +81 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-py/README.md +47 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-py/conformance.json +3 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-py/conftest.py +9 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-py/gitleaks.py +121 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-py/main.py +30 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-py/protocol.py +55 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-py/strictjson.py +51 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-py/tests/test_gitleaks.py +69 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-py/tests/test_protocol.py +135 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/.gitignore +1 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/Cargo.lock +107 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/Cargo.toml +17 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/README.md +39 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/conformance.json +3 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/src/gitleaks.rs +105 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/src/lib.rs +9 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/src/main.rs +26 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/src/protocol.rs +60 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/src/spans.rs +63 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/src/strictjson.rs +109 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/tests/gitleaks.rs +120 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/tests/protocol.rs +135 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/.gitignore +1 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Makefile +13 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Package.swift +21 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/README.md +64 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/Adapter/Finding.swift +34 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/Adapter/Gitleaks.swift +84 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/Adapter/Protocol.swift +98 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/Adapter/Spans.swift +64 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/Adapter/StrictJson.swift +143 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/offset-test/main.swift +85 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/rsp-gitleaks-swift/main.swift +26 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/conformance.json +4 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/testdata/requests.sh +45 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/.gitignore +1 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/README.md +24 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/conformance.json +3 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/package-lock.json +54 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/package.json +21 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/src/gitleaks.ts +133 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/src/main.ts +13 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/src/protocol.ts +58 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/src/strictjson.ts +107 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/test/binary.test.ts +42 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/test/gitleaks.test.ts +57 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/test/protocol.test.ts +128 -0
- rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/tsconfig.json +14 -0
- rag_security_protocol-0.1.1rc1/examples/host/README.md +74 -0
- rag_security_protocol-0.1.1rc1/examples/host/docs/deploy-notes.md +7 -0
- rag_security_protocol-0.1.1rc1/examples/host/docs/mirror-credentials.md +9 -0
- rag_security_protocol-0.1.1rc1/examples/host/docs/onboarding.md +7 -0
- rag_security_protocol-0.1.1rc1/examples/host/docs/runbook-incident.md +7 -0
- rag_security_protocol-0.1.1rc1/examples/host/main.py +111 -0
- rag_security_protocol-0.1.1rc1/examples/host/rsp.toml +13 -0
- rag_security_protocol-0.1.1rc1/examples/testdata/fake-gitleaks.sh +25 -0
- rag_security_protocol-0.1.1rc1/examples/testdata/loud-gitleaks.sh +7 -0
- rag_security_protocol-0.1.1rc1/plugins/rsp-echo/conformance.json +3 -0
- rag_security_protocol-0.1.1rc1/plugins/rsp-echo/main.py +78 -0
- rag_security_protocol-0.1.1rc1/plugins/rsp-echo/strictjson.py +54 -0
- rag_security_protocol-0.1.1rc1/plugins/rsp-replay/main.py +87 -0
- rag_security_protocol-0.1.1rc1/pyproject.toml +78 -0
- rag_security_protocol-0.1.1rc1/rsp/__init__.py +0 -0
- rag_security_protocol-0.1.1rc1/rsp/cli.py +80 -0
- rag_security_protocol-0.1.1rc1/rsp/codec.py +167 -0
- rag_security_protocol-0.1.1rc1/rsp/config.py +146 -0
- rag_security_protocol-0.1.1rc1/rsp/guards.py +91 -0
- rag_security_protocol-0.1.1rc1/rsp/handshake.py +77 -0
- rag_security_protocol-0.1.1rc1/rsp/ingest.py +153 -0
- rag_security_protocol-0.1.1rc1/rsp/process.py +183 -0
- rag_security_protocol-0.1.1rc1/rsp/py.typed +0 -0
- rag_security_protocol-0.1.1rc1/rsp/runtime.py +273 -0
- rag_security_protocol-0.1.1rc1/rsp/spans.py +112 -0
- rag_security_protocol-0.1.1rc1/tests/conftest.py +31 -0
- rag_security_protocol-0.1.1rc1/tests/plugins.py +152 -0
- rag_security_protocol-0.1.1rc1/tests/test_codec.py +181 -0
- rag_security_protocol-0.1.1rc1/tests/test_composition.py +295 -0
- rag_security_protocol-0.1.1rc1/tests/test_config.py +213 -0
- rag_security_protocol-0.1.1rc1/tests/test_conformance.py +103 -0
- rag_security_protocol-0.1.1rc1/tests/test_corpus.py +248 -0
- rag_security_protocol-0.1.1rc1/tests/test_demo.py +322 -0
- rag_security_protocol-0.1.1rc1/tests/test_example_host.py +124 -0
- rag_security_protocol-0.1.1rc1/tests/test_guards.py +190 -0
- rag_security_protocol-0.1.1rc1/tests/test_guide.py +135 -0
- rag_security_protocol-0.1.1rc1/tests/test_handshake.py +82 -0
- rag_security_protocol-0.1.1rc1/tests/test_host_conformance.py +108 -0
- rag_security_protocol-0.1.1rc1/tests/test_kit.py +136 -0
- rag_security_protocol-0.1.1rc1/tests/test_offset_table.py +90 -0
- rag_security_protocol-0.1.1rc1/tests/test_runtime.py +218 -0
- rag_security_protocol-0.1.1rc1/tests/test_spans.py +122 -0
- rag_security_protocol-0.1.1rc1/tests/test_spec_drift.py +367 -0
- rag_security_protocol-0.1.1rc1/uv.lock +2679 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# yaml-language-server: $schema=https://storage.googleapis.com/coderabbit_public_assets/schema.v2.json
|
|
2
|
+
# The standards live in AGENTS.md, which CodeRabbit reads on its own. Path
|
|
3
|
+
# instructions add only what is specific to a path; add one when a review misses it.
|
|
4
|
+
|
|
5
|
+
language: 'en-US'
|
|
6
|
+
|
|
7
|
+
# 250 char limit.
|
|
8
|
+
tone_instructions: >-
|
|
9
|
+
Be terse and concrete. One sentence per finding, naming the failure. No praise,
|
|
10
|
+
no summarising what the diff does, no restating a rule without applying it. If
|
|
11
|
+
the diff is clean, say so and stop.
|
|
12
|
+
|
|
13
|
+
reviews:
|
|
14
|
+
profile: 'chill'
|
|
15
|
+
poem: false
|
|
16
|
+
high_level_summary: true
|
|
17
|
+
request_changes_workflow: false
|
|
18
|
+
|
|
19
|
+
auto_review:
|
|
20
|
+
enabled: true
|
|
21
|
+
drafts: false
|
|
22
|
+
|
|
23
|
+
path_instructions:
|
|
24
|
+
- path: 'rsp/**/*.py'
|
|
25
|
+
instructions: >-
|
|
26
|
+
The two that matter most here: every error path must end in BLOCK unless
|
|
27
|
+
a per-plugin on_error says otherwise, and a plugin-supplied span must be
|
|
28
|
+
validated (in range, start <= end, on a UTF-8 boundary) before anything
|
|
29
|
+
slices with it.
|
|
30
|
+
|
|
31
|
+
- path: 'rsp/guards.py'
|
|
32
|
+
instructions: >-
|
|
33
|
+
Under 80 lines of code and no detection logic.
|
|
34
|
+
|
|
35
|
+
- path: '{plugins,examples}/**'
|
|
36
|
+
instructions: >-
|
|
37
|
+
Adapters wrap unmodified upstream binaries and contain no detection
|
|
38
|
+
logic — flag any the wrapped tool already performs. Under 80 lines of
|
|
39
|
+
code, except where a brace-per-line language pays for syntax rather
|
|
40
|
+
than behaviour. One JSON object on stdout per call; diagnostics on
|
|
41
|
+
stderr.
|
|
42
|
+
|
|
43
|
+
- path: 'examples/**/*.ts'
|
|
44
|
+
instructions: >-
|
|
45
|
+
Position arithmetic must produce byte offsets into the UTF-8 encoding of
|
|
46
|
+
the content, never string indices — flag any use of .length, .slice, or
|
|
47
|
+
.indexOf on a string where an offset is being computed. The conversion
|
|
48
|
+
functions must stay callable without the wrapped binary installed.
|
|
49
|
+
|
|
50
|
+
- path: 'SPEC.md'
|
|
51
|
+
instructions: >-
|
|
52
|
+
Flag any new MUST without a conformance fixture in the same PR, and any
|
|
53
|
+
clause without a Rationale.
|
|
54
|
+
|
|
55
|
+
tools:
|
|
56
|
+
# One entry per language present in the tree. The LLM review is
|
|
57
|
+
# language-agnostic; these are not.
|
|
58
|
+
ruff:
|
|
59
|
+
enabled: true # skipped automatically once ruff runs in CI
|
|
60
|
+
oxc:
|
|
61
|
+
enabled: true # TypeScript, no config file of its own to keep
|
|
62
|
+
biome:
|
|
63
|
+
enabled: true
|
|
64
|
+
eslint:
|
|
65
|
+
enabled: false # would mean an eslint config and a dev dependency
|
|
66
|
+
# for a hundred lines of example code
|
|
67
|
+
shellcheck:
|
|
68
|
+
enabled: true
|
|
69
|
+
actionlint:
|
|
70
|
+
enabled: true
|
|
71
|
+
zizmor:
|
|
72
|
+
enabled: true
|
|
73
|
+
yamllint:
|
|
74
|
+
enabled: true
|
|
75
|
+
gitleaks:
|
|
76
|
+
enabled: true # the demo corpus will carry fabricated secrets
|
|
77
|
+
languagetool:
|
|
78
|
+
enabled: false # prose nitpicks on a doc-heavy repo
|
|
79
|
+
markdownlint:
|
|
80
|
+
enabled: false
|
|
81
|
+
|
|
82
|
+
pre_merge_checks:
|
|
83
|
+
# A coverage threshold asks for more docstrings; AGENTS.md's Style asks for fewer.
|
|
84
|
+
docstrings:
|
|
85
|
+
mode: 'off'
|
|
86
|
+
|
|
87
|
+
custom_checks:
|
|
88
|
+
- name: 'Fail closed'
|
|
89
|
+
mode: 'warning'
|
|
90
|
+
instructions: >-
|
|
91
|
+
If this PR adds or changes an error path in rsp/ — an except handler, a
|
|
92
|
+
timeout branch, a parse failure, a size cap — verify it results in
|
|
93
|
+
BLOCK unless an explicit per-plugin on_error setting says otherwise.
|
|
94
|
+
Report a failure naming the file and line if such a path results in
|
|
95
|
+
ALLOW, skips the plugin silently, or lets the exception escape.
|
|
96
|
+
Scope: an error path is one that makes a response untrustworthy, per
|
|
97
|
+
SPEC.md E3. Failures that cost only diagnostics — an unreadable or
|
|
98
|
+
truncated stderr — are not error paths, and code that lets them pass
|
|
99
|
+
is correct, not a finding.
|
|
100
|
+
|
|
101
|
+
- name: 'MUST has a fixture'
|
|
102
|
+
mode: 'warning'
|
|
103
|
+
instructions: >-
|
|
104
|
+
If this PR adds or modifies a MUST, MUST NOT, or SHALL clause in
|
|
105
|
+
SPEC.md, verify the same PR adds or updates a conformance case under
|
|
106
|
+
conformance/cases/ that exercises it. Report a failure naming each
|
|
107
|
+
clause left without one.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Linguist counts examples/ as documentation and leaves it out of the language
|
|
2
|
+
# bar. Here the six adapters under it are implementations: the conformance kit
|
|
3
|
+
# runs them as plugins, and the claim this repository makes is that a plugin is
|
|
4
|
+
# a command in any language. A bar reading 100% Python says the opposite.
|
|
5
|
+
examples/** linguist-documentation=false
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
# nltk, which the sentence splitter pulls in, refuses the hardlinks uv makes by default.
|
|
11
|
+
env:
|
|
12
|
+
UV_LINK_MODE: copy
|
|
13
|
+
|
|
14
|
+
# A third party's action is pinned to a hash: whoever can move its tag can run
|
|
15
|
+
# code with this job's token. GitHub's own are pinned to a major tag (AGENTS.md).
|
|
16
|
+
|
|
17
|
+
concurrency:
|
|
18
|
+
group: ci-${{ github.ref }}
|
|
19
|
+
cancel-in-progress: true
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
lint:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v5
|
|
26
|
+
with:
|
|
27
|
+
# Nothing pushes, so the token is not left behind in .git/config.
|
|
28
|
+
persist-credentials: false
|
|
29
|
+
- uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.0.1
|
|
30
|
+
with:
|
|
31
|
+
enable-cache: true
|
|
32
|
+
# --frozen fails when uv.lock is out of date with pyproject.toml.
|
|
33
|
+
- run: uv sync --frozen
|
|
34
|
+
- run: uv run ruff check rsp/ tests/ plugins/ conformance/ examples/gitleaks-py/ examples/host/
|
|
35
|
+
- run: uv run ruff format --check rsp/ tests/ plugins/ conformance/ examples/gitleaks-py/ examples/host/
|
|
36
|
+
|
|
37
|
+
# actionlint for expression and matrix mistakes, zizmor for workflow security.
|
|
38
|
+
- run: uvx --from actionlint-py==1.7.12.24 actionlint .github/workflows/*.yml
|
|
39
|
+
- run: uvx zizmor==1.9.0 --persona=regular .github/workflows/
|
|
40
|
+
|
|
41
|
+
test:
|
|
42
|
+
strategy:
|
|
43
|
+
fail-fast: false
|
|
44
|
+
matrix:
|
|
45
|
+
# From the floor in pyproject.toml to whatever is current.
|
|
46
|
+
python: ["3.11", "3.12", "3.13", "3.14"]
|
|
47
|
+
os: [ubuntu-latest]
|
|
48
|
+
# One macOS job: process groups and pipe buffers (16 KiB, not 64) differ from Linux.
|
|
49
|
+
include:
|
|
50
|
+
- python: "3.12"
|
|
51
|
+
os: macos-latest
|
|
52
|
+
runs-on: ${{ matrix.os }}
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v5
|
|
55
|
+
with:
|
|
56
|
+
persist-credentials: false
|
|
57
|
+
- uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.0.1
|
|
58
|
+
with:
|
|
59
|
+
enable-cache: true
|
|
60
|
+
python-version: ${{ matrix.python }}
|
|
61
|
+
- run: uv sync --frozen
|
|
62
|
+
# Unit tests, conformance cases and drift checks are all pytest.
|
|
63
|
+
- run: uv run pytest tests/ examples/gitleaks-py/ -q --cov --cov-report=xml
|
|
64
|
+
|
|
65
|
+
# One upload: coverage does not differ across the matrix.
|
|
66
|
+
- if: matrix.os == 'ubuntu-latest' && matrix.python == '3.12'
|
|
67
|
+
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
|
|
68
|
+
with:
|
|
69
|
+
files: coverage.xml
|
|
70
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
71
|
+
fail_ci_if_error: false
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
name: Plugins
|
|
2
|
+
|
|
3
|
+
# Separate from CI, and scheduled, because a failure here can mean upstream changed:
|
|
4
|
+
# gitleaks retiring a rule changes a verdict without any pull request.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [main]
|
|
9
|
+
paths: &paths
|
|
10
|
+
- "examples/**"
|
|
11
|
+
- "conformance/**"
|
|
12
|
+
- "tests/**"
|
|
13
|
+
# The suite runs the host too.
|
|
14
|
+
- "rsp/**"
|
|
15
|
+
- "pyproject.toml"
|
|
16
|
+
- "SPEC.md"
|
|
17
|
+
- ".github/workflows/plugins.yml"
|
|
18
|
+
pull_request:
|
|
19
|
+
paths: *paths
|
|
20
|
+
schedule:
|
|
21
|
+
- cron: "23 5 * * 1"
|
|
22
|
+
workflow_dispatch:
|
|
23
|
+
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
|
|
27
|
+
concurrency:
|
|
28
|
+
group: plugins-${{ github.ref }}
|
|
29
|
+
cancel-in-progress: true
|
|
30
|
+
|
|
31
|
+
env:
|
|
32
|
+
# One pin for the binary and for the test corpus in its source archive.
|
|
33
|
+
GITLEAKS_VERSION: 8.30.1
|
|
34
|
+
UV_LINK_MODE: copy # see ci.yml
|
|
35
|
+
|
|
36
|
+
jobs:
|
|
37
|
+
gitleaks:
|
|
38
|
+
# One job for every adapter over this binary: the cases are shared, and
|
|
39
|
+
# disagreement is the finding. Two OSes, because the binary and the pipe differ.
|
|
40
|
+
strategy:
|
|
41
|
+
fail-fast: false
|
|
42
|
+
matrix:
|
|
43
|
+
include:
|
|
44
|
+
- runner: ubuntu-latest
|
|
45
|
+
platform: linux_x64
|
|
46
|
+
- runner: macos-latest
|
|
47
|
+
platform: darwin_arm64
|
|
48
|
+
runs-on: ${{ matrix.runner }}
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/checkout@v5
|
|
51
|
+
with:
|
|
52
|
+
persist-credentials: false
|
|
53
|
+
- uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.0.1
|
|
54
|
+
with:
|
|
55
|
+
enable-cache: true
|
|
56
|
+
# The image supplied Node 22, where the test runner rejected a directory.
|
|
57
|
+
- uses: actions/setup-node@v6
|
|
58
|
+
with:
|
|
59
|
+
node-version: '24'
|
|
60
|
+
cache: npm
|
|
61
|
+
cache-dependency-path: examples/gitleaks-ts/package-lock.json
|
|
62
|
+
- uses: actions/setup-go@v7
|
|
63
|
+
with:
|
|
64
|
+
go-version: '1.24'
|
|
65
|
+
cache: false # stdlib only, so there is no go.sum to key on
|
|
66
|
+
|
|
67
|
+
- name: Install gitleaks
|
|
68
|
+
run: |
|
|
69
|
+
set -euo pipefail
|
|
70
|
+
base="https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}"
|
|
71
|
+
asset="gitleaks_${GITLEAKS_VERSION}_${{ matrix.platform }}.tar.gz"
|
|
72
|
+
sums="gitleaks_${GITLEAKS_VERSION}_checksums.txt"
|
|
73
|
+
curl -sSfLO "${base}/${asset}"
|
|
74
|
+
curl -sSfLO "${base}/${sums}"
|
|
75
|
+
grep " ${asset}\$" "${sums}" | shasum -a 256 --check --strict -
|
|
76
|
+
tar -xzf "${asset}" gitleaks
|
|
77
|
+
sudo install -m 755 gitleaks /usr/local/bin/gitleaks
|
|
78
|
+
gitleaks version
|
|
79
|
+
|
|
80
|
+
- name: Unit tests and types
|
|
81
|
+
working-directory: examples/gitleaks-ts
|
|
82
|
+
run: |
|
|
83
|
+
npm ci
|
|
84
|
+
npm run typecheck
|
|
85
|
+
npm test
|
|
86
|
+
|
|
87
|
+
# Built once, not `go run` per call: the corpus suite calls it four hundred times.
|
|
88
|
+
- name: Build and test the Go plugin
|
|
89
|
+
working-directory: examples/gitleaks-go
|
|
90
|
+
run: |
|
|
91
|
+
test -z "$(gofmt -l .)"
|
|
92
|
+
go vet ./...
|
|
93
|
+
# -count=1: the offset table lives outside this module, so the cache misses changes.
|
|
94
|
+
go test -count=1 ./...
|
|
95
|
+
go build -o "${RUNNER_TEMP}/rsp-gitleaks-go" .
|
|
96
|
+
|
|
97
|
+
- uses: actions/setup-java@v4
|
|
98
|
+
with:
|
|
99
|
+
distribution: temurin
|
|
100
|
+
java-version: '21'
|
|
101
|
+
|
|
102
|
+
# Keyed on the Makefile, which holds both the version and the checksum:
|
|
103
|
+
# a jar restored from this cache meets the same check a fetched one does,
|
|
104
|
+
# and a rate-limited Maven Central has failed this job once already.
|
|
105
|
+
- uses: actions/cache@v6
|
|
106
|
+
with:
|
|
107
|
+
path: examples/gitleaks-java/lib
|
|
108
|
+
key: gson-${{ hashFiles('examples/gitleaks-java/Makefile') }}
|
|
109
|
+
|
|
110
|
+
# gson is pinned and checksummed by the Makefile, the way this job pins
|
|
111
|
+
# gitleaks: Java has no JSON in its standard library either.
|
|
112
|
+
- name: Build and test the Java plugin
|
|
113
|
+
working-directory: examples/gitleaks-java
|
|
114
|
+
run: make test
|
|
115
|
+
|
|
116
|
+
# macOS only, and the manifest says so rather than this file: the
|
|
117
|
+
# runner ships Swift, while Linux would mean a 748MB tarball or
|
|
118
|
+
# swift-actions/setup-swift, whose key import is currently broken
|
|
119
|
+
# upstream. What Swift demonstrates — that the byte discipline can be
|
|
120
|
+
# the compiler's — it demonstrates on one platform, and the tests
|
|
121
|
+
# skipping elsewhere say which reason it was.
|
|
122
|
+
- name: Build and test the Swift plugin
|
|
123
|
+
if: runner.os == 'macOS'
|
|
124
|
+
working-directory: examples/gitleaks-swift
|
|
125
|
+
run: make test
|
|
126
|
+
|
|
127
|
+
- name: Install cJSON
|
|
128
|
+
run: |
|
|
129
|
+
if [ "$RUNNER_OS" = "Linux" ]; then
|
|
130
|
+
sudo apt-get update && sudo apt-get install -y libcjson-dev
|
|
131
|
+
else
|
|
132
|
+
brew install cjson
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
# Twice: once as it ships, once under the sanitizers. Refusing a Match
|
|
136
|
+
# shorter than its span is memory safety, not behaviour, so no assertion
|
|
137
|
+
# here can see it go — ASan can.
|
|
138
|
+
- name: Build and test the C plugin
|
|
139
|
+
working-directory: examples/gitleaks-c
|
|
140
|
+
run: |
|
|
141
|
+
make test
|
|
142
|
+
make clean
|
|
143
|
+
make CFLAGS="-O1 -g -std=c11 -Wall -Wextra -Werror -fsanitize=address,undefined $EXTRA_I" \
|
|
144
|
+
LDFLAGS="-fsanitize=address,undefined $EXTRA_L" test
|
|
145
|
+
make clean
|
|
146
|
+
make rsp-gitleaks-c
|
|
147
|
+
env:
|
|
148
|
+
EXTRA_I: ${{ runner.os == 'macOS' && '-I/opt/homebrew/include' || '' }}
|
|
149
|
+
EXTRA_L: ${{ runner.os == 'macOS' && '-L/opt/homebrew/lib' || '' }}
|
|
150
|
+
|
|
151
|
+
# Release build: a debug build spends longer starting than scanning.
|
|
152
|
+
- name: Build and test the Rust plugin
|
|
153
|
+
working-directory: examples/gitleaks-rs
|
|
154
|
+
run: |
|
|
155
|
+
cargo fmt --check
|
|
156
|
+
cargo clippy --all-targets -- -D warnings
|
|
157
|
+
cargo test
|
|
158
|
+
cargo build --release
|
|
159
|
+
cp target/release/rsp-gitleaks-rs "${RUNNER_TEMP}/rsp-gitleaks-rs"
|
|
160
|
+
|
|
161
|
+
# Other people's test secrets, kept out of the checkout.
|
|
162
|
+
- name: Fetch the corpus
|
|
163
|
+
run: |
|
|
164
|
+
set -euo pipefail
|
|
165
|
+
mkdir -p "${RUNNER_TEMP}/corpus"
|
|
166
|
+
curl -sSfL \
|
|
167
|
+
"https://github.com/gitleaks/gitleaks/archive/refs/tags/v${GITLEAKS_VERSION}.tar.gz" \
|
|
168
|
+
| tar -xz -C "${RUNNER_TEMP}/corpus" --strip-components=2 \
|
|
169
|
+
"gitleaks-${GITLEAKS_VERSION}/testdata"
|
|
170
|
+
find "${RUNNER_TEMP}/corpus" -type f | wc -l
|
|
171
|
+
|
|
172
|
+
# The Python adapter needs no build step, but `pytest tests/` does not
|
|
173
|
+
# reach examples/, so it is named rather than assumed.
|
|
174
|
+
# Nothing skips here, so this is the only run of every clause against every plugin.
|
|
175
|
+
- name: Every case, every tool present
|
|
176
|
+
run: uv run --frozen pytest tests/ examples/gitleaks-py/ -q --html=report.html --self-contained-html
|
|
177
|
+
env:
|
|
178
|
+
RSP_REQUIRE_ALL_PLUGINS: "1"
|
|
179
|
+
RSP_GITLEAKS_CORPUS: ${{ runner.temp }}/corpus
|
|
180
|
+
RSP_PLUGIN_GITLEAKS_GO: ${{ runner.temp }}/rsp-gitleaks-go
|
|
181
|
+
RSP_PLUGIN_GITLEAKS_RS: ${{ runner.temp }}/rsp-gitleaks-rs
|
|
182
|
+
RSP_PLUGIN_GITLEAKS_C: ${{ github.workspace }}/examples/gitleaks-c/rsp-gitleaks-c
|
|
183
|
+
RSP_PLUGIN_GITLEAKS_JAVA: ${{ github.workspace }}/examples/gitleaks-java/rsp-gitleaks-java
|
|
184
|
+
RSP_PLUGIN_GITLEAKS_SWIFT: ${{ github.workspace }}/examples/gitleaks-swift/.build/release/rsp-gitleaks-swift
|
|
185
|
+
|
|
186
|
+
# always(): a failed run's report is the one worth reading. One OS is enough.
|
|
187
|
+
- if: always() && matrix.runner == 'ubuntu-latest'
|
|
188
|
+
uses: actions/upload-artifact@v7
|
|
189
|
+
with:
|
|
190
|
+
name: conformance-report
|
|
191
|
+
path: report.html
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Publishing is a tag push, and the tag is the only trigger: a release that can
|
|
2
|
+
# be made by hand is a release whose contents nobody can derive from the tree.
|
|
3
|
+
name: Publish
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags: ["v*"]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
env:
|
|
13
|
+
UV_LINK_MODE: copy # see ci.yml
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
publish:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
environment: pypi
|
|
19
|
+
permissions:
|
|
20
|
+
# Restated, because a job's block replaces the workflow's rather than
|
|
21
|
+
# adding to it, and checkout would be left reading a public repository
|
|
22
|
+
# only by its being public.
|
|
23
|
+
contents: read
|
|
24
|
+
# Trusted publishing: PyPI verifies this run, so no token is stored here.
|
|
25
|
+
id-token: write
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v5
|
|
28
|
+
with:
|
|
29
|
+
persist-credentials: false
|
|
30
|
+
- uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.0.1
|
|
31
|
+
with:
|
|
32
|
+
# A cache another run could have written has no business deciding
|
|
33
|
+
# what goes to PyPI.
|
|
34
|
+
enable-cache: false
|
|
35
|
+
|
|
36
|
+
# The suite before the upload, because a published version cannot be taken
|
|
37
|
+
# back — PyPI refuses a reused filename even after a delete.
|
|
38
|
+
- run: uv sync --frozen --extra llamaindex
|
|
39
|
+
- run: uv run --frozen pytest tests/ examples/gitleaks-py/ -q
|
|
40
|
+
|
|
41
|
+
- name: The tag and the version must be the same release
|
|
42
|
+
run: |
|
|
43
|
+
set -euo pipefail
|
|
44
|
+
declared=$(uv run --frozen python -c 'import tomllib; print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])')
|
|
45
|
+
tagged=${GITHUB_REF_NAME#v}
|
|
46
|
+
test "$declared" = "$tagged" || { echo "pyproject says $declared, the tag says $tagged"; exit 1; }
|
|
47
|
+
|
|
48
|
+
- run: uv build
|
|
49
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
.coverage
|
|
5
|
+
coverage.xml
|
|
6
|
+
.ruff_cache/
|
|
7
|
+
.pytest_cache/
|
|
8
|
+
report.html
|
|
9
|
+
|
|
10
|
+
# Build output. Committed once by a `git add -A` after a branch switch took
|
|
11
|
+
# the .gitignore that had been covering it, so the rule lives here now, where
|
|
12
|
+
# no checkout can remove it while the artefacts remain.
|
|
13
|
+
*.o
|
|
14
|
+
examples/gitleaks-c/rsp-gitleaks-c
|
|
15
|
+
examples/gitleaks-c/test-gitleaks
|
|
16
|
+
examples/gitleaks-java/classes/
|
|
17
|
+
examples/gitleaks-java/lib/
|
|
18
|
+
examples/gitleaks-java/rsp-gitleaks-java
|
|
19
|
+
examples/gitleaks-swift/.build/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
RSP is a protocol. `SPEC.md` is the deliverable; the code is evidence that it
|
|
4
|
+
works. Decisions (D1–D9) and open questions (Q1–Q8) are in the
|
|
5
|
+
[wiki](https://github.com/PCBZ/rsp/wiki) — cite them by number, don't re-argue them.
|
|
6
|
+
|
|
7
|
+
## Layout
|
|
8
|
+
|
|
9
|
+
Each layer knows strictly less than the one above it, and the imports go one way.
|
|
10
|
+
|
|
11
|
+
- `rsp/process.py` — start a plugin, feed it, drain it, reap it. Knows no JSON.
|
|
12
|
+
- `rsp/codec.py` — a request in, a parsed response out. Knows no plugin identity.
|
|
13
|
+
- `rsp/handshake.py` — who a plugin says it is.
|
|
14
|
+
- `rsp/spans.py` — byte offsets and redaction. Knows no verdicts.
|
|
15
|
+
- `rsp/runtime.py` — the deciding layer: dispatch, compose, fail closed.
|
|
16
|
+
- `rsp/guards.py` — LlamaIndex adapter. Knows no transport.
|
|
17
|
+
- `rsp/config.py` — plugins from a file. Not in the spec; a host may ignore it.
|
|
18
|
+
- `rsp/ingest.py` — a directory through the LlamaIndex pipeline, for the demo.
|
|
19
|
+
- `rsp/cli.py` — `rsp validate` and `rsp ingest`.
|
|
20
|
+
- `plugins/*` — untrusted third-party code. Detection lives only here.
|
|
21
|
+
|
|
22
|
+
A change that makes a lower layer import a higher one is a design change, not a
|
|
23
|
+
convenience.
|
|
24
|
+
|
|
25
|
+
## Commands
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uv sync
|
|
29
|
+
uv run ruff check rsp/ tests/ plugins/ conformance/ examples/gitleaks-py/ examples/host/
|
|
30
|
+
uv run ruff format --check rsp/ tests/ plugins/ conformance/ examples/gitleaks-py/ examples/host/
|
|
31
|
+
uv run pytest
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Rules
|
|
35
|
+
|
|
36
|
+
- Every error path ends in `BLOCK` unless that plugin's `on_error` says otherwise (D3).
|
|
37
|
+
- Validate a plugin's span before slicing with it: in range, `start <= end`, on a UTF-8 boundary (D6).
|
|
38
|
+
- Findings never reach an embedding or the LLM — both `excluded_*_metadata_keys` (Q8).
|
|
39
|
+
- Never log, embed, or echo matched content. Demo secrets are fabricated.
|
|
40
|
+
- No detection logic in `rsp/`. No dependencies in the core; `llama-index-core` is an extra.
|
|
41
|
+
- Ignore unknown protocol fields (D8).
|
|
42
|
+
- Cache key is `hash(content + plugin_version + plugin_config)`; never cache a plugin that didn't declare determinism (D4).
|
|
43
|
+
- Timeout every read and wait, then kill and reap. Plugin commands are argv lists, never `shell=True`.
|
|
44
|
+
- Strictest verdict wins, `BLOCK` short-circuits (D9).
|
|
45
|
+
- `guards.py` and each plugin adapter contain no detection logic and stay
|
|
46
|
+
small: under 80 lines of code, counting neither docstrings nor comments nor
|
|
47
|
+
blank lines. The budget is on `guards.py` and on the file wrapping the tool
|
|
48
|
+
— `gitleaks.c`, `Gitleaks.java`, `gitleaks.rs` — not on everything beside
|
|
49
|
+
it. A strict gate reads the bytes T4 binds before anything is deserialised,
|
|
50
|
+
and a span helper converts someone else's positions; those are other jobs,
|
|
51
|
+
in other files, and unbudgeted is not unbounded. A language that puts a
|
|
52
|
+
closing brace or a struct tag on its own line pays a fixed tax that is not
|
|
53
|
+
growth, so those lines do not count either —
|
|
54
|
+
`examples/gitleaks-go/gitleaks.go` is 136 lines, of which 80 do work. A
|
|
55
|
+
test does the counting, so a disagreement is about the work rather than
|
|
56
|
+
about the arithmetic. Judge the work, and say which it is when the number
|
|
57
|
+
goes over.
|
|
58
|
+
|
|
59
|
+
## Conventions
|
|
60
|
+
|
|
61
|
+
- Work top-down: write the call site first, then the code it calls. A file may import a module that does not exist yet — don't stub it, make it run, or test it. This is about the order you write in, not the order things sit in a file.
|
|
62
|
+
- Every MUST in `SPEC.md` gets a conformance fixture the same day. Fixtures assert protocol behaviour, not implementation.
|
|
63
|
+
- Comments cite decisions by number: `# span application is the runtime's job (D6)`.
|
|
64
|
+
- Never an issue number. `D6` and `S1` resolve inside a clone; `#13` resolves
|
|
65
|
+
only against a live tracker, and only until that issue is renumbered. Say the
|
|
66
|
+
reason or cite the clause — a test enforces this.
|
|
67
|
+
- `ruff` owns formatting and annotation style.
|
|
68
|
+
- A workflow pins an action from `actions/*` to its major tag and everything
|
|
69
|
+
else to a hash, because a third party's tag can be moved and one of these
|
|
70
|
+
workflows uploads a release. The lint job enforces half of that: `zizmor`
|
|
71
|
+
refuses an unpinned third party and accepts any ref under `actions/*`, so
|
|
72
|
+
`actions/checkout@main` passes it. The major tag is the convention, not the
|
|
73
|
+
check.
|
|
74
|
+
- One issue per PR, titled `#N Short summary`. Out-of-scope findings become
|
|
75
|
+
issues, not scope creep. A PR carries the labels of the issue it closes, or
|
|
76
|
+
of the areas it touched where it closes none, so that what a change touched
|
|
77
|
+
is answerable without reading it.
|
|
78
|
+
|
|
79
|
+
## Style
|
|
80
|
+
|
|
81
|
+
Written down so that a style finding cites a rule rather than a preference.
|
|
82
|
+
`ruff` enforces what it can (`pyproject.toml`); the rest is for reviewers.
|
|
83
|
+
|
|
84
|
+
- A comment says why, never what. If the code already says it, delete the comment.
|
|
85
|
+
- One line where one will do. Cite the clause instead of restating it: `(D6)`,
|
|
86
|
+
`(S3, V3)`, `§4`.
|
|
87
|
+
- A reason lives in one place. Protocol rationale belongs to `SPEC.md`; code
|
|
88
|
+
cites the clause. The same reason is not written in two files.
|
|
89
|
+
- No history. Not what the code used to do, not the bug that prompted a check —
|
|
90
|
+
`git log` keeps that. Keep the reason that still holds.
|
|
91
|
+
- Docstrings: a one-line summary. A body only for what the caller cannot learn
|
|
92
|
+
from the signature, after a blank line, with the closing `"""` on its own line.
|
|
93
|
+
A test's name says what holds; its docstring, if any, says why.
|
|
94
|
+
- In `rsp/`, a name used only inside its module starts with `_`: no underscore
|
|
95
|
+
means public API. A caught exception is `exc`.
|
|
96
|
+
- Constants come straight after the imports. A helper sits above its first
|
|
97
|
+
caller; `main` comes last.
|
|
98
|
+
- Every parameter and return in `rsp/` is annotated.
|
|
99
|
+
|
|
100
|
+
## Reviewers
|
|
101
|
+
|
|
102
|
+
Skip formatting, non-running files, missing tests for call sites, spawn-per-call
|
|
103
|
+
performance (Q6), and matters of taste. One sentence per finding, naming the
|
|
104
|
+
failure. Nothing to say is a valid review.
|