Skip to content

refactor(plugins): decouple plugin framework from gateway settings#2829

Closed
araujof wants to merge 2255 commits intomainfrom
refactor/plugins_settings
Closed

refactor(plugins): decouple plugin framework from gateway settings#2829
araujof wants to merge 2255 commits intomainfrom
refactor/plugins_settings

Conversation

@araujof
Copy link
Copy Markdown
Member

@araujof araujof commented Feb 11, 2026

Description

Introduces a self-contained PluginsSettings configuration class for the plugin framework, eliminating all os.environ reads and imports from mcpgateway.config.settings and mcpgateway.services.http_client_service. The plugin framework now owns its configuration and can operate independently of the gateway.

Closes: #2831

Problem

Multiple plugin framework modules imported settings from mcpgateway.config, the MCP client imported HTTP helpers from mcpgateway.services.http_client_service, and every from_env() factory method in models.py read os.environ directly with hand-rolled boolean parsing. This created tight coupling from the plugin framework back into the gateway — the opposite of the desired direction for ADR-019 modular architecture.

Solution

  • Created mcpgateway/plugins/framework/settings.py with a PluginsSettings class using pydantic_settings and the PLUGINS_ env var prefix
  • Consolidated all plugin-related env var reads into PluginsSettings: core config, HTTP client tuning, SSL/TLS (mTLS client, server SSL, gRPC client/server TLS), server bind, transport runtime, Unix socket, and CLI options
  • Replaced get_http_timeout() and get_default_verify() calls in the MCP client with direct usage of settings.httpx_* and settings.skip_ssl_verify
  • Migrated all from_env() factory methods in models.py (MCPClientTLSConfig, MCPServerTLSConfig, MCPServerConfig, GRPCClientTLSConfig, GRPCServerTLSConfig, GRPCServerConfig, UnixSocketServerConfig) from raw os.environ reads to PluginsSettings
  • Removed duplicate _parse_bool() static methods from MCPTransportTLSConfigBase and MCPServerConfig (pydantic handles type coercion)
  • Updated get_plugin_manager(), cli.py, and all external server runtimes (MCP, gRPC, Unix) to use the framework's own settings
  • Added settings.plugins property on LazySettingsWrapper so gateway code accesses plugin settings via settings.plugins.enabled instead of settings.plugins_enabled
  • Simplified gateway services (main.py, admin.py, prompt_service.py, resource_service.py, tool_service.py) by replacing manual os.getenv("PLUGINS_ENABLED") parsing with settings.plugins.enabled
  • Removed plugins_enabled and plugin_config_file fields from gateway Settings class
  • Removed unused PYTHON constant from constants.py
  • Standardized env var naming: PLUGIN_CONFIG_FILEPLUGINS_CONFIG_FILE (legacy name supported via AliasChoices for backwards compatibility)

Configuration mapping

Field names are chosen so that the PLUGINS_ env prefix produces clean env var names (e.g., field enabledPLUGINS_ENABLED).

Gateway env var Plugin framework env var Default Notes
PLUGINS_ENABLED PLUGINS_ENABLED false Shared
PLUGIN_CONFIG_FILE PLUGINS_CONFIG_FILE plugins/config.yaml Legacy alias supported
HTTPX_CONNECT_TIMEOUT PLUGINS_HTTPX_CONNECT_TIMEOUT 5.0 Scoped to plugins
HTTPX_READ_TIMEOUT PLUGINS_HTTPX_READ_TIMEOUT 120.0 Scoped to plugins
SKIP_SSL_VERIFY PLUGINS_SKIP_SSL_VERIFY false Scoped to plugins
PLUGINS_CLI_COMPLETION PLUGINS_CLI_COMPLETION false Shared
PLUGINS_CLI_MARKUP_MODE PLUGINS_CLI_MARKUP_MODE (none) Shared
(various PLUGINS_*) (see PluginsSettings for full list: mTLS, server SSL, gRPC TLS, server bind, transport, Unix socket)

Changes

Core

File Change
mcpgateway/plugins/framework/settings.py NewPluginsSettings class with PLUGINS_ env prefix covering all plugin framework configuration (HTTP client, TLS/mTLS, server bind, transport, CLI)
mcpgateway/plugins/framework/models.py Migrated all 7 from_env() factory methods from os.environ reads to PluginsSettings; removed duplicate _parse_bool() methods
mcpgateway/plugins/framework/__init__.py get_plugin_manager() uses mcpgateway.plugins.framework.settings instead of mcpgateway.config
mcpgateway/plugins/framework/external/mcp/client.py Replaced mcpgateway.config.settings and mcpgateway.services.http_client_service imports with framework settings; httpx.Timeout built from settings.httpx_* values
mcpgateway/plugins/framework/constants.py Removed unused PYTHON constant
mcpgateway/plugins/tools/cli.py Replaced mcpgateway.config.settings with mcpgateway.plugins.framework.settings

External server runtimes

File Change
mcpgateway/plugins/framework/external/mcp/server/runtime.py PLUGINS_TRANSPORT env var read replaced with PluginsSettings().transport
mcpgateway/plugins/framework/external/mcp/server/server.py PLUGINS_CONFIG_PATH env var read replaced with PluginsSettings().config_path
mcpgateway/plugins/framework/external/grpc/server/runtime.py PLUGINS_CONFIG_PATH env var read replaced with PluginsSettings().config_path
mcpgateway/plugins/framework/external/unix/server/runtime.py PLUGINS_CONFIG_PATH and UNIX_SOCKET_PATH env var reads replaced with PluginsSettings()

Gateway integration

