Skip to content

fix(gateway): read platform env overrides through the profile secret scope (#50094 salvage) - #59315

Merged
teknium1 merged 1 commit into
mainfrom
salvage/50094-config-secret-scope
Jul 6, 2026
Merged

teknium1 merged 1 commit into
mainfrom
salvage/50094-config-secret-scope

Conversation

@teknium1

@teknium1 teknium1 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Multiplexed secondary profiles now read their own platform tokens: gateway/config.py::_apply_env_overrides routes all ~174 env reads through a scope-aware _getenv() that prefers the active profile secret scope and falls back to legacy os.environ only when no scope is installed.

Salvages #50094 by @izumi0uu (cherry-picked, authorship preserved). Fixes the root cause of #50051 / #52446 / #49415 / #54675.

Root cause: phase 2's fail-closed credential isolation covered runtime_provider and hermes_cli/config.py, but gateway/config.py never learned about agent.secret_scope. The multiplexer loads each secondary profile's config inside _profile_runtime_scope — which installs the profile's .env as a contextvar without touching os.environ — so load_gateway_config() read the PRIMARY profile's TELEGRAM_BOT_TOKEN/DISCORD_BOT_TOKEN/etc. for every profile. The profile's own tokens were never seen; the collision guard then refused the duplicate and killed the secondary adapter.

Changes

  • gateway/config.py: new _getenv/_getenv_str/_getenv_int helpers — scoped read when current_secret_scope() is installed, legacy os.environ otherwise (crash-safe for the ~15 unscoped load_gateway_config() call sites in run.py, unlike the competing blanket-get_secret approaches); _apply_env_overrides swept to use them; boolean reads use the shared is_truthy_value helper
  • tests/gateway/test_config.py: regression test proving a scoped secondary profile resolves its own DISCORD_BOT_TOKEN and does not inherit the default profile's API_SERVER_ENABLED
  • Stripped from the original PR: an unrelated nested gateway: section merge + its test — that fix ships separately (fix(gateway): read multiplex_profiles from nested gateway section #51372 salvage, next in this cluster)
  • scripts/release.py: AUTHOR_MAP entry

Validation

Before After
Secondary profile, token in profile .env reads primary's token → collision guard kills adapter reads own token, adapter starts
Unscoped load_gateway_config() (single-profile) os.environ os.environ (unchanged)
tests/gateway/test_config.py + test_multiplex_credential_isolation.py 94/94 pass

Second PR in the multiplex isolation cluster, after the adapter-routing sweep (#59310).

Infographic

profile-secret-scope

@alt-glitch alt-glitch added type/security Security vulnerability or hardening comp/gateway Gateway runner, session dispatch, delivery area/auth Authentication, OAuth, credential pools area/config Config system, migrations, profiles sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data P2 Medium — degraded but workaround exists labels Jul 6, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Salvage of #50094 (@izumi0uu, earliest open). Related open work in the multiplex profile-secret-scope cluster: #55277 / #51115 (platform-token facet, both dup of #50094), #52399 (API_SERVER facet), #59076 (email-adapter facet). Marked related_to (salvage, not duplicate) — a maintainer should pick between this salvage and the open predecessors for the platform-token facet. Config-gated to gateway.multiplex_profiles and scoped to the operator's own gateway (all profiles inside the trust envelope), so priced P2 per the cluster tier.

Fixes #50051 by preserving nested gateway.multiplex_profiles and routing gateway config env reads through the active profile secret scope when present.

This keeps secondary profile adapter startup from inheriting default-profile platform tokens or port-binding enables while preserving legacy single-profile behavior outside a scope.

Constraint: latest upstream main f57ff7a still reproduced both nested-config loss and cross-profile env leakage
Rejected: special-casing API_SERVER_* only | left other profile-scoped tokens vulnerable to the same leak
Confidence: high
Scope-risk: moderate
Directive: keep future gateway/config env reads on the scoped helper path unless a variable is explicitly process-global
Tested: pytest -q tests/gateway/test_multiplex_phase0.py tests/gateway/test_multiplex_credential_isolation.py tests/gateway/test_config.py -k 'multiplex or scope or getenv or api_server or relay'
Not-tested: full gateway startup across live platform adapters
@teknium1
teknium1 force-pushed the salvage/50094-config-secret-scope branch from 6ef61a1 to 9492356 Compare July 6, 2026 04:51
@teknium1
teknium1 merged commit 0f154e7 into main Jul 6, 2026
31 checks passed
@teknium1
teknium1 deleted the salvage/50094-config-secret-scope branch July 6, 2026 05:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools area/config Config system, migrations, profiles comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants