snulbug 0.2.3__tar.gz → 0.2.5__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.
- {snulbug-0.2.3 → snulbug-0.2.5}/CHANGELOG.md +32 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/PKG-INFO +7 -2
- {snulbug-0.2.3 → snulbug-0.2.5}/README.md +6 -1
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/README.md +1 -0
- snulbug-0.2.5/docs/always-on-runtime.md +385 -0
- snulbug-0.2.5/docs/credential-brokers.md +172 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/devcontainers.md +2 -2
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-evidence.md +57 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-proxy.md +145 -5
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-share.md +58 -14
- snulbug-0.2.5/docs/ngrok-end-to-end.md +375 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/release.md +12 -2
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/share-doctor-checks.md +19 -0
- snulbug-0.2.5/docs/upgrading-to-0.2.4.md +112 -0
- snulbug-0.2.5/docs/upgrading-to-0.2.5.md +97 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/codespace_local_gateway/.devcontainer/devcontainer.json +1 -1
- {snulbug-0.2.3 → snulbug-0.2.5}/features/snulbug/README.md +1 -1
- {snulbug-0.2.3 → snulbug-0.2.5}/features/snulbug/devcontainer-feature.json +1 -1
- {snulbug-0.2.3 → snulbug-0.2.5}/pyproject.toml +1 -1
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/__init__.py +1 -1
- snulbug-0.2.5/snulbug/_operations_smoke.py +336 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/cli/rich_reports.py +21 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/cli/rich_share.py +59 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/cli/share.py +46 -6
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/config.py +6 -0
- snulbug-0.2.5/snulbug/credential_health.py +248 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/credentials.py +62 -14
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/events.py +11 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/fabric.py +13 -9
- snulbug-0.2.5/snulbug/http_mounts.py +185 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/http_routes.py +127 -10
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/inspection.py +52 -9
- snulbug-0.2.5/snulbug/ngrok_drift.py +438 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/proxy.py +154 -30
- snulbug-0.2.5/snulbug/public_origin.py +136 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/redaction.py +4 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/release_qa.py +45 -0
- snulbug-0.2.5/snulbug/request_explanations.py +348 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/share.py +131 -13
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/share_console.py +287 -443
- snulbug-0.2.5/snulbug/share_runtime.py +642 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/share_session.py +1 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/simulator.py +1 -1
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/tunnel.py +88 -21
- snulbug-0.2.5/tests/test_credential_health.py +283 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_fabric.py +2 -1
- snulbug-0.2.5/tests/test_gateway_snapshot.py +54 -0
- snulbug-0.2.5/tests/test_http_mounts.py +265 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_http_routes.py +222 -3
- snulbug-0.2.5/tests/test_ngrok_drift.py +369 -0
- snulbug-0.2.5/tests/test_operations_smoke.py +45 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_proxy.py +59 -0
- snulbug-0.2.5/tests/test_public_origin.py +209 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_release_qa.py +30 -6
- snulbug-0.2.5/tests/test_request_explanations.py +427 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_share_console.py +95 -12
- snulbug-0.2.5/tests/test_share_runtime.py +580 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_tunnel_init.py +68 -0
- snulbug-0.2.3/docs/credential-brokers.md +0 -67
- snulbug-0.2.3/docs/ngrok-end-to-end.md +0 -241
- {snulbug-0.2.3 → snulbug-0.2.5}/.gitignore +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/CODE_OF_CONDUCT.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/CONTRIBUTING.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/LICENSE +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/SECURITY.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/actions.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/auth-providers.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/aws-mcp.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/bundles.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/ci-policy-gates.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/comparison.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/discovery-providers.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/event-sink-providers.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/evidence-exporters.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/getting-started.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/lua-policy-dsl.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/lua-request-api.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-auth-recipes.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-client-recipes.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-fabric.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-gateway.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-guide.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-impact.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-learn.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-policy.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-presets.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-protocol.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-recorder.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/mcp-schemas.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/policy-deny-backoff.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/quickstart.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/roadmap.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/security-model.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/state.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/tool-catalog-projection.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/tool-risk-analyzers.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/tunnel-providers.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/docs/upstream-transports.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/auth_claim_patterns/.gitignore +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/auth_claim_patterns/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/auth_claim_patterns/ci-workload-identity.toml +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/auth_claim_patterns/group-gated-tools.toml +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/auth_claim_patterns/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/auth_claim_patterns/tenant-isolation.toml +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/basic/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/basic/app.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/idempotency.snulbug/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/idempotency.snulbug/fixtures/duplicate-delivery.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/idempotency.snulbug/fixtures/first-delivery.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/idempotency.snulbug/manifest.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/idempotency.snulbug/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/idempotency.snulbug/snapshots/duplicate.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/idempotency.snulbug/snapshots/empty.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/mcp-gateway.snulbug/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/mcp-gateway.snulbug/fixtures/allowed-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/mcp-gateway.snulbug/fixtures/blocked-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/mcp-gateway.snulbug/fixtures/unauthenticated.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/mcp-gateway.snulbug/manifest.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/mcp-gateway.snulbug/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/bundles/mcp-gateway.snulbug/snapshots/empty.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/codespace_local_gateway/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/codespace_local_gateway/mcp-client.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/codespace_local_gateway/mock_mcp_server.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/codespace_local_gateway/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/codespace_local_gateway/snulbug.env-gateway.toml +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/codespace_local_gateway/snulbug.local-gateway.toml +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/customer_policy/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/customer_policy/app.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/customer_policy/policies/acme.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/customer_policy/policies/default.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/customer_policy/policies/globex.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/customer_policy/requests/acme-invalid.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/customer_policy/requests/acme-valid.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/customer_policy/requests/globex-sandbox.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/customer_policy/requests/unknown-tenant.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/github-actions/snulbug-policy-gates.yml +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/.gitignore +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/Dockerfile.gateway +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/auth/keycloak/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/auth/keycloak/auth-init.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/auth/keycloak/client-token-request.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/auth/keycloak/commands.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/auth/keycloak/snulbug.auth.toml +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/docker-compose.yml +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/get-token.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/keycloak/snulbug-demo-realm.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/mock_mcp_server.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/policy.snulbug/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/requests/blocked-write-file.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/requests/read-file.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/requests/tools-list.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/keycloak_oauth_demo/snulbug.toml +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_container_facade/Dockerfile.gateway +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_container_facade/Dockerfile.remote-peer +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_container_facade/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_container_facade/docker-compose.yml +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_container_facade/hypertele-client.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_container_facade/hypertele-server.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_container_facade/mcp-client.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_container_facade/mock_mcp_server.js +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_container_facade/mock_mcp_server.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_container_facade/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_container_facade/snulbug.facade.toml +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_container_facade/snulbug.local.toml +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_gateway/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_gateway/app.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_proxy_demo/.gitignore +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_proxy_demo/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_proxy_demo/requests/blocked-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_proxy_demo/requests/safe-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_proxy_demo/requests/tools-list.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_proxy_demo/run_demo.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/mcp_proxy_demo/upstream.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/policy_promotion/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/policy_promotion/active.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/policy_promotion/draft.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/policy_promotion/fixtures/acme-invalid.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/policy_promotion/fixtures/acme-valid.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/provider_policy_templates/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/provider_policy_templates/cloudflare-access-group-gate.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/provider_policy_templates/entra-app-role-gate.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/provider_policy_templates/github-actions-workload-gate.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/provider_policy_templates/keycloak-role-gate.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/state_replay/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/state_replay/duplicate-state.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/state_replay/idempotency.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/state_replay/request.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/webhook_normalization/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/webhook_normalization/app.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/webhook_normalization/policies/github.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/webhook_normalization/policies/stripe.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/webhook_normalization/policies/unknown.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/webhook_normalization/requests/github-push.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/webhook_normalization/requests/stripe-invoice.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/webhook_normalization/requests/stripe-malformed.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/examples/webhook_normalization/requests/unknown-vendor.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/features/snulbug/install.sh +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/__main__.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/assets/prism.css +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/assets/prism.js +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/auth_providers.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/auth_recipes.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/auth-required.snulbug/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/auth-required.snulbug/fixtures/authenticated.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/auth-required.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/auth-required.snulbug/manifest.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/auth-required.snulbug/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/contexts/inventory-lease.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/contexts/sandbox-change-lease.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/data-read.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/iam-delete-user.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/inventory-read.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/knowledge-search.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/sandbox-mutation.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/manifest.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/snapshots/empty.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/fixtures/safe-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/fixtures/unsafe-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/manifest.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/snapshots/empty.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/fixtures/safe-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/fixtures/shell-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/manifest.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/fixtures/absolute-path.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/fixtures/allowed-path.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/fixtures/traversal-path.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/fixtures/unsafe-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/manifest.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/fixtures/safe-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/fixtures/tools-list.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/fixtures/write-method.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/manifest.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/snapshots/empty.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/fixtures/safe-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/fixtures/tools-list.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/fixtures/unsafe-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/manifest.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/fixtures/batch-request.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/fixtures/safe-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/fixtures/unsafe-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/manifest.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/snapshots/empty.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/allowed-read.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/secret-path.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/traversal-path.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/unsafe-tool.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/manifest.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/policy.lua +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/bundle.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/cli/__init__.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/cli/common.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/cli/evidence.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/cli/fabric.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/cli/policy.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/cli/schemas.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/cli_helpers.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/cloudflare_access.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/codespaces.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/confirm.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/control_events.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/controller.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/discovery.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/evidence_exporters.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/fabric_control.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/fabric_members.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/fabric_runtime.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/gateway_templates.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/guide.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/impact.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/json_schema.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/lab.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/learn.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/leases.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/manifests.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_auth.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_cache.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_capabilities.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_client_requests.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_completion.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_mrtr.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_parameter_headers.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_policy_bundles.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_progress.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_protocol.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_resources.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_schema_policy.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_schemas.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_spec_conformance.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_stdio.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_stream.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_subscriptions.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_tasks.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/mcp_tools.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/middleware.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/policy_activation.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/policy_backoff.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/policy_review.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/presets.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/promotion.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/py.typed +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/quickstart.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/recorder.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/response_policy.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/runtime.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/sarif.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/scaffolds.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/schema_policy.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/share_doctor.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/state.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/tool_catalog.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/tool_risk.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/snulbug/upstream_transports.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/fixtures/json_schema_2020_12/LICENSE +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/fixtures/json_schema_2020_12/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/fixtures/json_schema_2020_12/dependentSchemas.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/fixtures/json_schema_2020_12/dynamicRef.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/fixtures/json_schema_2020_12/if-then-else.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/fixtures/json_schema_2020_12/prefixItems.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/fixtures/json_schema_2020_12/unevaluatedProperties.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/fixtures/pocket_id/README.md +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/fixtures/pocket_id/oauth.json +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/fixtures/stdio_subscriptions.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_auth_claim_patterns.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_auth_recipes.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_automation_invites.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_cli_helpers.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_cloudflare_access.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_codespaces.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_config.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_credentials.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_customer_policy_demo.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_devcontainer_feature.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_discovery.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_events.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_evidence_exporters.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_fabric_controller.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_json_schema.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_keycloak_oauth_demo.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_leases.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_manifests.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_cache.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_gateway_demo.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_guide.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_helpers.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_impact.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_inspection.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_lab.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_learn.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_mrtr.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_parameter_headers.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_policy_bundles.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_presets.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_progress.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_protocol.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_proxy_demo.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_quickstart.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_recorder.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_resources.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_schema_policy.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_schemas.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_share.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_spec_conformance.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_stdio.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_stream.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_subscriptions.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_mcp_tools.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_middleware.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_pocket_id_auth.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_policy_bundle.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_policy_promotion.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_policy_state.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_provider_policy_templates.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_redaction_audit.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_response_policy.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_sandbox_abuse.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_scaffolds.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_state_snapshots.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_tool_catalog.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_tool_risk.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_tunnel_audit.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_tunnel_doctor.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_upstream_transports.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_webhook_normalization_demo.py +0 -0
- {snulbug-0.2.3 → snulbug-0.2.5}/tests/test_webhooks.py +0 -0
|
@@ -6,6 +6,38 @@ The format is based on Keep a Changelog, and this project follows semantic versi
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.2.5] - 2026-10-23
|
|
10
|
+
|
|
11
|
+
Public-origin preservation for shared MCP and HTTP gateways.
|
|
12
|
+
Read the [0.2.5 upgrade notes](docs/upgrading-to-0.2.5.md) before deploying an
|
|
13
|
+
existing ngrok share or a share with required signed HTTP mount contracts.
|
|
14
|
+
|
|
15
|
+
- Forward canonical public host, scheme, and port from the configured share URL across internal hops. HTTP mounts can opt into `preserve_host = true`; backend Host remains the default and upstream TLS verification is unchanged.
|
|
16
|
+
- Generate ngrok policies that capture and validate the original public authority/scheme before forwarding and replace caller-supplied origin/audit headers. Reject invalid capture pairs at the gateway and unsafe public URLs at config load; keep observed ingress headers for audit provenance, not forwarding authority.
|
|
17
|
+
- Include effective origin and Host mode in mount health checks, doctor, status, reports, the web console, readiness reviews, and signed mount contracts. Existing ngrok policies need manual review and reattachment; no cloud changes or share regeneration are applied automatically.
|
|
18
|
+
- Add regression coverage for spoofed/duplicate headers, redirects, prefixes, ports, IPv6, MCP forwarding, health/cache invalidation, and contract drift, including installed-wheel packaging checks.
|
|
19
|
+
|
|
20
|
+
No change to the default MCP protocol or preview limitations. Application auth,
|
|
21
|
+
proxy trust, base paths, and CSRF defenses remain the mounted app's responsibility;
|
|
22
|
+
this release does not rewrite HTML, redirect locations, or cookie paths.
|
|
23
|
+
|
|
24
|
+
## [0.2.4] - 2026-10-19
|
|
25
|
+
|
|
26
|
+
Operational hardening for always-on shares and shared HTTP/MCP gateways.
|
|
27
|
+
See the [0.2.4 upgrade notes](docs/upgrading-to-0.2.4.md) before restarting an
|
|
28
|
+
existing service, especially if a tunnel is already running separately.
|
|
29
|
+
|
|
30
|
+
- 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.
|
|
31
|
+
- 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.
|
|
32
|
+
- 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.
|
|
33
|
+
- 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.
|
|
34
|
+
- 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.
|
|
35
|
+
- 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.
|
|
36
|
+
|
|
37
|
+
No change to the default MCP protocol version or experimental profile limitations.
|
|
38
|
+
This release does not add HTTP application OIDC, overload protection, automatic
|
|
39
|
+
tool-call retries, or a published container image.
|
|
40
|
+
|
|
9
41
|
## [0.2.3] - 2026-10-18
|
|
10
42
|
|
|
11
43
|
Add Pocket ID setup through the existing OAuth provider and lease machinery.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: snulbug
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
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`
|
|
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
|
|
|
@@ -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`
|
|
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
|
|
|
@@ -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.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Credential broker plugins
|
|
2
|
+
|
|
3
|
+
snulbug uses credential brokers to inject upstream credentials without
|
|
4
|
+
forwarding caller tokens. Built-ins support:
|
|
5
|
+
|
|
6
|
+
- `type = "env"`: read the secret from an environment variable
|
|
7
|
+
- `type = "file"`: read the secret from a local file
|
|
8
|
+
|
|
9
|
+
External brokers can add other sources such as a local keychain, a vault, a
|
|
10
|
+
container metadata service, or a short-lived token minting service.
|
|
11
|
+
|
|
12
|
+
## Always-on upstream credentials
|
|
13
|
+
|
|
14
|
+
Keep caller authentication and upstream credentials separate. A client's OAuth
|
|
15
|
+
token or share bearer authenticates to snulbug; an upstream credential reference
|
|
16
|
+
authenticates snulbug to that upstream. Missing upstream credentials fail closed,
|
|
17
|
+
without retrying a tool call, forwarding the caller's token as a fallback, or
|
|
18
|
+
reusing a previously resolved value.
|
|
19
|
+
|
|
20
|
+
Use the existing registry in the share's `snulbug.toml`. File paths are relative
|
|
21
|
+
to that config file, not the launcher's working directory:
|
|
22
|
+
|
|
23
|
+
```toml
|
|
24
|
+
[mcp.fabric.credentials.service]
|
|
25
|
+
type = "file"
|
|
26
|
+
path = "/run/secrets/mcp-service-token"
|
|
27
|
+
scheme = "bearer"
|
|
28
|
+
header = "Authorization"
|
|
29
|
+
|
|
30
|
+
[mcp.proxy]
|
|
31
|
+
upstream = "https://mcp.example.com/mcp"
|
|
32
|
+
upstream_credential = "service"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Merge the setting into the existing `[mcp.proxy]` table rather than adding a
|
|
36
|
+
duplicate. For a facade, attach `auth = "service"` to the relevant
|
|
37
|
+
`[[mcp.proxy.upstreams]]` entry instead. Do not store secret values in TOML,
|
|
38
|
+
command arguments, images, or the policy source.
|
|
39
|
+
|
|
40
|
+
### Check and inspect
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
snulbug mcp share doctor /var/lib/snulbug/share
|
|
44
|
+
snulbug mcp share status /var/lib/snulbug/share
|
|
45
|
+
snulbug mcp share report /var/lib/snulbug/share
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Doctor's `credentials` check resolves each used source once and adds
|
|
49
|
+
`upstream_credentials` to its JSON result. It reports missing/unreadable,
|
|
50
|
+
empty, malformed, or oversized values as failures. It warns about POSIX
|
|
51
|
+
group/other file permissions, credentials sent over non-loopback plain HTTP,
|
|
52
|
+
client Authorization passthrough, and HTTP credential references on stdio
|
|
53
|
+
transports. Hygiene warnings require review, not an automatic chmod or config
|
|
54
|
+
rewrite. Intentional private Docker networks may explain an HTTP warning;
|
|
55
|
+
snulbug cannot prove that such a network is private.
|
|
56
|
+
|
|
57
|
+
The console's **Auth** section has an **Upstream credentials** drawer with
|
|
58
|
+
source references, attached upstreams, last-check state, rotation guidance,
|
|
59
|
+
and the existing **Run doctor** action. Readiness fails for a recorded source
|
|
60
|
+
failure and requests review for unchecked, changed, or warning states. No
|
|
61
|
+
additional credential-management endpoint or secret-reveal control is added.
|
|
62
|
+
|
|
63
|
+
Offline doctor skips source resolution. Status, reports, and normal console
|
|
64
|
+
refreshes reuse saved diagnostics, never invoke brokers, and never record
|
|
65
|
+
secret values or hashes of them. A reference, route, or file stat change
|
|
66
|
+
invalidates saved availability and requires another doctor run. The input
|
|
67
|
+
digest covers references and file metadata only; it is not a secret fingerprint.
|
|
68
|
+
Doctor results are historical diagnostics, not an authorization decision or a
|
|
69
|
+
guarantee about the next request. The request path always resolves again.
|
|
70
|
+
|
|
71
|
+
Availability means **resolved in the checking process**, not accepted by the
|
|
72
|
+
upstream. Run doctor with the same service account and environment as the
|
|
73
|
+
gateway, or use the running console's action. A CLI process may have different
|
|
74
|
+
environment values or permissions. Opaque token expiry, revocation, audience,
|
|
75
|
+
and upstream privileges cannot be inferred from a successful local read; use
|
|
76
|
+
the existing health checks and request failure explanations to see upstream
|
|
77
|
+
401/403 responses.
|
|
78
|
+
|
|
79
|
+
### Rotation
|
|
80
|
+
|
|
81
|
+
- **File:** stage the new value in a protected file on the same filesystem,
|
|
82
|
+
set its service ownership and mode (`0600` or a deliberate read-only mode),
|
|
83
|
+
then atomically rename it over the referenced path. New requests read the
|
|
84
|
+
replacement without a gateway restart. Do not truncate/rewrite the live file.
|
|
85
|
+
Symlinks to regular files are supported, including projected container
|
|
86
|
+
secrets. A missing or invalid replacement fails new requests immediately.
|
|
87
|
+
- **Environment:** update the supervisor's protected environment file and
|
|
88
|
+
restart the gateway. Exporting a variable in another shell cannot modify a
|
|
89
|
+
running process's environment. There is no last-known-good cache to flush.
|
|
90
|
+
- **Plugin:** the broker owns its source-specific refresh and rotation policy.
|
|
91
|
+
Keep network resolution bounded; plugins run trusted Python code and snulbug
|
|
92
|
+
does not supply a universal vault timeout or refresh scheduler.
|
|
93
|
+
|
|
94
|
+
File sources must resolve to regular UTF-8 files, at most 16 KiB, with an
|
|
95
|
+
optional trailing newline. Nonregular sources (including FIFOs/devices) are
|
|
96
|
+
rejected before reading. Every broker's result must be a nonempty, bounded
|
|
97
|
+
single HTTP header value without control characters. Resolver exception text
|
|
98
|
+
is replaced with fixed diagnostics, including for plugin errors.
|
|
99
|
+
POSIX mode checks inspect the target file, not directory permissions, ACLs,
|
|
100
|
+
ownership, or Windows access controls; restrict those separately as part of
|
|
101
|
+
service provisioning.
|
|
102
|
+
|
|
103
|
+
Rotation applies at request/probe boundaries. An established SSE stream or
|
|
104
|
+
managed upstream session is not reauthenticated mid-flight. Arrange upstream
|
|
105
|
+
old/new-token overlap when needed; snulbug does not retry rejected calls or
|
|
106
|
+
guess whether side effects occurred. After replacement, run doctor again and
|
|
107
|
+
verify a safe client operation before revoking the old token upstream.
|
|
108
|
+
|
|
109
|
+
This check covers credentials attached to MCP HTTP/Holepunch upstreams. It does
|
|
110
|
+
not rotate client share bearers, invite renewal secrets, OAuth signing keys,
|
|
111
|
+
ngrok agent authtokens, SSH keys, or mounted applications' sessions. Keep using
|
|
112
|
+
their existing controls. HTTP mounts remain outside the MCP credential broker.
|
|
113
|
+
|
|
114
|
+
## Custom brokers
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from collections.abc import Mapping
|
|
118
|
+
from pathlib import Path
|
|
119
|
+
from typing import Any
|
|
120
|
+
|
|
121
|
+
from snulbug import CredentialBroker, register_credential_broker
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class AcmeVaultBroker(CredentialBroker):
|
|
125
|
+
type = "acme-vault"
|
|
126
|
+
|
|
127
|
+
def normalize_source(
|
|
128
|
+
self,
|
|
129
|
+
entry: Mapping[str, Any],
|
|
130
|
+
*,
|
|
131
|
+
base_dir: Path,
|
|
132
|
+
field: str,
|
|
133
|
+
resolve_relative_paths: bool,
|
|
134
|
+
) -> Mapping[str, Any]:
|
|
135
|
+
del base_dir, resolve_relative_paths
|
|
136
|
+
name = entry.get("name")
|
|
137
|
+
if not isinstance(name, str) or not name:
|
|
138
|
+
raise ValueError(f"{field}.name must be a non-empty credential name")
|
|
139
|
+
return {"name": name}
|
|
140
|
+
|
|
141
|
+
def resolve(self, credential: Mapping[str, Any]) -> str:
|
|
142
|
+
# Fetch or mint the secret here. Return the raw token value; snulbug
|
|
143
|
+
# applies the configured scheme before forwarding.
|
|
144
|
+
return fetch_from_acme_vault(str(credential["name"]))
|
|
145
|
+
|
|
146
|
+
def metadata(self, credential: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
147
|
+
# Return only audit-safe fields. Never return the resolved secret.
|
|
148
|
+
return {"name": credential.get("name")}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
register_credential_broker(AcmeVaultBroker(), replace=True)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Config uses the same `[mcp.fabric.credentials]` table as built-ins:
|
|
155
|
+
|
|
156
|
+
```toml
|
|
157
|
+
[mcp.fabric.credentials.codespace]
|
|
158
|
+
type = "acme-vault"
|
|
159
|
+
name = "codespace-mcp-token"
|
|
160
|
+
scheme = "bearer"
|
|
161
|
+
header = "Authorization"
|
|
162
|
+
|
|
163
|
+
[[mcp.proxy.upstreams]]
|
|
164
|
+
name = "codespace-files"
|
|
165
|
+
url = "https://example-codespace.github.dev/mcp"
|
|
166
|
+
auth = "codespace"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The broker is called when snulbug forwards a request, probes an upstream, or
|
|
170
|
+
explicitly checks its availability through live doctor/fabric diagnostics.
|
|
171
|
+
Audit logs, share contracts, fabric status, and replay logs receive only
|
|
172
|
+
`credential_metadata()` output.
|
|
@@ -10,8 +10,8 @@ servers with a shared control plane.
|
|
|
10
10
|
```json
|
|
11
11
|
{
|
|
12
12
|
"features": {
|
|
13
|
-
"ghcr.io/nahuaque/snulbug/features/snulbug:0.2.
|
|
14
|
-
"version": "0.2.
|
|
13
|
+
"ghcr.io/nahuaque/snulbug/features/snulbug:0.2.5": {
|
|
14
|
+
"version": "0.2.5",
|
|
15
15
|
"mode": "member-agent",
|
|
16
16
|
"policy_profile": "tunnel-safe",
|
|
17
17
|
"registry": "redis://redis:6379/0",
|