File Change
mcpgateway/config.py Removed plugins_enabled and plugin_config_file fields from Settings; added settings.plugins property on LazySettingsWrapper
mcpgateway/main.py Replaced manual os.getenv("PLUGINS_ENABLED") parsing with settings.plugins.enabled / settings.plugins.config_file
mcpgateway/admin.py settings.plugins_enabledsettings.plugins.enabled
mcpgateway/services/prompt_service.py Replaced manual env var parsing with settings.plugins.enabled / settings.plugins.config_file
mcpgateway/services/resource_service.py Replaced manual env var parsing with settings.plugins.enabled / settings.plugins.config_file
mcpgateway/services/tool_service.py Replaced manual env var parsing with settings.plugins.enabled / settings.plugins.config_file
mcpgateway/tools/builder/common.py PLUGIN_CONFIG_FILEPLUGINS_CONFIG_FILE in K8s manifest generation

Documentation and configuration

File Change
.env.example Consolidated all PLUGINS_* env vars into a single "Plugin Framework Settings" section with descriptions
docs/docs/manage/configuration.md Added "Plugin Framework (Standalone) Settings" reference table
docs/docs/using/plugins/index.md Updated quick-start with PLUGINS_CONFIG_FILE; added standalone settings note
docs/docs/using/plugins/grpc-transport.md Added PLUGINS_CONFIG_FILE alongside PLUGIN_CONFIG_FILE
docs/docs/architecture/adr/019-modular-architecture-split.md Added PLUGINS_CONFIG_FILE
charts/mcp-stack/values.yaml Renamed PLUGIN_CONFIG_FILEPLUGINS_CONFIG_FILE; added standalone framework settings
charts/mcp-stack/templates/deployment-mcpgateway.yaml Updated volume mount to prefer PLUGINS_CONFIG_FILE with fallback
charts/mcp-stack/README.md Updated Helm values table
plugins/AGENTS.md PLUGIN_CONFIG_FILEPLUGINS_CONFIG_FILE
plugins/README.md Added PLUGINS_CONFIG_FILE
AGENTS.md PLUGIN_CONFIG_FILEPLUGINS_CONFIG_FILE

Tests

File Change
tests/unit/.../framework/test_settings.py New — 23 tests: default values, PLUGINS_-prefixed env var overrides, legacy alias (PLUGIN_CONFIG_FILE), module singleton stability
tests/unit/.../framework/test_plugin_models.py Updated from_env() tests to use PLUGINS_-prefixed env vars via PluginsSettings
tests/unit/.../framework/test_plugin_models_coverage.py Updated from_env() tests for PluginsSettings migration
tests/unit/.../grpc/test_grpc_models.py Updated gRPC from_env() tests for PluginsSettings migration
tests/unit/.../services/test_tool_service_coverage.py Updated plugin-enabled tests to monkeypatch PluginsSettings singleton
tests/unit/.../services/test_resource_service_plugins.py Updated plugin-enabled tests to monkeypatch PluginsSettings singleton
tests/unit/.../integration/test_cross_hook_context_sharing.py Minor import adjustment
tests/unit/.../integration/test_resource_plugin_integration.py Minor import adjustment
tests/unit/.../middleware/test_http_auth_integration.py Minor import adjustment

shoummu1 and others added 30 commits January 27, 2026 21:32
Signed-off-by: Shoumi <shoumimukherjee@gmail.com>
* Add profling tools, memray

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Add profling tools, memray

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(db): release DB sessions before external HTTP calls to prevent pool exhaustion

This commit addresses issue #2518 where DB connection pool exhaustion occurred
during A2A and RPC tool calls due to sessions being held during slow upstream
HTTP requests.

Changes:
- tool_service.py: Extract A2A agent data to local variables before calling
  db.commit(), allowing HTTP calls to proceed without holding the DB session.
  The A2A tool invocation logic now uses pre-extracted data instead of querying
  during the HTTP call phase.

- rbac.py: Add db.commit() and db.close() calls before returning user context
  in all authentication paths (proxy, anonymous, disabled auth). This ensures
  DB sessions are released early and not held during subsequent request processing.

- test_rbac.py: Update test to provide mock db parameter and verify that
  db.commit() and db.close() are called for proper session cleanup.

The fix follows the pattern established in other services: extract all needed
data from ORM objects, call db.commit() to release the transaction, then
proceed with external HTTP calls. This prevents "idle in transaction" states
that exhaust PgBouncer's connection pool under high load.

Load test results (4000 concurrent users, 1M+ requests):
- Success rate: 99.81%
- 502 errors reduced to 0.02% (edge cases with very slow upstreams)
- P50: 450ms, P95: 4300ms

Closes #2518

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* perf(config): tune connection pools for high concurrency

Based on profiling with 4000 concurrent users (~2000 RPS):

- MCP_SESSION_POOL_MAX_PER_KEY: 50 → 200 (reduce session creation)
- IDLE_TRANSACTION_TIMEOUT: 120s → 300s (handle slow MCP calls)
- CLIENT_IDLE_TIMEOUT: 120s → 300s (align with transaction timeout)
- HTTPX_MAX_CONNECTIONS: 200 → 500 (more outbound capacity)
- HTTPX_MAX_KEEPALIVE_CONNECTIONS: 100 → 300
- REDIS_MAX_CONNECTIONS: 150 → 100 (stay under maxclients)

Results:
- Failure rate: 0.446% → 0.102% (4.4x improvement)
- RPC latency: 3,014ms → 1,740ms (42% faster)
- CRUD latency: 1,207ms → 508ms (58% faster)

