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.
Files changed (216) hide show
  1. rag_security_protocol-0.1.1rc1/.coderabbit.yaml +107 -0
  2. rag_security_protocol-0.1.1rc1/.gitattributes +5 -0
  3. rag_security_protocol-0.1.1rc1/.github/workflows/ci.yml +71 -0
  4. rag_security_protocol-0.1.1rc1/.github/workflows/plugins.yml +191 -0
  5. rag_security_protocol-0.1.1rc1/.github/workflows/publish.yml +49 -0
  6. rag_security_protocol-0.1.1rc1/.gitignore +19 -0
  7. rag_security_protocol-0.1.1rc1/.python-version +1 -0
  8. rag_security_protocol-0.1.1rc1/AGENTS.md +104 -0
  9. rag_security_protocol-0.1.1rc1/LICENSE +201 -0
  10. rag_security_protocol-0.1.1rc1/PKG-INFO +132 -0
  11. rag_security_protocol-0.1.1rc1/README.md +106 -0
  12. rag_security_protocol-0.1.1rc1/SPEC.md +362 -0
  13. rag_security_protocol-0.1.1rc1/WRITING-A-PLUGIN.md +145 -0
  14. rag_security_protocol-0.1.1rc1/codecov.yml +14 -0
  15. rag_security_protocol-0.1.1rc1/conformance/README.md +59 -0
  16. rag_security_protocol-0.1.1rc1/conformance/cases/README.md +47 -0
  17. rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/aws-key.json +4 -0
  18. rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/clean.json +4 -0
  19. rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/non-ascii-prefix.json +4 -0
  20. rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/placeholder-is-not-a-secret.json +4 -0
  21. rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/span-across-lines.json +4 -0
  22. rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/span-on-a-later-line.json +4 -0
  23. rag_security_protocol-0.1.1rc1/conformance/cases/gitleaks/wrapper-version-in-handshake.json +5 -0
  24. rag_security_protocol-0.1.1rc1/conformance/cases/handshake.json +15 -0
  25. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-byte-order-mark-is-not-whitespace.json +10 -0
  26. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-doubled-backslash-is-not-an-escape.json +12 -0
  27. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-leading-zero-is-not-a-number.json +10 -0
  28. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-malformed-number-under-an-unread-field.json +10 -0
  29. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-repeated-key-inside-metadata.json +10 -0
  30. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-repeated-key-no-plugin-reads.json +10 -0
  31. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-a-repeated-key-written-with-an-escape.json +10 -0
  32. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-an-integer-above-the-safe-range-is-refused.json +10 -0
  33. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-an-unpaired-surrogate-in-a-key.json +10 -0
  34. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-an-unpaired-surrogate-is-refused.json +10 -0
  35. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-digits-in-the-content-are-not-numbers.json +12 -0
  36. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-duplicate-keys-are-refused.json +10 -0
  37. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-nan-is-not-a-number.json +10 -0
  38. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-sibling-objects-may-repeat-a-key.json +12 -0
  39. rag_security_protocol-0.1.1rc1/conformance/cases/json/t4-the-safe-range-includes-its-edges.json +12 -0
  40. rag_security_protocol-0.1.1rc1/conformance/cases/metadata-a-plugin-does-not-read.json +12 -0
  41. rag_security_protocol-0.1.1rc1/conformance/cases/metadata-is-advisory.json +15 -0
  42. rag_security_protocol-0.1.1rc1/conformance/cases/spans-are-utf8-bytes.json +15 -0
  43. rag_security_protocol-0.1.1rc1/conformance/cases/spans-multiple-occurrences.json +18 -0
  44. rag_security_protocol-0.1.1rc1/conformance/cases/stdout-is-protocol-only.json +17 -0
  45. rag_security_protocol-0.1.1rc1/conformance/cases/unknown-fields-ignored.json +14 -0
  46. rag_security_protocol-0.1.1rc1/conformance/cases/verdict-allow.json +16 -0
  47. rag_security_protocol-0.1.1rc1/conformance/cases/verdict-block.json +7 -0
  48. rag_security_protocol-0.1.1rc1/conformance/cases/verdict-flag.json +7 -0
  49. rag_security_protocol-0.1.1rc1/conformance/cases/verdict-redact.json +15 -0
  50. rag_security_protocol-0.1.1rc1/conformance/harness.py +107 -0
  51. rag_security_protocol-0.1.1rc1/conformance/host/error-a-crash-blocks.json +5 -0
  52. rag_security_protocol-0.1.1rc1/conformance/host/error-a-flood-blocks.json +5 -0
  53. rag_security_protocol-0.1.1rc1/conformance/host/error-a-hang-times-out.json +5 -0
  54. rag_security_protocol-0.1.1rc1/conformance/host/error-noisy-diagnostics-are-not-an-error.json +6 -0
  55. rag_security_protocol-0.1.1rc1/conformance/host/error-on-error-allow-lets-it-through.json +5 -0
  56. rag_security_protocol-0.1.1rc1/conformance/host/error-silence-blocks.json +5 -0
  57. rag_security_protocol-0.1.1rc1/conformance/host/error-unparseable-output-blocks.json +5 -0
  58. rag_security_protocol-0.1.1rc1/conformance/host/hooks-an-undeclared-hook-is-not-called.json +6 -0
  59. rag_security_protocol-0.1.1rc1/conformance/host/json-a-bom-is-not-whitespace.json +19 -0
  60. rag_security_protocol-0.1.1rc1/conformance/host/json-a-host-does-not-send-what-it-refuses.json +23 -0
  61. rag_security_protocol-0.1.1rc1/conformance/host/json-deep-nesting-is-an-error.json +19 -0
  62. rag_security_protocol-0.1.1rc1/conformance/host/json-duplicate-keys.json +19 -0
  63. rag_security_protocol-0.1.1rc1/conformance/host/json-framing-whitespace-is-the-rfc-s.json +19 -0
  64. rag_security_protocol-0.1.1rc1/conformance/host/json-huge-integers.json +19 -0
  65. rag_security_protocol-0.1.1rc1/conformance/host/json-lone-surrogates.json +19 -0
  66. rag_security_protocol-0.1.1rc1/conformance/host/json-nan-is-not-a-number.json +19 -0
  67. rag_security_protocol-0.1.1rc1/conformance/host/json-number-syntax-is-the-rfc-s.json +19 -0
  68. rag_security_protocol-0.1.1rc1/conformance/host/spans-adjacent-coalesce.json +5 -0
  69. rag_security_protocol-0.1.1rc1/conformance/host/spans-every-plugin-sees-the-original.json +46 -0
  70. rag_security_protocol-0.1.1rc1/conformance/host/spans-inside-a-character-is-refused.json +5 -0
  71. rag_security_protocol-0.1.1rc1/conformance/host/spans-out-of-range-is-refused.json +5 -0
  72. rag_security_protocol-0.1.1rc1/conformance/host/spans-overlapping-coalesce.json +5 -0
  73. rag_security_protocol-0.1.1rc1/conformance/host/spans-the-severest-replacement-wins.json +8 -0
  74. rag_security_protocol-0.1.1rc1/conformance/host/transport-two-objects-is-not-an-answer.json +18 -0
  75. rag_security_protocol-0.1.1rc1/conformance/host/verdicts-a-block-carries-its-reason.json +23 -0
  76. rag_security_protocol-0.1.1rc1/conformance/host/verdicts-an-unknown-severity-ranks-lowest.json +45 -0
  77. rag_security_protocol-0.1.1rc1/conformance/run.py +90 -0
  78. rag_security_protocol-0.1.1rc1/demo/README.md +47 -0
  79. rag_security_protocol-0.1.1rc1/demo/rsp.toml +3 -0
  80. rag_security_protocol-0.1.1rc1/demo/sample-docs/architecture.md +16 -0
  81. rag_security_protocol-0.1.1rc1/demo/sample-docs/deploy-notes.md +14 -0
  82. rag_security_protocol-0.1.1rc1/demo/sample-docs/faq.md +31 -0
  83. rag_security_protocol-0.1.1rc1/demo/sample-docs/meeting-2026-03-11.md +20 -0
  84. rag_security_protocol-0.1.1rc1/demo/sample-docs/onboarding.md +21 -0
  85. rag_security_protocol-0.1.1rc1/demo/sample-docs/runbook-backups.md +22 -0
  86. rag_security_protocol-0.1.1rc1/demo/sample-docs/runbook-oncall.md +29 -0
  87. rag_security_protocol-0.1.1rc1/demo/sample-docs/vector-store.md +28 -0
  88. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/Makefile +25 -0
  89. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/README.md +65 -0
  90. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/conformance.json +3 -0
  91. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/gitleaks.c +129 -0
  92. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/gitleaks.h +27 -0
  93. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/main.c +87 -0
  94. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/protocol.c +106 -0
  95. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/protocol.h +24 -0
  96. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/spawn.c +135 -0
  97. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/spawn.h +17 -0
  98. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/strict.c +69 -0
  99. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/strict.h +18 -0
  100. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/test_gitleaks.c +123 -0
  101. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/testdata/delivery.sh +42 -0
  102. rag_security_protocol-0.1.1rc1/examples/gitleaks-c/testdata/requests.sh +25 -0
  103. rag_security_protocol-0.1.1rc1/examples/gitleaks-go/.gitignore +3 -0
  104. rag_security_protocol-0.1.1rc1/examples/gitleaks-go/README.md +30 -0
  105. rag_security_protocol-0.1.1rc1/examples/gitleaks-go/conformance.json +3 -0
  106. rag_security_protocol-0.1.1rc1/examples/gitleaks-go/gitleaks.go +136 -0
  107. rag_security_protocol-0.1.1rc1/examples/gitleaks-go/gitleaks_test.go +76 -0
  108. rag_security_protocol-0.1.1rc1/examples/gitleaks-go/go.mod +5 -0
  109. rag_security_protocol-0.1.1rc1/examples/gitleaks-go/main.go +35 -0
  110. rag_security_protocol-0.1.1rc1/examples/gitleaks-go/protocol.go +76 -0
  111. rag_security_protocol-0.1.1rc1/examples/gitleaks-go/protocol_test.go +135 -0
  112. rag_security_protocol-0.1.1rc1/examples/gitleaks-go/strictjson.go +159 -0
  113. rag_security_protocol-0.1.1rc1/examples/gitleaks-java/Makefile +42 -0
  114. rag_security_protocol-0.1.1rc1/examples/gitleaks-java/README.md +61 -0
  115. rag_security_protocol-0.1.1rc1/examples/gitleaks-java/conformance.json +3 -0
  116. rag_security_protocol-0.1.1rc1/examples/gitleaks-java/src/Gitleaks.java +98 -0
  117. rag_security_protocol-0.1.1rc1/examples/gitleaks-java/src/Main.java +24 -0
  118. rag_security_protocol-0.1.1rc1/examples/gitleaks-java/src/Protocol.java +70 -0
  119. rag_security_protocol-0.1.1rc1/examples/gitleaks-java/src/Spans.java +93 -0
  120. rag_security_protocol-0.1.1rc1/examples/gitleaks-java/src/StrictJson.java +134 -0
  121. rag_security_protocol-0.1.1rc1/examples/gitleaks-java/test/GitleaksTest.java +85 -0
  122. rag_security_protocol-0.1.1rc1/examples/gitleaks-java/testdata/requests.sh +45 -0
  123. rag_security_protocol-0.1.1rc1/examples/gitleaks-offsets.json +295 -0
  124. rag_security_protocol-0.1.1rc1/examples/gitleaks-offsets.schema.json +81 -0
  125. rag_security_protocol-0.1.1rc1/examples/gitleaks-py/README.md +47 -0
  126. rag_security_protocol-0.1.1rc1/examples/gitleaks-py/conformance.json +3 -0
  127. rag_security_protocol-0.1.1rc1/examples/gitleaks-py/conftest.py +9 -0
  128. rag_security_protocol-0.1.1rc1/examples/gitleaks-py/gitleaks.py +121 -0
  129. rag_security_protocol-0.1.1rc1/examples/gitleaks-py/main.py +30 -0
  130. rag_security_protocol-0.1.1rc1/examples/gitleaks-py/protocol.py +55 -0
  131. rag_security_protocol-0.1.1rc1/examples/gitleaks-py/strictjson.py +51 -0
  132. rag_security_protocol-0.1.1rc1/examples/gitleaks-py/tests/test_gitleaks.py +69 -0
  133. rag_security_protocol-0.1.1rc1/examples/gitleaks-py/tests/test_protocol.py +135 -0
  134. rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/.gitignore +1 -0
  135. rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/Cargo.lock +107 -0
  136. rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/Cargo.toml +17 -0
  137. rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/README.md +39 -0
  138. rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/conformance.json +3 -0
  139. rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/src/gitleaks.rs +105 -0
  140. rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/src/lib.rs +9 -0
  141. rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/src/main.rs +26 -0
  142. rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/src/protocol.rs +60 -0
  143. rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/src/spans.rs +63 -0
  144. rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/src/strictjson.rs +109 -0
  145. rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/tests/gitleaks.rs +120 -0
  146. rag_security_protocol-0.1.1rc1/examples/gitleaks-rs/tests/protocol.rs +135 -0
  147. rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/.gitignore +1 -0
  148. rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Makefile +13 -0
  149. rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Package.swift +21 -0
  150. rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/README.md +64 -0
  151. rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/Adapter/Finding.swift +34 -0
  152. rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/Adapter/Gitleaks.swift +84 -0
  153. rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/Adapter/Protocol.swift +98 -0
  154. rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/Adapter/Spans.swift +64 -0
  155. rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/Adapter/StrictJson.swift +143 -0
  156. rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/offset-test/main.swift +85 -0
  157. rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/Sources/rsp-gitleaks-swift/main.swift +26 -0
  158. rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/conformance.json +4 -0
  159. rag_security_protocol-0.1.1rc1/examples/gitleaks-swift/testdata/requests.sh +45 -0
  160. rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/.gitignore +1 -0
  161. rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/README.md +24 -0
  162. rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/conformance.json +3 -0
  163. rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/package-lock.json +54 -0
  164. rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/package.json +21 -0
  165. rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/src/gitleaks.ts +133 -0
  166. rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/src/main.ts +13 -0
  167. rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/src/protocol.ts +58 -0
  168. rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/src/strictjson.ts +107 -0
  169. rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/test/binary.test.ts +42 -0
  170. rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/test/gitleaks.test.ts +57 -0
  171. rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/test/protocol.test.ts +128 -0
  172. rag_security_protocol-0.1.1rc1/examples/gitleaks-ts/tsconfig.json +14 -0
  173. rag_security_protocol-0.1.1rc1/examples/host/README.md +74 -0
  174. rag_security_protocol-0.1.1rc1/examples/host/docs/deploy-notes.md +7 -0
  175. rag_security_protocol-0.1.1rc1/examples/host/docs/mirror-credentials.md +9 -0
  176. rag_security_protocol-0.1.1rc1/examples/host/docs/onboarding.md +7 -0
  177. rag_security_protocol-0.1.1rc1/examples/host/docs/runbook-incident.md +7 -0
  178. rag_security_protocol-0.1.1rc1/examples/host/main.py +111 -0
  179. rag_security_protocol-0.1.1rc1/examples/host/rsp.toml +13 -0
  180. rag_security_protocol-0.1.1rc1/examples/testdata/fake-gitleaks.sh +25 -0
  181. rag_security_protocol-0.1.1rc1/examples/testdata/loud-gitleaks.sh +7 -0
  182. rag_security_protocol-0.1.1rc1/plugins/rsp-echo/conformance.json +3 -0
  183. rag_security_protocol-0.1.1rc1/plugins/rsp-echo/main.py +78 -0
  184. rag_security_protocol-0.1.1rc1/plugins/rsp-echo/strictjson.py +54 -0
  185. rag_security_protocol-0.1.1rc1/plugins/rsp-replay/main.py +87 -0
  186. rag_security_protocol-0.1.1rc1/pyproject.toml +78 -0
  187. rag_security_protocol-0.1.1rc1/rsp/__init__.py +0 -0
  188. rag_security_protocol-0.1.1rc1/rsp/cli.py +80 -0
  189. rag_security_protocol-0.1.1rc1/rsp/codec.py +167 -0
  190. rag_security_protocol-0.1.1rc1/rsp/config.py +146 -0
  191. rag_security_protocol-0.1.1rc1/rsp/guards.py +91 -0
  192. rag_security_protocol-0.1.1rc1/rsp/handshake.py +77 -0
  193. rag_security_protocol-0.1.1rc1/rsp/ingest.py +153 -0
  194. rag_security_protocol-0.1.1rc1/rsp/process.py +183 -0
  195. rag_security_protocol-0.1.1rc1/rsp/py.typed +0 -0
  196. rag_security_protocol-0.1.1rc1/rsp/runtime.py +273 -0
  197. rag_security_protocol-0.1.1rc1/rsp/spans.py +112 -0
  198. rag_security_protocol-0.1.1rc1/tests/conftest.py +31 -0
  199. rag_security_protocol-0.1.1rc1/tests/plugins.py +152 -0
  200. rag_security_protocol-0.1.1rc1/tests/test_codec.py +181 -0
  201. rag_security_protocol-0.1.1rc1/tests/test_composition.py +295 -0
  202. rag_security_protocol-0.1.1rc1/tests/test_config.py +213 -0
  203. rag_security_protocol-0.1.1rc1/tests/test_conformance.py +103 -0
  204. rag_security_protocol-0.1.1rc1/tests/test_corpus.py +248 -0
  205. rag_security_protocol-0.1.1rc1/tests/test_demo.py +322 -0
  206. rag_security_protocol-0.1.1rc1/tests/test_example_host.py +124 -0
  207. rag_security_protocol-0.1.1rc1/tests/test_guards.py +190 -0
  208. rag_security_protocol-0.1.1rc1/tests/test_guide.py +135 -0
  209. rag_security_protocol-0.1.1rc1/tests/test_handshake.py +82 -0
  210. rag_security_protocol-0.1.1rc1/tests/test_host_conformance.py +108 -0
  211. rag_security_protocol-0.1.1rc1/tests/test_kit.py +136 -0
  212. rag_security_protocol-0.1.1rc1/tests/test_offset_table.py +90 -0
  213. rag_security_protocol-0.1.1rc1/tests/test_runtime.py +218 -0
  214. rag_security_protocol-0.1.1rc1/tests/test_spans.py +122 -0
  215. rag_security_protocol-0.1.1rc1/tests/test_spec_drift.py +367 -0
  216. 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.