Files
wehub-resource-sync 4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

183 lines
4.9 KiB
Python

"""Secrets Manager access."""
import json
from typing import Any
from botocore.exceptions import ClientError
from tests.shared.infrastructure_sdk.deployer import DEFAULT_REGION, get_boto3_client
def get_secret_value(secret_name: str, region: str = DEFAULT_REGION) -> dict[str, Any]:
"""Get secret value as dict (JSON parsed).
Args:
secret_name: Secret name or ARN.
region: AWS region.
Returns:
Secret value as parsed JSON dict.
Raises:
ValueError: If secret doesn't exist or isn't valid JSON.
"""
secrets_client = get_boto3_client("secretsmanager", region)
try:
response = secrets_client.get_secret_value(SecretId=secret_name)
except ClientError as e:
if e.response["Error"]["Code"] == "ResourceNotFoundException":
raise ValueError(f"Secret '{secret_name}' not found") from e
raise
secret_string = response.get("SecretString")
if not secret_string:
raise ValueError(f"Secret '{secret_name}' has no string value (might be binary)")
try:
result: dict[str, Any] = json.loads(secret_string)
return result
except json.JSONDecodeError as e:
raise ValueError(f"Secret '{secret_name}' is not valid JSON: {e}") from e
def get_secret_string(secret_name: str, region: str = DEFAULT_REGION) -> str:
"""Get secret value as raw string.
Args:
secret_name: Secret name or ARN.
region: AWS region.
Returns:
Secret value as string.
Raises:
ValueError: If secret doesn't exist.
"""
secrets_client = get_boto3_client("secretsmanager", region)
try:
response = secrets_client.get_secret_value(SecretId=secret_name)
except ClientError as e:
if e.response["Error"]["Code"] == "ResourceNotFoundException":
raise ValueError(f"Secret '{secret_name}' not found") from e
raise
secret_string = response.get("SecretString")
if not secret_string:
raise ValueError(f"Secret '{secret_name}' has no string value")
return str(secret_string)
def get_secret_arn(secret_name: str, region: str = DEFAULT_REGION) -> str:
"""Get secret ARN.
Args:
secret_name: Secret name.
region: AWS region.
Returns:
Secret ARN.
Raises:
ValueError: If secret doesn't exist.
"""
secrets_client = get_boto3_client("secretsmanager", region)
try:
response = secrets_client.describe_secret(SecretId=secret_name)
except ClientError as e:
if e.response["Error"]["Code"] == "ResourceNotFoundException":
raise ValueError(f"Secret '{secret_name}' not found") from e
raise
return str(response["ARN"])
def secret_exists(secret_name: str, region: str = DEFAULT_REGION) -> bool:
"""Check if a secret exists.
Args:
secret_name: Secret name or ARN.
region: AWS region.
Returns:
True if secret exists.
"""
secrets_client = get_boto3_client("secretsmanager", region)
try:
secrets_client.describe_secret(SecretId=secret_name)
return True
except ClientError as e:
if e.response["Error"]["Code"] == "ResourceNotFoundException":
return False
raise
def list_secrets(
prefix: str | None = None,
max_results: int = 100,
region: str = DEFAULT_REGION,
) -> list[dict[str, Any]]:
"""List secrets.
Args:
prefix: Optional name prefix filter.
max_results: Maximum secrets to return.
region: AWS region.
Returns:
List of secret metadata.
"""
secrets_client = get_boto3_client("secretsmanager", region)
params: dict[str, Any] = {"MaxResults": min(max_results, 100)}
if prefix:
params["Filters"] = [{"Key": "name", "Values": [prefix]}]
secrets = []
paginator = secrets_client.get_paginator("list_secrets")
for page in paginator.paginate(**params):
for secret in page.get("SecretList", []):
secrets.append(
{
"name": secret["Name"],
"arn": secret["ARN"],
"description": secret.get("Description"),
"last_changed": secret.get("LastChangedDate"),
}
)
if len(secrets) >= max_results:
return secrets
return secrets
def get_secret_for_ecs(
secret_name: str, json_key: str | None = None, region: str = DEFAULT_REGION
) -> dict[str, str]:
"""Get secret reference for ECS container definition.
Args:
secret_name: Secret name.
json_key: Optional JSON key within the secret.
region: AWS region.
Returns:
Dict with 'name' and 'valueFrom' for ECS secrets config.
"""
arn = get_secret_arn(secret_name, region)
value_from = arn
if json_key:
value_from = f"{arn}:{json_key}::"
return {
"name": json_key or secret_name.split("/")[-1].upper(),
"valueFrom": value_from,
}