snulbug 0.2.2__tar.gz → 0.2.4__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 (402) hide show
  1. {snulbug-0.2.2 → snulbug-0.2.4}/CHANGELOG.md +29 -0
  2. {snulbug-0.2.2 → snulbug-0.2.4}/PKG-INFO +8 -3
  3. {snulbug-0.2.2 → snulbug-0.2.4}/README.md +7 -2
  4. {snulbug-0.2.2 → snulbug-0.2.4}/docs/README.md +1 -0
  5. snulbug-0.2.4/docs/always-on-runtime.md +385 -0
  6. {snulbug-0.2.2 → snulbug-0.2.4}/docs/auth-providers.md +5 -1
  7. snulbug-0.2.4/docs/credential-brokers.md +172 -0
  8. {snulbug-0.2.2 → snulbug-0.2.4}/docs/devcontainers.md +2 -2
  9. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-auth-recipes.md +112 -0
  10. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-evidence.md +57 -0
  11. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-proxy.md +81 -5
  12. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-share.md +58 -14
  13. {snulbug-0.2.2 → snulbug-0.2.4}/docs/ngrok-end-to-end.md +118 -11
  14. {snulbug-0.2.2 → snulbug-0.2.4}/docs/release.md +12 -2
  15. {snulbug-0.2.2 → snulbug-0.2.4}/docs/share-doctor-checks.md +19 -0
  16. snulbug-0.2.4/docs/upgrading-to-0.2.4.md +112 -0
  17. {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/.devcontainer/devcontainer.json +1 -1
  18. {snulbug-0.2.2 → snulbug-0.2.4}/features/snulbug/README.md +1 -1
  19. {snulbug-0.2.2 → snulbug-0.2.4}/features/snulbug/devcontainer-feature.json +1 -1
  20. {snulbug-0.2.2 → snulbug-0.2.4}/pyproject.toml +1 -1
  21. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/__init__.py +1 -1
  22. snulbug-0.2.4/snulbug/_operations_smoke.py +336 -0
  23. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/auth_recipes.py +114 -7
  24. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/rich_reports.py +21 -0
  25. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/rich_share.py +55 -0
  26. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/share.py +46 -6
  27. snulbug-0.2.4/snulbug/credential_health.py +248 -0
  28. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/credentials.py +62 -14
  29. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/events.py +11 -0
  30. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/fabric.py +13 -9
  31. snulbug-0.2.4/snulbug/http_mounts.py +168 -0
  32. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/http_routes.py +105 -8
  33. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/inspection.py +52 -9
  34. snulbug-0.2.4/snulbug/ngrok_drift.py +433 -0
  35. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/proxy.py +146 -28
  36. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/redaction.py +4 -0
  37. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/release_qa.py +42 -0
  38. snulbug-0.2.4/snulbug/request_explanations.py +348 -0
  39. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/share.py +195 -13
  40. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/share_console.py +285 -443
  41. snulbug-0.2.4/snulbug/share_runtime.py +642 -0
  42. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/share_session.py +1 -0
  43. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/simulator.py +1 -1
  44. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/tunnel.py +35 -20
  45. snulbug-0.2.4/tests/fixtures/pocket_id/README.md +19 -0
  46. snulbug-0.2.4/tests/fixtures/pocket_id/oauth.json +66 -0
  47. snulbug-0.2.4/tests/test_credential_health.py +283 -0
  48. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_fabric.py +2 -1
  49. snulbug-0.2.4/tests/test_gateway_snapshot.py +54 -0
  50. snulbug-0.2.4/tests/test_http_mounts.py +232 -0
  51. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_http_routes.py +103 -0
  52. snulbug-0.2.4/tests/test_ngrok_drift.py +361 -0
  53. snulbug-0.2.4/tests/test_operations_smoke.py +45 -0
  54. snulbug-0.2.4/tests/test_pocket_id_auth.py +345 -0
  55. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_proxy.py +59 -0
  56. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_release_qa.py +28 -6
  57. snulbug-0.2.4/tests/test_request_explanations.py +427 -0
  58. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_share_console.py +95 -12
  59. snulbug-0.2.4/tests/test_share_runtime.py +580 -0
  60. snulbug-0.2.2/docs/credential-brokers.md +0 -67
  61. {snulbug-0.2.2 → snulbug-0.2.4}/.gitignore +0 -0
  62. {snulbug-0.2.2 → snulbug-0.2.4}/CODE_OF_CONDUCT.md +0 -0
  63. {snulbug-0.2.2 → snulbug-0.2.4}/CONTRIBUTING.md +0 -0
  64. {snulbug-0.2.2 → snulbug-0.2.4}/LICENSE +0 -0
  65. {snulbug-0.2.2 → snulbug-0.2.4}/SECURITY.md +0 -0
  66. {snulbug-0.2.2 → snulbug-0.2.4}/docs/actions.md +0 -0
  67. {snulbug-0.2.2 → snulbug-0.2.4}/docs/aws-mcp.md +0 -0
  68. {snulbug-0.2.2 → snulbug-0.2.4}/docs/bundles.md +0 -0
  69. {snulbug-0.2.2 → snulbug-0.2.4}/docs/ci-policy-gates.md +0 -0
  70. {snulbug-0.2.2 → snulbug-0.2.4}/docs/comparison.md +0 -0
  71. {snulbug-0.2.2 → snulbug-0.2.4}/docs/discovery-providers.md +0 -0
  72. {snulbug-0.2.2 → snulbug-0.2.4}/docs/event-sink-providers.md +0 -0
  73. {snulbug-0.2.2 → snulbug-0.2.4}/docs/evidence-exporters.md +0 -0
  74. {snulbug-0.2.2 → snulbug-0.2.4}/docs/getting-started.md +0 -0
  75. {snulbug-0.2.2 → snulbug-0.2.4}/docs/lua-policy-dsl.md +0 -0
  76. {snulbug-0.2.2 → snulbug-0.2.4}/docs/lua-request-api.md +0 -0
  77. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-client-recipes.md +0 -0
  78. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-fabric.md +0 -0
  79. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-gateway.md +0 -0
  80. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-guide.md +0 -0
  81. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-impact.md +0 -0
  82. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-learn.md +0 -0
  83. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-policy.md +0 -0
  84. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-presets.md +0 -0
  85. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-protocol.md +0 -0
  86. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-recorder.md +0 -0
  87. {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-schemas.md +0 -0
  88. {snulbug-0.2.2 → snulbug-0.2.4}/docs/policy-deny-backoff.md +0 -0
  89. {snulbug-0.2.2 → snulbug-0.2.4}/docs/quickstart.md +0 -0
  90. {snulbug-0.2.2 → snulbug-0.2.4}/docs/roadmap.md +0 -0
  91. {snulbug-0.2.2 → snulbug-0.2.4}/docs/security-model.md +0 -0
  92. {snulbug-0.2.2 → snulbug-0.2.4}/docs/state.md +0 -0
  93. {snulbug-0.2.2 → snulbug-0.2.4}/docs/tool-catalog-projection.md +0 -0
  94. {snulbug-0.2.2 → snulbug-0.2.4}/docs/tool-risk-analyzers.md +0 -0
  95. {snulbug-0.2.2 → snulbug-0.2.4}/docs/tunnel-providers.md +0 -0
  96. {snulbug-0.2.2 → snulbug-0.2.4}/docs/upstream-transports.md +0 -0
  97. {snulbug-0.2.2 → snulbug-0.2.4}/examples/auth_claim_patterns/.gitignore +0 -0
  98. {snulbug-0.2.2 → snulbug-0.2.4}/examples/auth_claim_patterns/README.md +0 -0
  99. {snulbug-0.2.2 → snulbug-0.2.4}/examples/auth_claim_patterns/ci-workload-identity.toml +0 -0
  100. {snulbug-0.2.2 → snulbug-0.2.4}/examples/auth_claim_patterns/group-gated-tools.toml +0 -0
  101. {snulbug-0.2.2 → snulbug-0.2.4}/examples/auth_claim_patterns/policy.lua +0 -0
  102. {snulbug-0.2.2 → snulbug-0.2.4}/examples/auth_claim_patterns/tenant-isolation.toml +0 -0
  103. {snulbug-0.2.2 → snulbug-0.2.4}/examples/basic/README.md +0 -0
  104. {snulbug-0.2.2 → snulbug-0.2.4}/examples/basic/app.py +0 -0
  105. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/README.md +0 -0
  106. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/fixtures/duplicate-delivery.json +0 -0
  107. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/fixtures/first-delivery.json +0 -0
  108. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/manifest.json +0 -0
  109. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/policy.lua +0 -0
  110. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/snapshots/duplicate.json +0 -0
  111. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/snapshots/empty.json +0 -0
  112. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/README.md +0 -0
  113. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/fixtures/allowed-tool.json +0 -0
  114. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/fixtures/blocked-tool.json +0 -0
  115. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/fixtures/unauthenticated.json +0 -0
  116. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/manifest.json +0 -0
  117. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/policy.lua +0 -0
  118. {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/snapshots/empty.json +0 -0
  119. {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/README.md +0 -0
  120. {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/mcp-client.json +0 -0
  121. {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/mock_mcp_server.py +0 -0
  122. {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/policy.lua +0 -0
  123. {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/snulbug.env-gateway.toml +0 -0
  124. {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/snulbug.local-gateway.toml +0 -0
  125. {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/README.md +0 -0
  126. {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/app.py +0 -0
  127. {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/policies/acme.lua +0 -0
  128. {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/policies/default.lua +0 -0
  129. {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/policies/globex.lua +0 -0
  130. {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/requests/acme-invalid.json +0 -0
  131. {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/requests/acme-valid.json +0 -0
  132. {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/requests/globex-sandbox.json +0 -0
  133. {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/requests/unknown-tenant.json +0 -0
  134. {snulbug-0.2.2 → snulbug-0.2.4}/examples/github-actions/snulbug-policy-gates.yml +0 -0
  135. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/.gitignore +0 -0
  136. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/Dockerfile.gateway +0 -0
  137. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/README.md +0 -0
  138. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/auth/keycloak/README.md +0 -0
  139. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/auth/keycloak/auth-init.json +0 -0
  140. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/auth/keycloak/client-token-request.json +0 -0
  141. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/auth/keycloak/commands.json +0 -0
  142. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/auth/keycloak/snulbug.auth.toml +0 -0
  143. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/docker-compose.yml +0 -0
  144. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/get-token.py +0 -0
  145. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/keycloak/snulbug-demo-realm.json +0 -0
  146. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/mock_mcp_server.py +0 -0
  147. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/policy.snulbug/policy.lua +0 -0
  148. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/requests/blocked-write-file.json +0 -0
  149. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/requests/read-file.json +0 -0
  150. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/requests/tools-list.json +0 -0
  151. {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/snulbug.toml +0 -0
  152. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/Dockerfile.gateway +0 -0
  153. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/Dockerfile.remote-peer +0 -0
  154. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/README.md +0 -0
  155. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/docker-compose.yml +0 -0
  156. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/hypertele-client.json +0 -0
  157. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/hypertele-server.json +0 -0
  158. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/mcp-client.json +0 -0
  159. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/mock_mcp_server.js +0 -0
  160. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/mock_mcp_server.py +0 -0
  161. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/policy.lua +0 -0
  162. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/snulbug.facade.toml +0 -0
  163. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/snulbug.local.toml +0 -0
  164. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_gateway/README.md +0 -0
  165. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_gateway/app.py +0 -0
  166. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/.gitignore +0 -0
  167. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/README.md +0 -0
  168. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/requests/blocked-tool.json +0 -0
  169. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/requests/safe-tool.json +0 -0
  170. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/requests/tools-list.json +0 -0
  171. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/run_demo.py +0 -0
  172. {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/upstream.py +0 -0
  173. {snulbug-0.2.2 → snulbug-0.2.4}/examples/policy_promotion/README.md +0 -0
  174. {snulbug-0.2.2 → snulbug-0.2.4}/examples/policy_promotion/active.lua +0 -0
  175. {snulbug-0.2.2 → snulbug-0.2.4}/examples/policy_promotion/draft.lua +0 -0
  176. {snulbug-0.2.2 → snulbug-0.2.4}/examples/policy_promotion/fixtures/acme-invalid.json +0 -0
  177. {snulbug-0.2.2 → snulbug-0.2.4}/examples/policy_promotion/fixtures/acme-valid.json +0 -0
  178. {snulbug-0.2.2 → snulbug-0.2.4}/examples/provider_policy_templates/README.md +0 -0
  179. {snulbug-0.2.2 → snulbug-0.2.4}/examples/provider_policy_templates/cloudflare-access-group-gate.lua +0 -0
  180. {snulbug-0.2.2 → snulbug-0.2.4}/examples/provider_policy_templates/entra-app-role-gate.lua +0 -0
  181. {snulbug-0.2.2 → snulbug-0.2.4}/examples/provider_policy_templates/github-actions-workload-gate.lua +0 -0
  182. {snulbug-0.2.2 → snulbug-0.2.4}/examples/provider_policy_templates/keycloak-role-gate.lua +0 -0
  183. {snulbug-0.2.2 → snulbug-0.2.4}/examples/state_replay/README.md +0 -0
  184. {snulbug-0.2.2 → snulbug-0.2.4}/examples/state_replay/duplicate-state.json +0 -0
  185. {snulbug-0.2.2 → snulbug-0.2.4}/examples/state_replay/idempotency.lua +0 -0
  186. {snulbug-0.2.2 → snulbug-0.2.4}/examples/state_replay/request.json +0 -0
  187. {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/README.md +0 -0
  188. {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/app.py +0 -0
  189. {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/policies/github.lua +0 -0
  190. {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/policies/stripe.lua +0 -0
  191. {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/policies/unknown.lua +0 -0
  192. {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/requests/github-push.json +0 -0
  193. {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/requests/stripe-invoice.json +0 -0
  194. {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/requests/stripe-malformed.json +0 -0
  195. {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/requests/unknown-vendor.json +0 -0
  196. {snulbug-0.2.2 → snulbug-0.2.4}/features/snulbug/install.sh +0 -0
  197. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/__main__.py +0 -0
  198. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/assets/prism.css +0 -0
  199. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/assets/prism.js +0 -0
  200. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/auth_providers.py +0 -0
  201. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/auth-required.snulbug/README.md +0 -0
  202. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/auth-required.snulbug/fixtures/authenticated.json +0 -0
  203. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/auth-required.snulbug/fixtures/missing-token.json +0 -0
  204. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/auth-required.snulbug/manifest.json +0 -0
  205. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/auth-required.snulbug/policy.lua +0 -0
  206. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/README.md +0 -0
  207. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/contexts/inventory-lease.json +0 -0
  208. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/contexts/sandbox-change-lease.json +0 -0
  209. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/data-read.json +0 -0
  210. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/iam-delete-user.json +0 -0
  211. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/inventory-read.json +0 -0
  212. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/knowledge-search.json +0 -0
  213. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/missing-token.json +0 -0
  214. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/sandbox-mutation.json +0 -0
  215. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/manifest.json +0 -0
  216. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/policy.lua +0 -0
  217. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/snapshots/empty.json +0 -0
  218. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/README.md +0 -0
  219. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/fixtures/missing-token.json +0 -0
  220. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/fixtures/safe-tool.json +0 -0
  221. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/fixtures/unsafe-tool.json +0 -0
  222. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/manifest.json +0 -0
  223. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/policy.lua +0 -0
  224. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/snapshots/empty.json +0 -0
  225. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/README.md +0 -0
  226. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/fixtures/missing-token.json +0 -0
  227. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/fixtures/safe-tool.json +0 -0
  228. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/fixtures/shell-tool.json +0 -0
  229. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/manifest.json +0 -0
  230. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/policy.lua +0 -0
  231. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/README.md +0 -0
  232. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/fixtures/absolute-path.json +0 -0
  233. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/fixtures/allowed-path.json +0 -0
  234. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/fixtures/traversal-path.json +0 -0
  235. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/fixtures/unsafe-tool.json +0 -0
  236. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/manifest.json +0 -0
  237. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/policy.lua +0 -0
  238. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/README.md +0 -0
  239. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/fixtures/missing-token.json +0 -0
  240. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/fixtures/safe-tool.json +0 -0
  241. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/fixtures/tools-list.json +0 -0
  242. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/fixtures/write-method.json +0 -0
  243. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/manifest.json +0 -0
  244. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/policy.lua +0 -0
  245. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/snapshots/empty.json +0 -0
  246. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/README.md +0 -0
  247. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/fixtures/safe-tool.json +0 -0
  248. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/fixtures/tools-list.json +0 -0
  249. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/fixtures/unsafe-tool.json +0 -0
  250. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/manifest.json +0 -0
  251. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/policy.lua +0 -0
  252. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/README.md +0 -0
  253. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/fixtures/batch-request.json +0 -0
  254. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/fixtures/missing-token.json +0 -0
  255. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/fixtures/safe-tool.json +0 -0
  256. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/fixtures/unsafe-tool.json +0 -0
  257. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/manifest.json +0 -0
  258. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/policy.lua +0 -0
  259. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/snapshots/empty.json +0 -0
  260. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/README.md +0 -0
  261. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/allowed-read.json +0 -0
  262. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/missing-token.json +0 -0
  263. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/secret-path.json +0 -0
  264. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/traversal-path.json +0 -0
  265. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/unsafe-tool.json +0 -0
  266. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/manifest.json +0 -0
  267. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/policy.lua +0 -0
  268. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/bundle.py +0 -0
  269. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/__init__.py +0 -0
  270. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/common.py +0 -0
  271. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/evidence.py +0 -0
  272. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/fabric.py +0 -0
  273. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/policy.py +0 -0
  274. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/schemas.py +0 -0
  275. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli_helpers.py +0 -0
  276. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cloudflare_access.py +0 -0
  277. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/codespaces.py +0 -0
  278. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/config.py +0 -0
  279. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/confirm.py +0 -0
  280. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/control_events.py +0 -0
  281. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/controller.py +0 -0
  282. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/discovery.py +0 -0
  283. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/evidence_exporters.py +0 -0
  284. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/fabric_control.py +0 -0
  285. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/fabric_members.py +0 -0
  286. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/fabric_runtime.py +0 -0
  287. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/gateway_templates.py +0 -0
  288. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/guide.py +0 -0
  289. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/impact.py +0 -0
  290. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/json_schema.py +0 -0
  291. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/lab.py +0 -0
  292. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/learn.py +0 -0
  293. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/leases.py +0 -0
  294. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/manifests.py +0 -0
  295. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_auth.py +0 -0
  296. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_cache.py +0 -0
  297. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_capabilities.py +0 -0
  298. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_client_requests.py +0 -0
  299. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_completion.py +0 -0
  300. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_mrtr.py +0 -0
  301. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_parameter_headers.py +0 -0
  302. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_policy_bundles.py +0 -0
  303. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_progress.py +0 -0
  304. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_protocol.py +0 -0
  305. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_resources.py +0 -0
  306. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_schema_policy.py +0 -0
  307. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_schemas.py +0 -0
  308. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_spec_conformance.py +0 -0
  309. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_stdio.py +0 -0
  310. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_stream.py +0 -0
  311. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_subscriptions.py +0 -0
  312. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_tasks.py +0 -0
  313. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_tools.py +0 -0
  314. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/middleware.py +0 -0
  315. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/policy_activation.py +0 -0
  316. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/policy_backoff.py +0 -0
  317. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/policy_review.py +0 -0
  318. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/presets.py +0 -0
  319. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/promotion.py +0 -0
  320. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/py.typed +0 -0
  321. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/quickstart.py +0 -0
  322. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/recorder.py +0 -0
  323. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/response_policy.py +0 -0
  324. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/runtime.py +0 -0
  325. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/sarif.py +0 -0
  326. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/scaffolds.py +0 -0
  327. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/schema_policy.py +0 -0
  328. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/share_doctor.py +0 -0
  329. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/state.py +0 -0
  330. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/tool_catalog.py +0 -0
  331. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/tool_risk.py +0 -0
  332. {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/upstream_transports.py +0 -0
  333. {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/LICENSE +0 -0
  334. {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/README.md +0 -0
  335. {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/dependentSchemas.json +0 -0
  336. {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/dynamicRef.json +0 -0
  337. {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/if-then-else.json +0 -0
  338. {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/prefixItems.json +0 -0
  339. {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/unevaluatedProperties.json +0 -0
  340. {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/stdio_subscriptions.py +0 -0
  341. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_auth_claim_patterns.py +0 -0
  342. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_auth_recipes.py +0 -0
  343. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_automation_invites.py +0 -0
  344. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_cli_helpers.py +0 -0
  345. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_cloudflare_access.py +0 -0
  346. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_codespaces.py +0 -0
  347. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_config.py +0 -0
  348. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_credentials.py +0 -0
  349. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_customer_policy_demo.py +0 -0
  350. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_devcontainer_feature.py +0 -0
  351. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_discovery.py +0 -0
  352. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_events.py +0 -0
  353. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_evidence_exporters.py +0 -0
  354. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_fabric_controller.py +0 -0
  355. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_json_schema.py +0 -0
  356. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_keycloak_oauth_demo.py +0 -0
  357. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_leases.py +0 -0
  358. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_manifests.py +0 -0
  359. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_cache.py +0 -0
  360. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_gateway_demo.py +0 -0
  361. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_guide.py +0 -0
  362. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_helpers.py +0 -0
  363. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_impact.py +0 -0
  364. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_inspection.py +0 -0
  365. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_lab.py +0 -0
  366. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_learn.py +0 -0
  367. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_mrtr.py +0 -0
  368. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_parameter_headers.py +0 -0
  369. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_policy_bundles.py +0 -0
  370. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_presets.py +0 -0
  371. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_progress.py +0 -0
  372. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_protocol.py +0 -0
  373. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_proxy_demo.py +0 -0
  374. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_quickstart.py +0 -0
  375. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_recorder.py +0 -0
  376. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_resources.py +0 -0
  377. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_schema_policy.py +0 -0
  378. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_schemas.py +0 -0
  379. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_share.py +0 -0
  380. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_spec_conformance.py +0 -0
  381. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_stdio.py +0 -0
  382. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_stream.py +0 -0
  383. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_subscriptions.py +0 -0
  384. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_tools.py +0 -0
  385. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_middleware.py +0 -0
  386. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_policy_bundle.py +0 -0
  387. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_policy_promotion.py +0 -0
  388. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_policy_state.py +0 -0
  389. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_provider_policy_templates.py +0 -0
  390. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_redaction_audit.py +0 -0
  391. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_response_policy.py +0 -0
  392. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_sandbox_abuse.py +0 -0
  393. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_scaffolds.py +0 -0
  394. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_state_snapshots.py +0 -0
  395. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_tool_catalog.py +0 -0
  396. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_tool_risk.py +0 -0
  397. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_tunnel_audit.py +0 -0
  398. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_tunnel_doctor.py +0 -0
  399. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_tunnel_init.py +0 -0
  400. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_upstream_transports.py +0 -0
  401. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_webhook_normalization_demo.py +0 -0
  402. {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_webhooks.py +0 -0
@@ -6,6 +6,35 @@ The format is based on Keep a Changelog, and this project follows semantic versi
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.2.4] - 2026-10-19
10
+
11
+ Operational hardening for always-on shares and shared HTTP/MCP gateways.
12
+ See the [0.2.4 upgrade notes](docs/upgrading-to-0.2.4.md) before restarting an
13
+ existing service, especially if a tunnel is already running separately.
14
+
15
+ - Moved ngrok/SSH tunnel management into the share runtime: `share run` supervises tunnels with or without the web console, bounded crash-restart backoff, explicit stop/start controls, and graceful gateway/tunnel shutdown. Added `--no-tunnel` and always-on deployment recipes.
16
+ - Added read-only ngrok policy drift checks to share doctor, readiness, reports, and the console: compare current config, generated policy, and deployed Cloud Endpoint policy without exposing deployed secrets or applying cloud changes. Includes OAuth-aware edge baselines and stale-result invalidation.
17
+ - Added evidence-based request failure explanations to existing audit logs, live decisions, and session reports: distinguish admission gates, upstream credentials/connectivity, HTTP/MCP errors, partial catalogs, and response checks while preserving Lua decisions and unknown execution outcomes. Removed raw forwarding exceptions from client errors and facade health evidence; no tool-call retries.
18
+ - Hardened upstream credential operations: bounded regular-file/header reads, secret-free broker failures, and live share doctor availability/hygiene checks surfaced in readiness, status, reports, and the Auth drawer. Documented atomic file rotation and environment restart semantics; passive refreshes reuse saved diagnostics without resolving secrets.
19
+ - Added explicit HTTP mount contracts for authentication ownership, methods, credential-header forwarding, inactivity timeouts, and optional backend health checks. Reused share doctor/readiness, reports, the provider drawer, and signed share-contract bindings; public mounts strip Authorization/cookies by default, and MCP auth/leases remain separate from application access.
20
+ - Added isolated installed-wheel operations QA for share creation, local MCP/HTTP traffic, credential rotation, persisted leases, and supervised shutdown. Fixed installed-package share creation so container recipe snapshots no longer require a source checkout.
21
+
22
+ No change to the default MCP protocol version or experimental profile limitations.
23
+ This release does not add HTTP application OIDC, overload protection, automatic
24
+ tool-call retries, or a published container image.
25
+
26
+ ## [0.2.3] - 2026-10-18
27
+
28
+ Add Pocket ID setup through the existing OAuth provider and lease machinery.
29
+
30
+ - Added `share auth init --provider pocket-id` with resource-bound API permissions, deny-by-default scope maps, PKCE/CIMD registration instructions, automation guidance, and lease-aware doctor commands.
31
+ - Extended auth doctor to check exact issuer metadata identity, advertised PKCE S256, and CIMD availability without claiming access to private provider grants or allowlists.
32
+ - Added synthetic RS256 user/bot token fixtures, rejection and JWKS rotation tests, and existing auth conformance-pack coverage; documented setup and identity-claim limitations.
33
+
34
+ Pocket ID live passkey/client interoperability remains unverified. This release
35
+ does not add browser console login or authentication to HTTP mounts. No change
36
+ to the default MCP protocol version or the experimental profile's limitations.
37
+
9
38
  ## [0.2.2] - 2026-10-16
10
39
 
11
40
  Support always-on MCP bots with renewable automation invites, without introducing
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: snulbug
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: A local-dev MCP policy proxy with Lua policies, replay logs, and learned least-privilege bundles
5
5
  Project-URL: Homepage, https://github.com/nahuaque/snulbug
6
6
  Project-URL: Repository, https://github.com/nahuaque/snulbug
@@ -174,7 +174,12 @@ snulbug mcp share run .snulbug/shares/share-...
174
174
  Inside a generated share directory, `snulbug mcp share run` is enough;
175
175
  it reads `.snulbug/share/session.json`, reconciles the active config,
176
176
  policy, lease, and log paths, and starts the local share console before
177
- starting the gateway. Pass `--no-console` when you only want the proxy.
177
+ starting the gateway. Pass `--no-console` to disable the local web UI.
178
+
179
+ For ngrok and SSH shares, `share run` also starts and supervises the generated
180
+ tunnel independently of the console. Use `--no-tunnel` for an externally managed
181
+ agent. See [always-on deployment](docs/always-on-runtime.md) for crash recovery,
182
+ graceful shutdown, and systemd, launchd, and container recipes.
178
183
 
179
184
  3. Check what is happening:
180
185
 
@@ -468,7 +473,7 @@ Workflow:
468
473
  - optional OAuth protected-resource mode with JWT/JWKS, token introspection, DPoP validation, and MCP auth challenges
469
474
  - OAuth scope-to-MCP method/tool mapping for least-privilege public shares
470
475
  - OAuth resource/audience drift checks for tunnel-safe public shares
471
- - generated auth setup flows for Keycloak, Auth0, Okta, Entra, Cloudflare Access, and GitHub OIDC
476
+ - generated auth setup flows for Keycloak, Pocket ID, Auth0, Okta, Entra, Cloudflare Access, and GitHub OIDC
472
477
  - composable OAuth + auth-bound task lease + Lua policy access decisions
473
478
  - anti-passthrough credential brokering so caller OAuth tokens stop at snulbug
474
479
  - learned least-privilege bundles from observed traffic
@@ -131,7 +131,12 @@ snulbug mcp share run .snulbug/shares/share-...
131
131
  Inside a generated share directory, `snulbug mcp share run` is enough;
132
132
  it reads `.snulbug/share/session.json`, reconciles the active config,
133
133
  policy, lease, and log paths, and starts the local share console before
134
- starting the gateway. Pass `--no-console` when you only want the proxy.
134
+ starting the gateway. Pass `--no-console` to disable the local web UI.
135
+
136
+ For ngrok and SSH shares, `share run` also starts and supervises the generated
137
+ tunnel independently of the console. Use `--no-tunnel` for an externally managed
138
+ agent. See [always-on deployment](docs/always-on-runtime.md) for crash recovery,
139
+ graceful shutdown, and systemd, launchd, and container recipes.
135
140
 
136
141
  3. Check what is happening:
137
142
 
@@ -425,7 +430,7 @@ Workflow:
425
430
  - optional OAuth protected-resource mode with JWT/JWKS, token introspection, DPoP validation, and MCP auth challenges
426
431
  - OAuth scope-to-MCP method/tool mapping for least-privilege public shares
427
432
  - OAuth resource/audience drift checks for tunnel-safe public shares
428
- - generated auth setup flows for Keycloak, Auth0, Okta, Entra, Cloudflare Access, and GitHub OIDC
433
+ - generated auth setup flows for Keycloak, Pocket ID, Auth0, Okta, Entra, Cloudflare Access, and GitHub OIDC
429
434
  - composable OAuth + auth-bound task lease + Lua policy access decisions
430
435
  - anti-passthrough credential brokering so caller OAuth tokens stop at snulbug
431
436
  - learned least-privilege bundles from observed traffic
@@ -29,6 +29,7 @@ share create -> share run -> share status -> share requests approve -> share pol
29
29
  ## Sharing, Tunnels, And Remote Dev
30
30
 
31
31
  - [End-to-end ngrok MCP gateway](ngrok-end-to-end.md)
32
+ - [Always-on share runtime and deployment](always-on-runtime.md)
32
33
  - [Tunnel provider plugins](tunnel-providers.md)
33
34
  - [Credential broker plugins](credential-brokers.md)
34
35
  - [Discovery provider plugins](discovery-providers.md)
@@ -0,0 +1,385 @@
1
+ # Always-on share runtime
2
+
3
+ Use the existing `snulbug mcp share run DIRECTORY` command for a long-lived
4
+ gateway. It runs in the foreground; systemd, launchd, or a container restart
5
+ policy owns whole-gateway restarts. There is no separate daemon or new CLI.
6
+ Create and review the share first using [MCP share sessions](mcp-share.md).
7
+
8
+ ## Tunnel ownership
9
+
10
+ For ngrok and SSH shares, `share run` automatically starts and supervises the
11
+ managed tunnel independently of the web console. It uses the same generated
12
+ provider config and commands; existing shares need no new generated layout.
13
+ ngrok still uses `tunnel/ngrok-agent.yml` plus the separately attached Cloud
14
+ Endpoint Traffic Policy. SSH still uses the generated reverse-forward target.
15
+ See the [ngrok walkthrough](ngrok-end-to-end.md) for cloud setup.
16
+
17
+ ```bash
18
+ /opt/snulbug/venv/bin/snulbug mcp share run /var/lib/snulbug/share --no-console
19
+ ```
20
+
21
+ - `--no-console` disables only the UI, not tunnel startup or supervision.
22
+ - `--no-tunnel` disables automatic tunnel startup. The console can still
23
+ explicitly start a managed tunnel; combine both flags for a headless gateway
24
+ whose tunnel is externally managed.
25
+ - The existing console **Start tunnel** and **Stop tunnel** controls operate on
26
+ the same managed process. An intentional stop cancels pending restarts and
27
+ keeps the tunnel stopped until an explicit start.
28
+ - `generic`, `cloudflare`, `tailscale`, `pinggy`, `holepunch`, and other supported
29
+ providers remain externally managed. Their generated setup commands still
30
+ apply; snulbug does not start, restart, or stop those external processes.
31
+
32
+ Do not start a second provider process for an automatically managed endpoint.
33
+ The runtime supervises processes, not public reachability: a running ngrok or
34
+ SSH process does not prove that forwarding, DNS, TLS, authentication, or cloud
35
+ policy is correct. Use existing share doctor and health checks, including the
36
+ public URL checks, rather than treating a PID as readiness.
37
+ For ngrok, [doctor's policy drift inspection](ngrok-end-to-end.md#check-for-configuration-drift)
38
+ compares local configuration with the deployed Cloud Endpoint through optional,
39
+ read-only API access. Supply its API credential to the service account to enable
40
+ the same inspection from the console; it is separate from the agent authtoken.
41
+
42
+ ## Runtime settings
43
+
44
+ The following optional table in the share's existing `snulbug.toml` shows all
45
+ defaults. Merge it into the file; do not replace the generated config or add a
46
+ second `[mcp.runtime]` table. Durations are in seconds.
47
+
48
+ ```toml
49
+ [mcp.runtime]
50
+ tunnel_autostart = true
51
+ restart_initial_seconds = 1.0
52
+ restart_max_seconds = 30.0
53
+ restart_max_attempts = 5
54
+ restart_reset_seconds = 60.0
55
+ tunnel_shutdown_timeout = 5.0
56
+ graceful_shutdown_timeout = 30.0
57
+ ```
58
+
59
+ `tunnel_autostart = false` disables automatic startup in the same way as
60
+ `--no-tunnel`; an explicit console start remains available. `--no-tunnel`
61
+ overrides `tunnel_autostart = true` for that invocation.
62
+
63
+ An unexpected managed tunnel exit triggers bounded exponential crash restart:
64
+ the delay begins at `restart_initial_seconds`, doubles on each retry, and is
65
+ capped at `restart_max_seconds`. `restart_max_attempts` limits restart attempts,
66
+ not the initial launch. With defaults, a repeatedly crashing process gets at
67
+ most five retries, after delays of 1, 2, 4, 8, and 16 seconds.
68
+
69
+ After exhaustion, automatic retries stop. Fix the cause, then explicitly start
70
+ the tunnel through the console or restart the whole service. A healthy process
71
+ running continuously for `restart_reset_seconds` resets the retry budget; this
72
+ is process stability, not a successful public endpoint probe. An intentional
73
+ console stop is not a crash and never consumes a retry or triggers a restart.
74
+
75
+ Only the managed tunnel process is restarted here. The OS supervisor handles a
76
+ gateway process failure; it is not a public health watchdog and should not be
77
+ used to bypass exhausted tunnel retries. No MCP tool calls are retried or
78
+ replayed by this runtime. A broken connection can leave a tool's outcome
79
+ unknown; reconnecting does not make a repeated side effect safe.
80
+ The existing decision feed and session reports include
81
+ [request failure explanations](mcp-evidence.md#request-failure-explanations),
82
+ separating admission, upstream credentials/transport, and response-policy failures
83
+ without performing retries or adding background probes.
84
+
85
+ ## Shutdown
86
+
87
+ On SIGTERM or SIGINT, Uvicorn stops accepting new work and drains in-flight
88
+ requests and streams. `graceful_shutdown_timeout` bounds that drain; at the
89
+ deadline, remaining work is cancelled. Only after the gateway drain/cancellation
90
+ does the runtime stop its managed tunnel. `tunnel_shutdown_timeout` bounds the
91
+ tunnel's termination wait before forced cleanup. Tunnel restart is suppressed
92
+ during shutdown. Externally managed provider processes remain their owner's
93
+ responsibility.
94
+
95
+ Give the outer supervisor more than the sum of these two timeouts plus cleanup
96
+ headroom. The recipes below use 45 seconds for the default 30-second drain and
97
+ 5-second tunnel wait. Increase the supervisor timeout if you increase either
98
+ runtime setting. SIGKILL, a host crash, or a shorter supervisor deadline cannot
99
+ provide graceful draining.
100
+
101
+ ## Deployment prerequisites
102
+
103
+ - Install a build containing this runtime into a fixed virtual environment.
104
+ Use an absolute `snulbug` executable path, not an interactive shell's alias,
105
+ `uv run`, or a login-shell activation script. Keep the installation and
106
+ launcher files administrator-owned and non-service-writable.
107
+ - Use a dedicated unprivileged account. Create the share once at its persistent
108
+ absolute path under that account; do not run `share create --force` at boot.
109
+ Keep the same path inside a container, or reconcile recorded paths before
110
+ moving an existing share.
111
+ - Persist the whole share directory: config, policy, `leases.json`, invite
112
+ secrets, canonical session state, tunnel config, and evidence. Give the service
113
+ account write access, restrict the directory to mode `0700`, and protect
114
+ secret-bearing files with mode `0600`. Backups are secret-bearing too.
115
+ - Install `ngrok` or `ssh` on the service's explicit `PATH`. Complete ngrok's
116
+ generated authtoken setup; a placeholder config will not start. For SSH,
117
+ provision non-interactive credentials and verified `known_hosts` for that
118
+ account. Do not disable host-key verification or depend on a desktop agent.
119
+ - Arrange the upstream service separately. A tunnel restart does not restart
120
+ the upstream, renew expired leases, extend invite authorization, or repair
121
+ cloud policy. Use [renewable automation invites](mcp-share.md#renewable-automation-invites)
122
+ where a bot needs approved renewal rather than an unbounded lease.
123
+ - Keep the share console on loopback or disable it with `--no-console`, as these
124
+ recipes do. Never add a public tunnel or shared HTTP route to its admin port
125
+ or ngrok's inspection port. For remote administration, deliberately enable
126
+ the loopback console and use authenticated SSH local forwarding.
127
+
128
+ Do not put tokens in unit files, plists, command arguments, images, or source
129
+ control. Where the generated configuration uses environment references, load
130
+ them from a protected env file. For example, `share.env` can contain:
131
+
132
+ ```dotenv
133
+ SNULBUG_SHARE_TOKEN=replace-with-the-existing-share-token
134
+ ```
135
+
136
+ This is an existing credential, not a request to mint a different token. Keep
137
+ secrets already stored in generated policy/provider files protected as well;
138
+ setting an env variable does not replace a literal ngrok authtoken placeholder.
139
+ Environment variables are still visible to sufficiently privileged local
140
+ processes. Treat service logs and container inspection access as sensitive.
141
+
142
+ For upstream service tokens, prefer the existing
143
+ [credential broker references](credential-brokers.md#always-on-upstream-credentials).
144
+ File sources support atomic replacement without a restart; environment-backed
145
+ sources require a service restart to pick up supervisor environment changes.
146
+ Live share doctor checks availability and hygiene, and status/report plus the
147
+ console's Auth drawer reuse its secret-free diagnostics. Run checks in the
148
+ service environment: local availability is not proof of upstream acceptance.
149
+
150
+ If the same tunnel exposes a web app or API, declare its
151
+ [HTTP mount contract](mcp-proxy.md#mount-contracts-and-readiness): explicit
152
+ auth ownership, methods, credential-header forwarding, and an optional safe
153
+ backend health endpoint. MCP lease revocation does not stop application access.
154
+ Use the existing share doctor and provider drawer to review both kinds of
155
+ exposure; application OIDC/session auth remains the app's responsibility.
156
+
157
+ ## Linux: systemd
158
+
159
+ This example assumes an existing `snulbug` user/group, an installation at
160
+ `/opt/snulbug/venv`, and a share created at `/var/lib/snulbug/share`.
161
+ Store the env file at `/etc/snulbug/share.env`, owned by root with mode `0600`;
162
+ systemd reads it before dropping privileges. Install ngrok at
163
+ `/usr/local/bin/ngrok` or SSH at `/usr/bin/ssh`.
164
+
165
+ Install `/etc/systemd/system/snulbug-share.service`:
166
+
167
+ ```ini
168
+ [Unit]
169
+ Description=snulbug MCP share gateway
170
+ Wants=network-online.target
171
+ After=network-online.target
172
+ StartLimitIntervalSec=300
173
+ StartLimitBurst=5
174
+
175
+ [Service]
176
+ Type=exec
177
+ User=snulbug
178
+ Group=snulbug
179
+ WorkingDirectory=/var/lib/snulbug/share
180
+ Environment=HOME=/var/lib/snulbug
181
+ Environment=PATH=/usr/local/bin:/usr/bin:/bin
182
+ EnvironmentFile=/etc/snulbug/share.env
183
+ ExecStart=/opt/snulbug/venv/bin/snulbug mcp share run /var/lib/snulbug/share --no-console
184
+ Restart=on-failure
185
+ RestartSec=5s
186
+ KillSignal=SIGTERM
187
+ KillMode=mixed
188
+ TimeoutStopSec=45s
189
+ UMask=0077
190
+ NoNewPrivileges=true
191
+
192
+ [Install]
193
+ WantedBy=multi-user.target
194
+ ```
195
+
196
+ `KillMode=mixed` sends the initial SIGTERM to the gateway, allowing it to drain
197
+ before stopping its tunnel; leftover processes are still forcibly cleaned up.
198
+ The default control-group termination would signal the tunnel at the same time
199
+ as the gateway. See [systemd.kill](https://www.freedesktop.org/software/systemd/man/latest/systemd.kill.html).
200
+ `Restart=on-failure` covers gateway failure, not tunnel retry exhaustion or an
201
+ intentional service stop. See [systemd.service](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html).
202
+
203
+ ```bash
204
+ sudo systemctl daemon-reload
205
+ sudo systemctl enable --now snulbug-share.service
206
+ sudo journalctl -u snulbug-share.service -f
207
+ ```
208
+
209
+ Stop with `sudo systemctl stop snulbug-share.service`. After repairing a gateway
210
+ start failure that hit systemd's start limit, use `sudo systemctl reset-failed
211
+ snulbug-share.service`, then `sudo systemctl start snulbug-share.service`.
212
+ Use `sudo systemctl restart snulbug-share.service` for an explicit whole-service
213
+ restart, including recovery after exhausted tunnel retries.
214
+
215
+ ## macOS: launchd
216
+
217
+ For service operation before login, use a LaunchDaemon, not a per-login
218
+ LaunchAgent. This example assumes an existing dedicated `snulbug` account/group
219
+ with home `/Users/snulbug`, an installation at `/opt/snulbug/venv`, and a share
220
+ at `/Users/snulbug/share`. Create `/Users/snulbug/Library/Logs/snulbug` for its
221
+ logs, owned by that account with mode `0700`. The machine must remain awake and
222
+ its share volume must be available; launchd cannot provide uptime during sleep.
223
+ See Apple's [launchd job guide](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html).
224
+
225
+ launchd has no systemd-style `EnvironmentFile`. Store
226
+ `/Users/snulbug/.config/snulbug/share.env` as mode `0600`, owned by `snulbug`,
227
+ inside mode `0700` directories. Use simple shell-compatible `KEY=value` entries
228
+ with quoted values where needed. The following root-owned, non-service-writable
229
+ launcher at `/usr/local/libexec/snulbug-share-run` only loads that trusted file
230
+ and replaces itself with the existing command; it is not a new daemon:
231
+
232
+ ```sh
233
+ #!/bin/sh
234
+ set -eu
235
+ umask 077
236
+ set -a
237
+ . /Users/snulbug/.config/snulbug/share.env
238
+ set +a
239
+ export HOME=/Users/snulbug
240
+ export PATH=/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin
241
+ exec /opt/snulbug/venv/bin/snulbug mcp share run /Users/snulbug/share --no-console
242
+ ```
243
+
244
+ Install `/Library/LaunchDaemons/com.snulbug.share.plist`, owned by `root:wheel`
245
+ with mode `0644`; keep secrets out of it:
246
+
247
+ ```xml
248
+ <?xml version="1.0" encoding="UTF-8"?>
249
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
250
+ <plist version="1.0">
251
+ <dict>
252
+ <key>Label</key>
253
+ <string>com.snulbug.share</string>
254
+ <key>UserName</key>
255
+ <string>snulbug</string>
256
+ <key>GroupName</key>
257
+ <string>snulbug</string>
258
+ <key>ProgramArguments</key>
259
+ <array>
260
+ <string>/usr/local/libexec/snulbug-share-run</string>
261
+ </array>
262
+ <key>WorkingDirectory</key>
263
+ <string>/Users/snulbug/share</string>
264
+ <key>RunAtLoad</key>
265
+ <true/>
266
+ <key>KeepAlive</key>
267
+ <true/>
268
+ <key>ThrottleInterval</key>
269
+ <integer>10</integer>
270
+ <key>ExitTimeOut</key>
271
+ <integer>45</integer>
272
+ <key>StandardOutPath</key>
273
+ <string>/Users/snulbug/Library/Logs/snulbug/share.out.log</string>
274
+ <key>StandardErrorPath</key>
275
+ <string>/Users/snulbug/Library/Logs/snulbug/share.err.log</string>
276
+ </dict>
277
+ </plist>
278
+ ```
279
+
280
+ `KeepAlive` restarts a gateway that exits; `ThrottleInterval` limits rapid
281
+ launches, and `ExitTimeOut` leaves time for graceful shutdown. These are outer
282
+ process controls, not public health checks or the managed tunnel retry budget.
283
+ See Apple's [launchd.plist reference](https://github.com/apple-oss-distributions/launchd/blob/main/man/launchd.plist.5).
284
+
285
+ ```bash
286
+ sudo chmod 0755 /usr/local/libexec/snulbug-share-run
287
+ plutil -lint /Library/LaunchDaemons/com.snulbug.share.plist
288
+ sudo launchctl bootstrap system /Library/LaunchDaemons/com.snulbug.share.plist
289
+ sudo launchctl print system/com.snulbug.share
290
+ ```
291
+
292
+ For an orderly stop, use `sudo launchctl bootout system/com.snulbug.share`.
293
+ For an explicit restart, boot out, then bootstrap the plist again. Avoid
294
+ `launchctl kickstart -k` for a draining restart: it kills the existing process.
295
+ A direct signal while `KeepAlive` is enabled may cause a new gateway launch;
296
+ boot out to keep the service stopped. Arrange rotation for the log files.
297
+
298
+ ## Container
299
+
300
+ Use a locally built image containing this runtime and the chosen provider
301
+ binary; no new published image is required. The generated
302
+ `containers/Dockerfile.gateway` is a starting point and installs from its
303
+ `snulbug-src/` snapshot of the checkout or installed package, not a published
304
+ snulbug image. Ensure that snapshot
305
+ contains the runtime. It does not install ngrok or SSH: add a verified,
306
+ architecture-matched Linux ngrok binary or install `openssh-client` in your
307
+ local build before using managed startup. Never copy provider credentials into
308
+ the image. In this example the resulting local tag is
309
+ `snulbug-share-runtime:local`, and snulbug is installed at
310
+ `/usr/local/bin/snulbug` with provider binaries on its `PATH`.
311
+
312
+ The following command is for a Linux Docker host. Create the share at
313
+ `/srv/snulbug/share` and keep its generated gateway bound to `127.0.0.1`.
314
+ Host networking lets the gateway and its managed tunnel use the existing
315
+ loopback origin and reach an upstream on the host's loopback interface without
316
+ changing generated tunnel config. Do not use this unchanged for Docker Desktop
317
+ or bridge networking; those require deliberate upstream/network configuration.
318
+ The example assumes the host service account has UID/GID `10001:10001` and owns
319
+ the persistent share; substitute your account's numeric IDs.
320
+
321
+ Protect `/etc/snulbug/share.env` on the host as root-owned with mode `0600`.
322
+ Use Docker's `KEY=value` env-file syntax, not shell `export` or shell expansion.
323
+ The privileged Docker invocation below can read that file; the container itself
324
+ runs as the unprivileged UID. Use a persistent read-write bind volume at the
325
+ same absolute path:
326
+
327
+ ```bash
328
+ sudo docker run --detach --name snulbug-share \
329
+ --pull=never \
330
+ --init \
331
+ --restart=unless-stopped \
332
+ --stop-signal=SIGTERM \
333
+ --stop-timeout=45 \
334
+ --network=host \
335
+ --user=10001:10001 \
336
+ --env-file=/etc/snulbug/share.env \
337
+ --env HOME=/srv/snulbug \
338
+ --env PATH=/usr/local/bin:/usr/bin:/bin \
339
+ --mount type=bind,src=/srv/snulbug/share,dst=/srv/snulbug/share \
340
+ --workdir=/srv/snulbug/share \
341
+ --entrypoint=/usr/local/bin/snulbug \
342
+ snulbug-share-runtime:local \
343
+ mcp share run /srv/snulbug/share --no-console
344
+ ```
345
+
346
+ For SSH, also mount the service account's SSH config, private key, and verified
347
+ `known_hosts` read-only at `/srv/snulbug/.ssh`, with permissions readable only by
348
+ that UID. Do not mount a general-purpose personal SSH directory. For ngrok,
349
+ complete the authtoken configuration in the protected share volume.
350
+
351
+ `--init` forwards signals and reaps children; `--stop-timeout` allows draining
352
+ before forced termination. No console or inspection port is published. With
353
+ host networking, loopback binds are essential: it does not isolate listening
354
+ ports from the host. See [Docker run reference](https://docs.docker.com/reference/cli/docker/container/run/).
355
+
356
+ Use `sudo docker logs -f snulbug-share` for gateway output and
357
+ `sudo docker stop snulbug-share` for an orderly stop. Use
358
+ `sudo docker restart --timeout 45 snulbug-share` for an explicit restart. The
359
+ restart policy handles container exit, not a live gateway with exhausted tunnel
360
+ retries or failing public checks.
361
+
362
+ ## Verify and operate
363
+
364
+ After starting or restarting, use the existing checks from an account and
365
+ network that can reach the intended client URL:
366
+
367
+ ```bash
368
+ /opt/snulbug/venv/bin/snulbug mcp share status /var/lib/snulbug/share
369
+ /opt/snulbug/venv/bin/snulbug mcp share doctor /var/lib/snulbug/share \
370
+ --url https://YOUR-PUBLIC-HOST/mcp
371
+ ```
372
+
373
+ Use the corresponding paths on macOS or inside the container. An SSH share's
374
+ default client URL is loopback on the remote SSH host, not the gateway host;
375
+ verify from that remote side as described in
376
+ [plain SSH reverse tunnels](mcp-share.md#plain-ssh-reverse-tunnel). For ngrok,
377
+ verify the generated Traffic Policy is attached to the public Cloud Endpoint,
378
+ not just that the private internal Agent Endpoint is running.
379
+
380
+ If a tunnel repeatedly exits, inspect its existing console diagnostics and
381
+ provider log, fix credentials/configuration or duplicate agents, and explicitly
382
+ start it again. With `--no-console`, restart the OS service instead. Do not
383
+ automatically replay failed MCP tool calls as a recovery mechanism. Finish a
384
+ bounded sharing task with the existing [closeout flow](mcp-share.md#close-out);
385
+ stopping a process alone is not lease or invite revocation.
@@ -5,9 +5,13 @@ snulbug has a small auth provider extension point for two related jobs:
5
5
  - generate `snulbug mcp share auth init --provider ...` setup recipes
6
6
  - map provider-specific token claims into `context.auth.provider.*` for Lua policy helpers
7
7
 
8
- Built-ins cover Keycloak, Auth0, Okta, Entra, Cloudflare Access, and GitHub
8
+ Built-ins cover Keycloak, Pocket ID, Auth0, Okta, Entra, Cloudflare Access, and GitHub
9
9
  Actions OIDC. External providers can register the same surface from Python.
10
10
 
11
+ The [Pocket ID recipe](mcp-auth-recipes.md#pocket-id) uses standard verified
12
+ subject/client identity and API scopes. It does not invent provider claims or
13
+ retrieve identity claims from ID tokens/userinfo during MCP requests.
14
+
11
15
  ```python
12
16
  from collections.abc import Mapping
13
17
  from typing import Any