fix(#3961): complete cloud-credential scrub set (AWS container FULL_URI + Azure identity family)
Round-3 gate found two more credential env vars the agent resolves cross-profile that the scrub set missed, verified against the installed agent source: - AWS_CONTAINER_CREDENTIALS_FULL_URI — read by model_switch._has_aws_creds:1360 (botocore container-credentials provider; RELATIVE_URI was present, FULL_URI was not). - Azure identity family — AZURE_CLIENT_ID / AZURE_CLIENT_SECRET / AZURE_TENANT_ID / AZURE_FEDERATED_TOKEN_FILE (agent/azure_identity_adapter.py service-principal + workload-identity model auth) and AZURE_FOUNDRY_API_KEY (runtime_provider.py). Enumerated the agent's full credential-env read surface from source to close the whole class in one pass rather than one var per gate round. Deliberately EXCLUDES config/region vars (AWS_REGION, AWS_DEFAULT_REGION, AZURE_FOUNDRY_BASE_URL) — the child probe may legitimately need those. Regressions extended to pin FULL_URI + the Azure family. Co-authored-by: rodboev <rodboev@users.noreply.github.com>
This commit is contained in:
1 parent
4eb069be97
commit
bf548a255d
2 files changed
+23
-1
No files matched your search
+15
-1
@@ -890,19 +890,33 @@ def filter_runtime_env_for_gateway_parity(env: dict[str, str]) -> dict[str, str]
|
||||
# would miss them). Fail-closed list — verified against the installed agent:
|
||||
# CUSTOM_API_KEY hermes_cli/models.py (generic custom provider key)
|
||||
# AZURE_ANTHROPIC_KEY hermes_cli/runtime_provider.py (Azure-hosted Anthropic)
|
||||
# AZURE_FOUNDRY_API_KEY hermes_cli/runtime_provider.py (Azure Foundry key)
|
||||
# AZURE_* identity family agent/azure_identity_adapter.py (service-principal /
|
||||
# workload-identity model auth)
|
||||
# AWS_BEARER_TOKEN_BEDROCK hermes_cli/model_switch.py (Bedrock bearer token)
|
||||
# AWS_* agent/bedrock_adapter.py (boto3 credential chain)
|
||||
# AWS_* credential chain agent/bedrock_adapter.py + model_switch._has_aws_creds
|
||||
# (boto3 access keys, session token, profile,
|
||||
# container/web-identity credential providers)
|
||||
# NOTE: region/base-url config vars (AWS_REGION, AWS_DEFAULT_REGION,
|
||||
# AZURE_FOUNDRY_BASE_URL) are deliberately NOT included — they're configuration,
|
||||
# not credentials, and the child probe may legitimately need them.
|
||||
# Stripping these in a profile-scoped read prevents an empty named profile from
|
||||
# inheriting the server-process credential (#3961 residual cross-profile leak).
|
||||
_NON_REGISTRY_AGENT_CREDENTIAL_ENV_NAMES: tuple[str, ...] = (
|
||||
"CUSTOM_API_KEY",
|
||||
"AZURE_ANTHROPIC_KEY",
|
||||
"AZURE_FOUNDRY_API_KEY",
|
||||
"AZURE_CLIENT_ID",
|
||||
"AZURE_CLIENT_SECRET",
|
||||
"AZURE_TENANT_ID",
|
||||
"AZURE_FEDERATED_TOKEN_FILE",
|
||||
"AWS_BEARER_TOKEN_BEDROCK",
|
||||
"AWS_ACCESS_KEY_ID",
|
||||
"AWS_SECRET_ACCESS_KEY",
|
||||
"AWS_SESSION_TOKEN",
|
||||
"AWS_PROFILE",
|
||||
"AWS_CONTAINER_CREDENTIALS_RELATIVE_URI",
|
||||
"AWS_CONTAINER_CREDENTIALS_FULL_URI",
|
||||
"AWS_WEB_IDENTITY_TOKEN_FILE",
|
||||
)
|
||||
|
||||
|
||||
@@ -809,6 +809,7 @@ def test_account_usage_subprocess_env_strips_non_registry_agent_creds(monkeypatc
|
||||
monkeypatch.setenv("CUSTOM_API_KEY", "process-default-custom-key")
|
||||
monkeypatch.setenv("AWS_PROFILE", "process-default-aws-profile")
|
||||
monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "process-default-bedrock-token")
|
||||
monkeypatch.setenv("AWS_CONTAINER_CREDENTIALS_FULL_URI", "http://169.254.170.2/creds")
|
||||
|
||||
profiles.set_request_profile("work")
|
||||
try:
|
||||
@@ -821,6 +822,7 @@ def test_account_usage_subprocess_env_strips_non_registry_agent_creds(monkeypatc
|
||||
assert "CUSTOM_API_KEY" not in env
|
||||
assert "AWS_PROFILE" not in env
|
||||
assert "AWS_BEARER_TOKEN_BEDROCK" not in env
|
||||
assert "AWS_CONTAINER_CREDENTIALS_FULL_URI" not in env
|
||||
|
||||
|
||||
def test_detached_worker_scope_scrubs_non_registry_agent_creds(monkeypatch, tmp_path):
|
||||
@@ -835,14 +837,20 @@ def test_detached_worker_scope_scrubs_non_registry_agent_creds(monkeypatch, tmp_
|
||||
monkeypatch.setenv("CUSTOM_API_KEY", "process-default-custom-key")
|
||||
monkeypatch.setenv("AWS_PROFILE", "process-default-aws-profile")
|
||||
monkeypatch.setenv("AWS_SECRET_ACCESS_KEY", "process-default-aws-secret")
|
||||
monkeypatch.setenv("AZURE_CLIENT_SECRET", "process-default-azure-secret")
|
||||
monkeypatch.setenv("AZURE_FOUNDRY_API_KEY", "process-default-foundry-key")
|
||||
|
||||
with profiles.profile_scope_for_detached_worker("work", "test-worker"):
|
||||
assert os.environ.get("CUSTOM_API_KEY") is None
|
||||
assert os.environ.get("AWS_PROFILE") is None
|
||||
assert os.environ.get("AWS_SECRET_ACCESS_KEY") is None
|
||||
assert os.environ.get("AZURE_CLIENT_SECRET") is None
|
||||
assert os.environ.get("AZURE_FOUNDRY_API_KEY") is None
|
||||
assert config._thread_local_env_value("CUSTOM_API_KEY") == ""
|
||||
|
||||
assert os.environ.get("CUSTOM_API_KEY") == "process-default-custom-key"
|
||||
assert os.environ.get("AWS_PROFILE") == "process-default-aws-profile"
|
||||
assert os.environ.get("AWS_SECRET_ACCESS_KEY") == "process-default-aws-secret"
|
||||
assert os.environ.get("AZURE_CLIENT_SECRET") == "process-default-azure-secret"
|
||||
assert os.environ.get("AZURE_FOUNDRY_API_KEY") == "process-default-foundry-key"
|
||||
|
||||
Reference in new issue
Block a user