See: todo/profile-full.md for detailed analysis
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* fix(helm): stabilize chart templates and configs

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(helm): align migration job with bootstrap

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs(helm): refresh chart README

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* docs: sync env defaults and references

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs: sync env templates and performance tuning

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* chore: stabilize coverage target

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* chore: reduce test warnings

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* chore: reduce test startup costs

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* chore: resolve bandit warning

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* test(playwright): handle admin password change

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* test(playwright): stabilize admin UI flows

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…2534)

The MCP specification does not mandate that tool names must start with
a letter - tool names are simply strings without pattern restrictions.
This fix updates the validation pattern to align with SEP-986.

Changes:
- Update VALIDATION_TOOL_NAME_PATTERN from ^[a-zA-Z][a-zA-Z0-9._-]*$
  to ^[a-zA-Z0-9_][a-zA-Z0-9._/-]*$ per SEP-986
- Allow leading underscore/number and slashes in tool names
- Remove / from HTML special characters regex (not XSS-relevant)
- Update all error messages, docstrings, and documentation
- Update tests to verify new valid cases

Tool names like `_5gpt_query_by_market_id` and `namespace/tool` are
now accepted.

Closes #2528

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…figuration (#2515)

- Add passphrase-protected key support for Granian via --ssl-keyfile-password
- Add KEY_FILE_PASSWORD and CERT_PASSPHRASE compatibility in run-granian.sh
- Export KEY_FILE in run-gunicorn.sh for Python SSL manager access
- Improve Makefile cert targets with proper permissions (640) and group 0
- Split certs-passphrase into two-step generation (genrsa + req) for AES-256
- Add SSL configuration templates to nginx.conf for client and backend TLS
- Expose port 443 in NGINX Dockerfile for HTTPS support
- Update docker-compose.yml with TLS-related comments and correct cert paths
- Add comprehensive TLS configuration documentation

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
…2537)

During gateway activation with OAuth Authorization Code flow,
`_initialize_gateway` returns empty lists because the user hasn't
completed authorization yet. Health checks then treat these empty
responses as legitimate and delete all existing tools/resources/prompts.

This change adds an `oauth_auto_fetch_tool_flag` parameter to
`_initialize_gateway` that:

- When False (default): Returns empty lists for auth_code gateways
  during health checks, preserving existing tools
- When True (activation): Skips the early return for auth_code
  gateways, allowing activation to proceed

The existing check in `_refresh_gateway_tools_resources_prompts` at
lines 4724-4729 prevents stale deletion for auth_code gateways with
empty responses.

Fixed issues from original PR:
- Corrected typo: oath -> oauth in parameter name
- Removed duplicate docstring entry
- Fixed logic bug that incorrectly skipped token fetch for
  client_credentials flow when flag was True


Closes #2272

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
* feat(auth): add token revocation and proxy auth to admin middleware

- Support token revocation checks in AdminAuthMiddleware
- Enable proxy authentication for admin routes
- Filter session listings by user ownership
- Validate team membership for OAuth operations
- Add configurable public registration setting

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(config): change token validation defaults to secure-by-default

- Set require_token_expiration default to true (was false)
- Set require_jti default to true (was false)
- Update .env.example to reflect new secure defaults

Tokens without expiration or JTI claims will now be rejected by default.
Set REQUIRE_TOKEN_EXPIRATION=false or REQUIRE_JTI=false to restore
previous behavior if needed for backward compatibility.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs(security): expand securing guide with token lifecycle and access controls

Add documentation for:
- Token lifecycle management (revocation, validation settings)
- Admin route authentication requirements
- Session management access controls
- User registration configuration
- Updated production checklist with new settings

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(auth): address SSO redirect validation and admin middleware gaps

- SSO redirect_uri validation now uses server-side allowlist only
  (allowed_origins, app_domain) instead of trusting Host header
- Full origin comparison including scheme and port to prevent
  cross-port or HTTP downgrade redirects
- AdminAuthMiddleware now supports API token authentication
- AdminAuthMiddleware now honors platform admin bootstrap when
  REQUIRE_USER_IN_DB=false for fresh deployments

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(auth): add basic auth support to AdminAuthMiddleware

Align AdminAuthMiddleware with require_admin_auth by supporting:
- HTTP Basic authentication for legacy deployments
- Basic auth users are treated as admin (consistent with existing behavior)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(auth): finalize secure defaults and update changelog for RC1

- Move hashlib/base64 imports to top-level in main.py (pylint C0415)
- Add CHANGELOG entry for 1.0.0-RC1 secure defaults release
- Add Security Defaults section to .env.example
- Update test helpers to include JTI by default for REQUIRE_JTI=true

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* refactor(auth): streamline authentication model and update documentation

- Simplify Admin UI to use session-based email/password authentication
- Add API_ALLOW_BASIC_AUTH setting for granular API auth control
- Scope gateway credentials to prevent unintended forwarding
- Update 25+ documentation files for auth model clarity
- Add comprehensive test coverage for auth settings
- Fix REQUIRE_TOKEN_EXPIRATION and REQUIRE_JTI defaults in docs
- Remove BASIC_AUTH_* from Docker examples (not needed by default)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs: update changelog with neutral language and ignore coverage.svg

- Reword RC1 changelog entries to use neutral language
- Add coverage.svg to .gitignore (generated by make coverage)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
#2514)

Refactors GatewayService, ExportService, ImportService, and A2AService to use
globally-initialized service singletons (ToolService, PromptService,
ResourceService, ServerService, RootService, GatewayService) instead of
creating private, uninitialized instances.

Uses lazy singleton pattern with __getattr__ to avoid import-time instantiation
when only exception classes are imported. This ensures services are created
after logging/plugin setup is complete.

By importing the module-level services, all gateway operations now share the
same EventService/Redis client. This ensures events such as activate/deactivate
propagate correctly across workers and reach Redis subscribers.

Changes:
- Add lazy singleton pattern using __getattr__ to service modules
- Update main.py to import singletons instead of instantiating services
- Update GatewayService.__init__ to use lazy imports of singletons
- Update ExportService.__init__ to use lazy imports of singletons
- Update ImportService.__init__ to use lazy imports of singletons
- Update A2AService methods to use tool_service singleton
- Update tests to patch singleton methods instead of class instantiation
- Add pylint disables for no-name-in-module (due to __getattr__)

The fix resolves silent event drops caused by missing initialize() calls on
locally constructed services. Cross-worker UI updates and subscriber
notifications now behave as intended.

Closes #2256

Signed-off-by: NAYANAR <nayana.r7813@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
* feat: support external plugin stdio launch options

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* feat: add streamable http uds support

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: tidy streamable http shutdown

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* style: fix docstring line length in client.py

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(security): harden UDS and cwd path validation

- Add canonical path resolution (.resolve()) to cwd validation to prevent
  path traversal via symlinks or relative path escapes
- Add UDS security validation:
  - Require absolute paths for Unix domain sockets
  - Verify parent directory exists
  - Warn if parent directory is world-writable (potential socket hijacking)
- Return canonical resolved paths instead of raw input
- Update tests to use tmp_path fixture for secure temp directories

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* style: fix pylint warnings in models.py

Move logging import to top level and fix implicit string concatenation.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
)

* feat(infra): add zero-config TLS for nginx via Docker Compose profile

Add a new `--profile tls` Docker Compose profile that enables HTTPS
with zero configuration. Certificates are auto-generated on first run
or users can provide their own CA-signed certificates.

Features:
- One command TLS: `make compose-tls` starts with HTTPS on port 8443
- Auto-generates self-signed certs if ./certs/ is empty
- Custom certs: place cert.pem/key.pem in ./certs/ before starting
- Optional HTTP->HTTPS redirect via `make compose-tls-https`
- Environment variable NGINX_FORCE_HTTPS=true for redirect mode
- Works alongside other profiles (monitoring, benchmark)

New files:
- infra/nginx/nginx-tls.conf: TLS-enabled nginx configuration
- infra/nginx/docker-entrypoint.sh: Handles NGINX_FORCE_HTTPS env var

New Makefile targets:
- compose-tls: Start with HTTP:8080 + HTTPS:8443
- compose-tls-https: Force HTTPS redirect (HTTP->HTTPS)
- compose-tls-down: Stop TLS stack
- compose-tls-logs: Tail TLS service logs
- compose-tls-ps: Show TLS stack status

Docker Compose additions:
- cert_init service: Auto-generates certs using alpine/openssl
- nginx_tls service: TLS-enabled nginx reverse proxy

Documentation:
- Updated tls-configuration.md with Quick Start section
- Updated compose.md with TLS section
- Added to deployment navigation
- Updated README.md quick start

Closes #2571

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(nginx): use smart port detection for HTTPS redirect

Fix hard-coded :8443 port in HTTPS redirect that broke internal
container-to-container calls.

Problem:
- External access via port 8080 correctly redirected to :8443
- Internal container calls (no port) also redirected to :8443
- But nginx_tls only listens on 443 internally, so internal redirects failed

Solution:
Add a map directive that detects request origin based on Host header:
- Requests with :8080 in Host → redirect to :8443 (external)
- Requests without port → redirect without port, defaults to 443 (internal)

Tested:
- External: curl http://localhost:8080/health → https://localhost:8443/health ✓
- Internal: curl http://nginx_tls/health → https://nginx_tls/health (443) ✓

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
)

* fix: resolve LLM admin router db session and add favicon redirect

- Fix LLM admin router endpoints that failed with 500 errors due to
  db session being None from RBAC middleware (intentionally closed
  to prevent idle-in-transaction). Added explicit db: Session =
  Depends(get_db) to all 11 affected endpoints.

- Add /favicon.ico redirect to /static/favicon.ico for browser
  compatibility (browsers request favicon at root path).

- Update README.md Running section with clear table documenting
  the three running modes (make dev, make serve, docker-compose)
  with their respective ports, servers, and databases.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(llm-admin): pass kwargs to fetch_provider_models for permission check

The require_permission decorator only searches kwargs for user context.
sync_provider_models was calling fetch_provider_models with positional
args, causing the decorator to raise 401 Unauthorized.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* feat(testing): add JMeter performance testing baseline

Add comprehensive JMeter test plans for industry-standard performance
baseline measurements and CI/CD integration.

Test Plans (10 .jmx files):
- rest_api_baseline: REST API endpoints (1,000 RPS, 10min)
- mcp_jsonrpc_baseline: MCP JSON-RPC protocol (1,000 RPS, 15min)
- mcp_test_servers_baseline: Direct MCP server testing (2,000 RPS)
- load_test: Production load simulation (4,000 RPS, 30min)
- stress_test: Progressive stress to breaking point (10,000 RPS)
- spike_test: Traffic spike recovery (1K→10K→1K)
- soak_test: 24-hour memory leak detection (2,000 RPS)
- sse_streaming_baseline: SSE connection stability (1,000 conn)
- websocket_baseline: WebSocket performance (500 conn)
- admin_ui_baseline: Admin UI user simulation (50 users)

Infrastructure:
- 12 Makefile targets for running tests and generating reports
- Properties files for production and CI environments
- CSV test data for parameterized testing
- Performance SLAs documentation (P50/P95/P99 latencies)

Closes #2541

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(testing): improve JMeter testing setup and fix test issues

