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.
- {snulbug-0.2.2 → snulbug-0.2.4}/CHANGELOG.md +29 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/PKG-INFO +8 -3
- {snulbug-0.2.2 → snulbug-0.2.4}/README.md +7 -2
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/README.md +1 -0
- snulbug-0.2.4/docs/always-on-runtime.md +385 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/auth-providers.md +5 -1
- snulbug-0.2.4/docs/credential-brokers.md +172 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/devcontainers.md +2 -2
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-auth-recipes.md +112 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-evidence.md +57 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-proxy.md +81 -5
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-share.md +58 -14
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/ngrok-end-to-end.md +118 -11
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/release.md +12 -2
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/share-doctor-checks.md +19 -0
- snulbug-0.2.4/docs/upgrading-to-0.2.4.md +112 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/.devcontainer/devcontainer.json +1 -1
- {snulbug-0.2.2 → snulbug-0.2.4}/features/snulbug/README.md +1 -1
- {snulbug-0.2.2 → snulbug-0.2.4}/features/snulbug/devcontainer-feature.json +1 -1
- {snulbug-0.2.2 → snulbug-0.2.4}/pyproject.toml +1 -1
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/__init__.py +1 -1
- snulbug-0.2.4/snulbug/_operations_smoke.py +336 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/auth_recipes.py +114 -7
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/rich_reports.py +21 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/rich_share.py +55 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/share.py +46 -6
- snulbug-0.2.4/snulbug/credential_health.py +248 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/credentials.py +62 -14
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/events.py +11 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/fabric.py +13 -9
- snulbug-0.2.4/snulbug/http_mounts.py +168 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/http_routes.py +105 -8
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/inspection.py +52 -9
- snulbug-0.2.4/snulbug/ngrok_drift.py +433 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/proxy.py +146 -28
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/redaction.py +4 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/release_qa.py +42 -0
- snulbug-0.2.4/snulbug/request_explanations.py +348 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/share.py +195 -13
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/share_console.py +285 -443
- snulbug-0.2.4/snulbug/share_runtime.py +642 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/share_session.py +1 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/simulator.py +1 -1
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/tunnel.py +35 -20
- snulbug-0.2.4/tests/fixtures/pocket_id/README.md +19 -0
- snulbug-0.2.4/tests/fixtures/pocket_id/oauth.json +66 -0
- snulbug-0.2.4/tests/test_credential_health.py +283 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_fabric.py +2 -1
- snulbug-0.2.4/tests/test_gateway_snapshot.py +54 -0
- snulbug-0.2.4/tests/test_http_mounts.py +232 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_http_routes.py +103 -0
- snulbug-0.2.4/tests/test_ngrok_drift.py +361 -0
- snulbug-0.2.4/tests/test_operations_smoke.py +45 -0
- snulbug-0.2.4/tests/test_pocket_id_auth.py +345 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_proxy.py +59 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_release_qa.py +28 -6
- snulbug-0.2.4/tests/test_request_explanations.py +427 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_share_console.py +95 -12
- snulbug-0.2.4/tests/test_share_runtime.py +580 -0
- snulbug-0.2.2/docs/credential-brokers.md +0 -67
- {snulbug-0.2.2 → snulbug-0.2.4}/.gitignore +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/CODE_OF_CONDUCT.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/CONTRIBUTING.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/LICENSE +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/SECURITY.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/actions.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/aws-mcp.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/bundles.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/ci-policy-gates.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/comparison.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/discovery-providers.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/event-sink-providers.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/evidence-exporters.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/getting-started.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/lua-policy-dsl.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/lua-request-api.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-client-recipes.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-fabric.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-gateway.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-guide.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-impact.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-learn.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-policy.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-presets.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-protocol.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-recorder.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/mcp-schemas.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/policy-deny-backoff.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/quickstart.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/roadmap.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/security-model.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/state.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/tool-catalog-projection.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/tool-risk-analyzers.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/tunnel-providers.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/docs/upstream-transports.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/auth_claim_patterns/.gitignore +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/auth_claim_patterns/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/auth_claim_patterns/ci-workload-identity.toml +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/auth_claim_patterns/group-gated-tools.toml +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/auth_claim_patterns/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/auth_claim_patterns/tenant-isolation.toml +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/basic/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/basic/app.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/fixtures/duplicate-delivery.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/fixtures/first-delivery.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/manifest.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/snapshots/duplicate.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/idempotency.snulbug/snapshots/empty.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/fixtures/allowed-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/fixtures/blocked-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/fixtures/unauthenticated.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/manifest.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/bundles/mcp-gateway.snulbug/snapshots/empty.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/mcp-client.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/mock_mcp_server.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/snulbug.env-gateway.toml +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/codespace_local_gateway/snulbug.local-gateway.toml +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/app.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/policies/acme.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/policies/default.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/policies/globex.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/requests/acme-invalid.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/requests/acme-valid.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/requests/globex-sandbox.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/customer_policy/requests/unknown-tenant.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/github-actions/snulbug-policy-gates.yml +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/.gitignore +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/Dockerfile.gateway +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/auth/keycloak/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/auth/keycloak/auth-init.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/auth/keycloak/client-token-request.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/auth/keycloak/commands.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/auth/keycloak/snulbug.auth.toml +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/docker-compose.yml +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/get-token.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/keycloak/snulbug-demo-realm.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/mock_mcp_server.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/policy.snulbug/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/requests/blocked-write-file.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/requests/read-file.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/requests/tools-list.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/keycloak_oauth_demo/snulbug.toml +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/Dockerfile.gateway +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/Dockerfile.remote-peer +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/docker-compose.yml +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/hypertele-client.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/hypertele-server.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/mcp-client.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/mock_mcp_server.js +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/mock_mcp_server.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/snulbug.facade.toml +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_container_facade/snulbug.local.toml +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_gateway/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_gateway/app.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/.gitignore +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/requests/blocked-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/requests/safe-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/requests/tools-list.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/run_demo.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/mcp_proxy_demo/upstream.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/policy_promotion/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/policy_promotion/active.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/policy_promotion/draft.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/policy_promotion/fixtures/acme-invalid.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/policy_promotion/fixtures/acme-valid.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/provider_policy_templates/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/provider_policy_templates/cloudflare-access-group-gate.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/provider_policy_templates/entra-app-role-gate.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/provider_policy_templates/github-actions-workload-gate.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/provider_policy_templates/keycloak-role-gate.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/state_replay/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/state_replay/duplicate-state.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/state_replay/idempotency.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/state_replay/request.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/app.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/policies/github.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/policies/stripe.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/policies/unknown.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/requests/github-push.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/requests/stripe-invoice.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/requests/stripe-malformed.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/examples/webhook_normalization/requests/unknown-vendor.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/features/snulbug/install.sh +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/__main__.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/assets/prism.css +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/assets/prism.js +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/auth_providers.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/auth-required.snulbug/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/auth-required.snulbug/fixtures/authenticated.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/auth-required.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/auth-required.snulbug/manifest.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/auth-required.snulbug/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/contexts/inventory-lease.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/contexts/sandbox-change-lease.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/data-read.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/iam-delete-user.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/inventory-read.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/knowledge-search.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/fixtures/sandbox-mutation.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/manifest.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/aws-mcp.snulbug/snapshots/empty.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/fixtures/safe-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/fixtures/unsafe-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/manifest.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/local-dev-safe.snulbug/snapshots/empty.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/fixtures/safe-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/fixtures/shell-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/manifest.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/no-shell-tools.snulbug/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/fixtures/absolute-path.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/fixtures/allowed-path.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/fixtures/traversal-path.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/fixtures/unsafe-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/manifest.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/project-path-allowlist.snulbug/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/fixtures/safe-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/fixtures/tools-list.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/fixtures/write-method.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/manifest.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/read-only-local-dev.snulbug/snapshots/empty.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/fixtures/safe-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/fixtures/tools-list.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/fixtures/unsafe-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/manifest.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tool-allowlist.snulbug/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/fixtures/batch-request.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/fixtures/safe-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/fixtures/unsafe-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/manifest.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/tunnel-safe.snulbug/snapshots/empty.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/allowed-read.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/missing-token.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/secret-path.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/traversal-path.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/fixtures/unsafe-tool.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/manifest.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/builtin_presets/mcp/workspace-firewall.snulbug/policy.lua +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/bundle.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/__init__.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/common.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/evidence.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/fabric.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/policy.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli/schemas.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cli_helpers.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/cloudflare_access.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/codespaces.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/config.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/confirm.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/control_events.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/controller.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/discovery.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/evidence_exporters.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/fabric_control.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/fabric_members.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/fabric_runtime.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/gateway_templates.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/guide.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/impact.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/json_schema.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/lab.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/learn.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/leases.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/manifests.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_auth.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_cache.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_capabilities.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_client_requests.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_completion.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_mrtr.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_parameter_headers.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_policy_bundles.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_progress.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_protocol.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_resources.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_schema_policy.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_schemas.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_spec_conformance.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_stdio.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_stream.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_subscriptions.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_tasks.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/mcp_tools.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/middleware.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/policy_activation.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/policy_backoff.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/policy_review.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/presets.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/promotion.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/py.typed +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/quickstart.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/recorder.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/response_policy.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/runtime.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/sarif.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/scaffolds.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/schema_policy.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/share_doctor.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/state.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/tool_catalog.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/tool_risk.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/snulbug/upstream_transports.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/LICENSE +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/README.md +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/dependentSchemas.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/dynamicRef.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/if-then-else.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/prefixItems.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/json_schema_2020_12/unevaluatedProperties.json +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/fixtures/stdio_subscriptions.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_auth_claim_patterns.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_auth_recipes.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_automation_invites.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_cli_helpers.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_cloudflare_access.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_codespaces.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_config.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_credentials.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_customer_policy_demo.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_devcontainer_feature.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_discovery.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_events.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_evidence_exporters.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_fabric_controller.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_json_schema.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_keycloak_oauth_demo.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_leases.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_manifests.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_cache.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_gateway_demo.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_guide.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_helpers.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_impact.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_inspection.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_lab.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_learn.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_mrtr.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_parameter_headers.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_policy_bundles.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_presets.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_progress.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_protocol.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_proxy_demo.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_quickstart.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_recorder.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_resources.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_schema_policy.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_schemas.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_share.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_spec_conformance.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_stdio.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_stream.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_subscriptions.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_mcp_tools.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_middleware.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_policy_bundle.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_policy_promotion.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_policy_state.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_provider_policy_templates.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_redaction_audit.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_response_policy.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_sandbox_abuse.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_scaffolds.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_state_snapshots.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_tool_catalog.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_tool_risk.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_tunnel_audit.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_tunnel_doctor.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_tunnel_init.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_upstream_transports.py +0 -0
- {snulbug-0.2.2 → snulbug-0.2.4}/tests/test_webhook_normalization_demo.py +0 -0
- {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.
|
|
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`
|
|
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`
|
|
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
|