- Add jmeter-install target to download JMeter 5.6.3 locally
- Add jmeter-ui target to launch JMeter GUI
- Add jmeter-check to verify JMeter 5.x+ (required for -e -o flags)
- Add jmeter-clean target to clean results directory
- Fix jmeter-report to handle empty results gracefully
- Fix load_test.jmx JEXL3 thread count expressions
- Fix admin_ui_baseline.jmx HTMX endpoint paths
- Add HTTPS/TLS testing documentation and configuration
- Add .jmeter/ to .gitignore for local installation

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(testing): fix JMeter JWT auth and add linter fixes

- Fix JMETER_TOKEN generation: use python3 instead of python
- Add JMETER_JWT_SECRET with default value (my-test-key)
- Add encoding headers and fix import formatting from linter

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* feat(testing): add jmeter-quick target for fast test verification

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
- Add .envrc for direnv support
- Remove 14+ duplicate/redundant patterns
- Reorganize with clear section comments
- Add missing patterns (.ica.env, pip-log.txt, pip-delete-this-directory.txt)

Signed-off-by: Adnan Vahora <adnanvahora114@gmail.com>
* feat(plugins): add TOON encoder plugin for token-efficient responses

Add a tool_post_invoke plugin that converts JSON tool results to TOON
(Token-Oriented Object Notation) format, achieving 30-70% token reduction.

Features:
- Pure Python TOON encoder/decoder per spec v3.0
- Configurable size thresholds and tool filtering
- Format markers for downstream parsing
- Graceful error handling with skip_on_error fallback
- Columnar format for homogeneous object arrays

Closes #2574

Signed-off-by: Joe Stein <joe.stein@sscinc.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* lint

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs(toon): document alternative delimiter limitation

Add documentation about tab/pipe delimiter limitation in columnar
array headers. The TOON spec v3.0 allows alternative delimiters,
which our regex matches but decoder doesn't parse correctly (always
splits on commas). Document this as a known decoder limitation.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* feat(toon): support tab/pipe delimiters in columnar arrays

Add support for alternative delimiters (tab, pipe) in columnar array
headers per TOON spec v3.0. The decoder now detects the delimiter from
the header and uses it consistently for parsing row values.

- Add _detect_delimiter() function to identify delimiter from header
- Update _decode_columnar_array() to accept and use delimiter parameter
- Update _split_row_values() to split on configurable delimiter
- Add tests for pipe and tab delimiter decoding
- Remove limitation from README (now fully supported)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(toon): remove unused import and variable

- Remove unused Union import (F401)
- Remove unused ind variable in _encode_array (F841)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(toon): prefix unused parameters with underscore

Silence vulture warnings by prefixing intentionally unused parameters:
- _as_root in _encode_array and _encode_object (for API consistency)
- _expected_count in _split_row_values (for potential validation)
- _context in tool_post_invoke (required by plugin interface)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(admin): return disabled plugin details in View Details

get_plugin_by_name() only checked the registry for enabled plugins,
causing "Not Found" errors when clicking View Details on disabled
plugins. Now falls back to checking config.plugins for disabled
plugins, matching the behavior of get_all_plugins().

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Joe Stein <joe.stein@sscinc.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
- allow overriding the python runtime for external plugins
- reset plugin registry before re-init to avoid stale entries
- normalize resource/service tag lists to strings

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…2605)

Add 409 to allowed response codes for state change endpoints in the
Locust load test. Under high concurrency, 409 Conflict is expected
behavior due to optimistic locking when multiple users try to toggle
the same entity's state simultaneously.

Updated endpoints:
- set_server_state() - /servers/[id]/state
- set_tool_state() - /tools/[id]/state
- set_resource_state() - /resources/[id]/state
- set_prompt_state() - /prompts/[id]/state
- set_gateway_state() - /gateways/[id]/state

Closes #2566

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* test: expand coverage unit tests and plan

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* chore: remove local test plan from repo

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* docs: rationalize README and move detailed content to docs

- Reduce README from 2,502 to 960 lines (-62%)
- Add Quick Links section linking to pinned issues (#2502, #2503, #2504)
- Move environment variables to docs/docs/manage/configuration.md
- Create docs/docs/manage/troubleshooting.md with detailed guides
- Add VS Code Dev Container section to developer-onboarding.md
- Use <details> collapsibles for advanced Docker/Podman/PostgreSQL content
- Streamline Configuration section to essential variables only
- Update version reference from v0.9.0 to 1.0.0-BETA-2
- Verify all 15 ToC anchors and 17 external doc links

Closes #2365

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* chore(docs): bump documentation dependency versions

- mkdocs-git-revision-date-localized-plugin: 1.5.0 → 1.5.1
- mkdocs-include-markdown-plugin: 7.2.0 → 7.2.1
- pathspec: 1.0.3 → 1.0.4

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(docs): add missing blank lines before tables in index.md

MkDocs requires blank lines between bold headers and tables for
proper rendering. Fixed SSO configuration sections.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs: streamline docs landing page and fix broken links

- Replace verbose docs/docs/index.md with streamlined content matching README
- Convert GitHub-flavored <details> to MkDocs ??? admonitions
- Use relative links for internal navigation
- Fix broken #configuration-env-or-env-vars anchors in:
  - docs/docs/development/index.md
  - docs/docs/manage/securing.md
- Reduce docs landing page from 2,603 to 678 lines (-74%)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Add is_active field support through the complete request pipeline:

- Schemas: Added is_active to TokenCreateRequest (bool, default=True)
  and TokenUpdateRequest (Optional[bool], default=None)
- Service: Modified create_token() and update_token() methods to accept
  and use is_active parameter instead of hardcoding
- Router: Updated all 3 token endpoints (create, update, create_team)
  to pass is_active=request.is_active
- Tests: Added explicit coverage for is_active=False on create and
  update, including toggle and reactivation scenarios

Backward compatible: default values maintain existing behavior for
clients not sending the field.

Closes #2573

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* feat(testing): add Batch 1 & 2 load test user classes for extended API coverage

Add new Locust user classes to improve API endpoint coverage:

Batch 1 - High Priority:
- VersionMetaUser: /version, /health/security
- ExportImportUser: /export, /import/status, /import/cleanup
- A2AFullCRUDUser: A2A agent CRUD operations

Batch 2 - Extended APIs:
- ResourcesExtendedUser: /resources/templates/list, /resources/[id]/info
- ServerExtendedUser: /servers/[id]/prompts

Removed (caused instability):
- GatewayFullCRUDUser: Gateway CRUD triggers slow MCP network calls
- TagsExtendedUser: App bug with json_extract on PostgreSQL (#2607)
- AdvancedProtocolUser: Complex payload validation issues

Disabled (app bug):
- /export/selective: Server object missing is_active attribute (#2606)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* feat(testing): add Batch 3 load test user classes (TokensUser, RBACUser)

Add TokensUser and RBACUser classes for improved API coverage:
- TokensUser: GET /tokens endpoint for token listing
- RBACUser: GET /rbac/roles, /rbac/my/roles, /rbac/my/permissions,
  /rbac/permissions/available endpoints

TeamsUser was removed due to app bug #2608 (current_user_ctx["db"]
returns None causing 500 errors on /teams endpoint).

Closes #2608

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* feat(testing): add Batch 4 load test user classes (AuthUser, OAuthUser)

Add authentication and OAuth user classes for improved API coverage:
- AuthUser: GET /auth/email/events, /auth/email/admin/events,
  /auth/email/admin/users endpoints
- OAuthUser: GET /oauth/registered-clients endpoint

SSO endpoints were not added as they return 404 (not available).
Write operations (login, register) were skipped intentionally.

Total unique endpoints now tested: 99

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* feat(testing): add Batch 5 load test user classes (LogSearchUser, MetricsUser, ObservabilityUser)

Add logging, metrics, and observability user classes for improved API coverage:
- LogSearchUser: GET /api/logs/security-events, /api/logs/audit-trails,
  /api/logs/performance-metrics endpoints
- MetricsUser: GET /metrics, /api/metrics/stats, /api/metrics/config,
  /metrics/prometheus endpoints
- ObservabilityUser: GET /admin/observability/tools/usage,
  /admin/observability/tools/performance,
  /admin/observability/metrics/top-volume endpoints

Total unique endpoints now tested: 108

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* feat(testing): add Batch 6 load test user classes (LLMUser, ReverseProxyUser)

Add LLM and reverse proxy user classes for final API coverage:
- LLMUser: GET /llm/gateway/models, /llmchat/gateway/models,
  /admin/llm/provider-configs, /admin/llm/provider-defaults endpoints
- ReverseProxyUser: GET /reverse-proxy/sessions endpoint

Toolops and well-known endpoints were not added (404 - not available).
Cancellation endpoints skipped (require valid request IDs).

Total unique endpoints now tested: 113
All 6 batches complete.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…in (#2587)

- New main entry point: scripts/contextforge-setup.sh
- Modular library structure: scripts/lib/common.sh, debian.sh, rhel.sh
- Removes old scripts/rocky-contextforge-setup-script.sh
- Renames scripts/ubuntu-contextforge-setup-script.sh to lib/common.sh
- Adds --skip-docker-login flag and DOCKER_* env var support
- Adds Docker Compose deployment documentation

Signed-off-by: Jonathan Springer <jps@s390x.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* test: expand rpc and admin coverage

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* chore: drop ignored todo from repo

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Add onkeydown handlers to HTML elements (div and span) that have onclick
handlers to support keyboard users. This enables Tab navigation to
interactive elements on Overview, MCP Registry and Plugins pages.

The implementation:
- Adds a handleKeydown() utility function in admin.js that triggers
  callbacks on Enter or Space key presses
- Adds role="button", tabindex="0", and onkeydown attributes to
  interactive elements
- Includes event.preventDefault() to stop default browser behavior

Closes #2167

Signed-off-by: Marek Dano <mk.dano@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
Fixes #2329

Updates tag filtering in TagService.get_entities_by_tag() to use the
cross-database compatible json_contains_tag_expr helper instead of the
raw json_extract LIKE query that only worked with string arrays.

Changes:
- Replace func.json_extract(tags, "$").LIKE query with json_contains_tag_expr
  which supports both legacy string tags and new dict-format tags
- Update PostgreSQL implementation to use table_valued() pattern for
  idiomatic SQLAlchemy handling of jsonb_array_elements (elem.c.value)
- Update unit tests to mock database dialect for json_contains_tag_expr
- Improve test mocking to use patch.object context manager
- Fix docstring to reflect new implementation (was "JSON LIKE queries")
- Add comprehensive tests for dict-format tags [{id, label}]
- Add rigorous PostgreSQL SQL compilation tests with regex validation
- Document design decision: DB filters by 'id' only (TagValidator ensures
  id is always present; label is for display only)

The json_contains_tag_expr helper handles both formats:
- Legacy: ["tag1", "tag2"]
- Dict format: [{"id": "tag1", "label": "Tag 1"}, ...]

PostgreSQL implementation uses table_valued() for explicit column reference:
- func.jsonb_array_elements(...).table_valued("value").alias("elem")
- elem.c.value.op("->>")("id") for proper column access

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
crivetimihai and others added 23 commits February 21, 2026 20:07
The validation step only checked for empty secrets, allowing
placeholder values like '-' to pass. This caused the workflow to
build and push the Docker image (~3 min) before failing at the
verification step. Now rejects '-', 'changeme', and 'CHANGE_ME'
early with a helpful error pointing to GitHub Settings.

Also sets all 5 CF_* secrets in the production environment to
strong random values (they were previously set to '-').

Closes #3096

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* feat: implement Subresource Integrity (SRI) for CDN resources

Implements comprehensive SRI protection for all external CDN resources
to prevent tampering and ensure content integrity.

Changes:
- Pin 15 CDN resources to specific versions (HTMX 1.9.10, Alpine.js 3.14.1, etc.)
- Generate SHA-384 integrity hashes for all CDN resources
- Add integrity and crossorigin attributes to all CDN script/link tags
- Create shared scripts/cdn_resources.py module for DRY configuration
- Implement hash generation (scripts/generate-sri-hashes.py)
- Implement hash verification (scripts/verify-sri-hashes.py)
- Add CI pipeline verification (make sri-verify)
- Document SRI in security guide and ADR-0014
- Add Tailwind JIT exclusion comments (dynamic content incompatible with SRI)
- Use @lru_cache for efficient hash loading (no global variables)

Templates updated:
- admin.html: HTMX with canonical /dist/htmx.min.js URL
- login.html: Font Awesome with corrected closing tag
- change-password-required.html: Font Awesome

All 15 CDN resources now protected with cryptographic integrity verification.

Closes #2558

Signed-off-by: SuciuDaniel <Daniel.Vasile.Suciu@ibm.com>

* style: add blank line before lru_cache decorator for PEP 8 compliance

Signed-off-by: SuciuDaniel <Daniel.Vasile.Suciu@ibm.com>

* test: add comprehensive test coverage for load_sri_hashes()

- Add 8 test cases covering all code paths in load_sri_hashes()
- Test success case, file not found, invalid JSON, permission errors
- Test lru_cache behavior and integration with admin endpoints
- Test edge cases: empty file, unicode content
- Remove shebang from scripts/cdn_resources.py (library module)

Closes #2558

Signed-off-by: SuciuDaniel <Daniel.Vasile.Suciu@ibm.com>

* fix: review fixes for SRI implementation

- Fix docs referencing wrong file (generate-sri-hashes.py -> cdn_resources.py)
- Add *.json to pyproject.toml package-data for wheel builds
- Add sri_hashes context to forgot-password and reset-password endpoints
- Fix HTMX script tag indentation in admin.html
- Use %s logger format instead of f-string in load_sri_hashes
- Remove unused monkeypatch parameter from SRI tests
- Add Tailwind JIT exclusion comments to forgot-password and reset-password

Closes #2558

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Makefile update

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(test): remove Authorization header from cookie injection to fix CORS

The SRI PR added crossorigin="anonymous" to CDN resources (required by
the W3C SRI spec for cross-origin integrity checks). This changed CDN
fetch mode from no-cors to cors. Playwright's set_extra_http_headers
sends the Authorization header on ALL requests including cross-origin
CDN fetches, triggering CORS preflight failures on CDNs that don't
whitelist Authorization — blocking Alpine.js, CodeMirror, and other
scripts from loading.

Fix: use cookie-only auth in _inject_jwt_cookie and
_set_admin_jwt_cookie. The JWT cookie alone is sufficient for
same-origin page navigation and HTMX requests.

Closes #2558

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: SuciuDaniel <Daniel.Vasile.Suciu@ibm.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
…c, and ssrf (#3101)

* fix: harden websocket auth and gate ws/reverse-proxy by default

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: token scoping hardening for unmatched paths (C-15)

Default deny for unmatched scoped paths in token scoping middleware

Preserve public/wildcard behavior and add regression coverage

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: bearer scheme parsing consistency in token scoping (C-03)

Accept case-insensitive Bearer authorization scheme

Add regression coverage for mixed-case bearer and empty-token handling

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* test: token scope regression coverage for MCP/RPC paths (C-09)

Assert scoped tokens are denied on /rpc and require servers.use on server MCP endpoints

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: cancellation notification authorization checks (C-10)

Require run ownership or admin context before honoring notifications/cancelled

Store run owner metadata at registration and add regression coverage

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: enforce admin access on DCR management endpoints (O-05)

Require admin context for registered OAuth client list/get/delete endpoints

Add regression tests for non-admin denial

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: streamable auth revocation and user status checks (U-05)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: oidc id_token verification in sso callback flow (O-01)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: strict ssrf defaults with explicit cidr allowlist (S-01)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: harden cancellation auth paths and align ws/oidc security behavior

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* test: add full regression coverage for new security paths

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* test: align locust expectations with feature flags and auth hardening

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Fix testing on github runner

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Update docs

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* fix: security health auth validation hardening and behavior consistency

Aligns /health/security token checks with JWT verification flow for consistent authenticated access behavior.

Ref: C-38
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: rpc logging authorization hardening and behavior consistency

Adds admin.system_config permission checks for JSON-RPC logging/setLevel to align RPC and HTTP behavior.

Ref: C-30
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: utility transport permission consistency hardening and behavior consistency

Aligns utility SSE/message permission checks with the canonical tools.execute action used by role defaults.

Ref: C-13
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: auth dependency validation hardening and behavior consistency

Adds token revocation and active-user enforcement to require_auth while preserving existing auth source precedence.

Ref: C-33
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: admin auth validation hardening and behavior consistency

Enforces revocation and active-user checks in require_admin_auth before admin access is granted.

Ref: C-16
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: auth hardening consistency and documentation updates

Aligns auth dependency behavior and updates RC2 changelog plus RBAC/security docs to reflect current permission and validation flows.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* test: cover auth hardening diff branches

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
… h-batch-2 (#3106)

* fix: session and resource access hardening and behavior consistency

Align websocket token handling, session ownership checks, resource visibility enforcement, and roots permission consistency for C-04 C-07 C-11 C-14 C-28 C-29.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs: rc2 changelog hardening and migration clarity

Document C-04 C-07 C-11 C-14 C-28 C-29 behavior changes and breaking-change migration guidance under 1.0.0-RC2.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* chore: docstring lint compliance and coverage consistency

Add missing Args/Returns/Raises docstrings for helper methods and nested search/session owner helpers to satisfy flake8 DAR rules and interrogate coverage.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: session ownership claim hardening and auth semantics

Use atomic owner claim for initialize, distinguish missing session from unverifiable owner metadata on message ingress, add defensive team-access guard, and extend regression coverage.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Update pylint

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: distributed owner-claim fail-closed semantics

Return unverifiable state when Redis ownership backend is unavailable and extend backend coverage for owner claim/session existence behavior.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* test: expand hardening regression and diff coverage

Add backend-specific session owner claim/existence tests and helper-path regressions to reach 100% diff coverage for new hardening code.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* fix: access control hardening and behavior consistency

- C-05: require tools.execute for both tools/call and legacy JSON-RPC tool invocation paths

- C-18: enforce scoped access on GET /resources/{resource_id}/info and maintain fail-closed ID ownership checks

- C-19: align root management endpoints with admin.system_config authorization requirements

- C-20: harden OAuth fetch-tools scope resolution and ownership checks with normalized token-team semantics

- C-35: validate server existence and scoped access before SSE setup, preserving deterministic 404/403 behavior

- C-39: sanitize imported scoped fields (team_id, owner_email, visibility, team) before persistence

- C-18: harden JWT rich-token teams semantics by distinguishing omitted teams from explicit teams=null

- add/update regression tests for allow/deny coverage across RPC, OAuth, resource info, import sanitization, and token helpers

- update CHANGELOG and local issue evidence/index entries for the hardening follow-up

Refs: C-05 C-18 C-19 C-20 C-35 C-39
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Update tests

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…3111)

* fix: visibility and admin scope hardening and behavior consistency (C-22 C-24 C-27 C-32 C-23)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* chore: docstring completeness hardening and behavior consistency

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* test: scope regression coverage hardening and behavior consistency

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: streamable completion scope hardening and behavior consistency (C-24)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* test: completion scope branch coverage hardening in rpc and protocol paths

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
)

* fix: oauth grant handling hardening and behavior consistency (O-11)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: sso flow validation hardening and behavior consistency (O-03 O-04 O-06 O-14)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: oauth access enforcement hardening and behavior consistency (O-02 O-15 O-16)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* chore: auth lint compliance hardening and behavior consistency

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs: rc2 changelog and sso approval flow consistency

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: oauth status request-context hardening (O-16)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* test: expand oauth and sso hardening regression coverage

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: github sso email-claim handling and regression coverage

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: oauth fetch-tools access hardening (O-15)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Update tests

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…utbound URL validation (h-batch-6) (#3115)

* fix: oauth config hardening and behavior consistency

Refs: A-02, A-05, O-10, O-17

- centralize oauth secret protection for service-layer CRUD

- add server oauth masking parity for read/list responses

- keep oauth secret decrypt to runtime token exchange paths

- expand regression coverage for encryption and masking behavior

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: email auth timing hardening and behavior consistency

Refs: A-06

- add dummy password verification on early login failures

- enforce configurable minimum failed-login response duration

- add focused regression tests for timing guard paths

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: outbound url validation hardening and behavior consistency

Refs: S-02, S-03

- validate admin gateway test base URL before outbound requests

- validate llmchat connect server URL before session setup

- add regression tests for strict local/private URL rejection

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* test: regression coverage hardening and behavior consistency

Refs: A-02, A-05, A-06, O-10, O-17

- add branch-focused regression tests for oauth secret handling and runtime decrypt guards

- add legacy update-object coverage for server oauth update path

- align helper docstrings with linting policy requirements

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Update tests

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: hardening consistency for oauth storage, auth timing, and SSRF validation (A-02 A-05 A-06 O-10 O-17 S-02 S-03)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: harden admin endpoints and align load-test payloads

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
- Comment out PLUGINS_CONFIG_FILE default in values.yaml so legacy
  PLUGIN_CONFIG_FILE overrides are not shadowed by coalesce/AliasChoices
- Return PluginsSettings from config.py plugins property (not the
  LazySettingsWrapper proxy) to match the type annotation
- Use SecretStr for keyfile_password fields and .get_secret_value() in
  from_env adapters
- Switch runtime servers from PluginsSettings() to get_settings() for
  cached singleton access
- Simplify get_settings to no-arg lru_cache(maxsize=1)
- Remove LazySettingsWrapper.enabled os.getenv bypass
- Fix AliasChoices priority to prefer PLUGINS_ prefixed names
- Add env_file and extra=ignore to model_config
- Simplify test_tool_service_coverage to rely on autouse cache_clear

Signed-off-by: Jonathan Springer <jps@s390x.com>
@crivetimihai
Copy link
Copy Markdown
Member

Reopened as #3141. CI/CD will re-run on the new PR. You are still credited as the author.

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request plugins SHOULD P2: Important but not vital; high-value items that are not crucial for the immediate release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: Create plugin framework settings