agentcore-cli 0.31.1__py3-none-any.whl
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.
- agentcore/__init__.py +1 -0
- agentcore/agent_inspector/NOTICE +9 -0
- agentcore/agent_inspector/favicon.svg +60 -0
- agentcore/agent_inspector/index.css +1 -0
- agentcore/agent_inspector/index.html +14 -0
- agentcore/agent_inspector/index.js +289 -0
- agentcore/assets/AGENTS.md +60 -0
- agentcore/assets/README.md +108 -0
- agentcore/assets/agents/AGENTS.md +218 -0
- agentcore/assets/cdk/.prettierrc +8 -0
- agentcore/assets/cdk/README.md +26 -0
- agentcore/assets/cdk/bin/cdk.ts +216 -0
- agentcore/assets/cdk/cdk.json +88 -0
- agentcore/assets/cdk/gitignore.template +9 -0
- agentcore/assets/cdk/jest.config.js +9 -0
- agentcore/assets/cdk/lib/cdk-stack.ts +291 -0
- agentcore/assets/cdk/npmignore.template +6 -0
- agentcore/assets/cdk/package.json +30 -0
- agentcore/assets/cdk/test/cdk.test.ts +31 -0
- agentcore/assets/cdk/tsconfig.json +28 -0
- agentcore/assets/container/python/Dockerfile +47 -0
- agentcore/assets/container/python/dockerignore.template +27 -0
- agentcore/assets/container/typescript/Dockerfile +25 -0
- agentcore/assets/container/typescript/dockerignore.template +24 -0
- agentcore/assets/datasets/predefined-v1.jsonl +3 -0
- agentcore/assets/datasets/simulated-v1.jsonl +3 -0
- agentcore/assets/evaluators/autoevals-lambda/execution-role-policy.json +15 -0
- agentcore/assets/evaluators/autoevals-lambda/lambda_function.py +37 -0
- agentcore/assets/evaluators/autoevals-lambda/pyproject.toml +22 -0
- agentcore/assets/evaluators/deepeval-lambda/execution-role-policy.json +15 -0
- agentcore/assets/evaluators/deepeval-lambda/lambda_function.py +29 -0
- agentcore/assets/evaluators/deepeval-lambda/pyproject.toml +19 -0
- agentcore/assets/evaluators/python-lambda/execution-role-policy.json +10 -0
- agentcore/assets/evaluators/python-lambda/lambda_function.py +19 -0
- agentcore/assets/evaluators/python-lambda/pyproject.toml +15 -0
- agentcore/assets/harness/invoke.py.template +74 -0
- agentcore/assets/mcp/python/README.md +27 -0
- agentcore/assets/mcp/python/pyproject.toml +22 -0
- agentcore/assets/mcp/python/server.py +117 -0
- agentcore/assets/mcp/python-lambda/README.md +22 -0
- agentcore/assets/mcp/python-lambda/handler.py +144 -0
- agentcore/assets/mcp/python-lambda/pyproject.toml +15 -0
- agentcore/assets/python/a2a/googleadk/base/README.md +22 -0
- agentcore/assets/python/a2a/googleadk/base/gitignore.template +41 -0
- agentcore/assets/python/a2a/googleadk/base/main.py +124 -0
- agentcore/assets/python/a2a/googleadk/base/model/__init__.py +1 -0
- agentcore/assets/python/a2a/googleadk/base/model/load.py +41 -0
- agentcore/assets/python/a2a/googleadk/base/pyproject.toml +22 -0
- agentcore/assets/python/a2a/langchain_langgraph/base/README.md +22 -0
- agentcore/assets/python/a2a/langchain_langgraph/base/gitignore.template +41 -0
- agentcore/assets/python/a2a/langchain_langgraph/base/main.py +144 -0
- agentcore/assets/python/a2a/langchain_langgraph/base/model/__init__.py +1 -0
- agentcore/assets/python/a2a/langchain_langgraph/base/model/load.py +123 -0
- agentcore/assets/python/a2a/langchain_langgraph/base/pyproject.toml +26 -0
- agentcore/assets/python/a2a/strands/base/README.md +22 -0
- agentcore/assets/python/a2a/strands/base/gitignore.template +41 -0
- agentcore/assets/python/a2a/strands/base/main.py +113 -0
- agentcore/assets/python/a2a/strands/base/model/__init__.py +1 -0
- agentcore/assets/python/a2a/strands/base/model/load.py +123 -0
- agentcore/assets/python/a2a/strands/base/pyproject.toml +23 -0
- agentcore/assets/python/a2a/strands/capabilities/memory/__init__.py +1 -0
- agentcore/assets/python/a2a/strands/capabilities/memory/session.py +46 -0
- agentcore/assets/python/agui/googleadk/base/README.md +30 -0
- agentcore/assets/python/agui/googleadk/base/gitignore.template +41 -0
- agentcore/assets/python/agui/googleadk/base/main.py +91 -0
- agentcore/assets/python/agui/googleadk/base/model/__init__.py +1 -0
- agentcore/assets/python/agui/googleadk/base/model/load.py +41 -0
- agentcore/assets/python/agui/googleadk/base/pyproject.toml +25 -0
- agentcore/assets/python/agui/langchain_langgraph/base/README.md +22 -0
- agentcore/assets/python/agui/langchain_langgraph/base/gitignore.template +41 -0
- agentcore/assets/python/agui/langchain_langgraph/base/main.py +130 -0
- agentcore/assets/python/agui/langchain_langgraph/base/model/__init__.py +1 -0
- agentcore/assets/python/agui/langchain_langgraph/base/model/load.py +123 -0
- agentcore/assets/python/agui/langchain_langgraph/base/pyproject.toml +31 -0
- agentcore/assets/python/agui/strands/base/README.md +22 -0
- agentcore/assets/python/agui/strands/base/gitignore.template +41 -0
- agentcore/assets/python/agui/strands/base/main.py +105 -0
- agentcore/assets/python/agui/strands/base/model/__init__.py +1 -0
- agentcore/assets/python/agui/strands/base/model/load.py +123 -0
- agentcore/assets/python/agui/strands/base/pyproject.toml +27 -0
- agentcore/assets/python/agui/strands/capabilities/memory/__init__.py +1 -0
- agentcore/assets/python/agui/strands/capabilities/memory/session.py +46 -0
- agentcore/assets/python/http/autogen/base/README.md +45 -0
- agentcore/assets/python/http/autogen/base/gitignore.template +41 -0
- agentcore/assets/python/http/autogen/base/main.py +145 -0
- agentcore/assets/python/http/autogen/base/mcp_client/__init__.py +1 -0
- agentcore/assets/python/http/autogen/base/mcp_client/client.py +28 -0
- agentcore/assets/python/http/autogen/base/model/__init__.py +1 -0
- agentcore/assets/python/http/autogen/base/model/load.py +136 -0
- agentcore/assets/python/http/autogen/base/pyproject.toml +34 -0
- agentcore/assets/python/http/bma/base/Dockerfile +41 -0
- agentcore/assets/python/http/bma/base/README.md +178 -0
- agentcore/assets/python/http/bma/base/client.py +200 -0
- agentcore/assets/python/http/bma/base/lifecycle/server.py +641 -0
- agentcore/assets/python/http/bma/base/otel/collector.yaml +69 -0
- agentcore/assets/python/http/bma/base/plugins/acr-report/.codex-plugin/plugin.json +6 -0
- agentcore/assets/python/http/bma/base/plugins/acr-report/skills/acr-report/SKILL.md +16 -0
- agentcore/assets/python/http/bma/base/policies/bma-acr-policy.json +11 -0
- agentcore/assets/python/http/bma/base/policies/bma-session-policy.json +35 -0
- agentcore/assets/python/http/bma/base/policies/bma-session-trust.json +20 -0
- agentcore/assets/python/http/bma/base/pyproject.toml +21 -0
- agentcore/assets/python/http/googleadk/base/README.md +45 -0
- agentcore/assets/python/http/googleadk/base/gitignore.template +41 -0
- agentcore/assets/python/http/googleadk/base/main.py +207 -0
- agentcore/assets/python/http/googleadk/base/mcp_client/__init__.py +1 -0
- agentcore/assets/python/http/googleadk/base/mcp_client/client.py +75 -0
- agentcore/assets/python/http/googleadk/base/model/__init__.py +1 -0
- agentcore/assets/python/http/googleadk/base/model/load.py +41 -0
- agentcore/assets/python/http/googleadk/base/pyproject.toml +24 -0
- agentcore/assets/python/http/langchain_langgraph/base/README.md +45 -0
- agentcore/assets/python/http/langchain_langgraph/base/gitignore.template +41 -0
- agentcore/assets/python/http/langchain_langgraph/base/main.py +227 -0
- agentcore/assets/python/http/langchain_langgraph/base/mcp_client/__init__.py +1 -0
- agentcore/assets/python/http/langchain_langgraph/base/mcp_client/client.py +79 -0
- agentcore/assets/python/http/langchain_langgraph/base/model/__init__.py +1 -0
- agentcore/assets/python/http/langchain_langgraph/base/model/load.py +123 -0
- agentcore/assets/python/http/langchain_langgraph/base/pyproject.toml +38 -0
- agentcore/assets/python/http/openaiagents/base/README.md +45 -0
- agentcore/assets/python/http/openaiagents/base/gitignore.template +41 -0
- agentcore/assets/python/http/openaiagents/base/main.py +200 -0
- agentcore/assets/python/http/openaiagents/base/mcp_client/__init__.py +1 -0
- agentcore/assets/python/http/openaiagents/base/mcp_client/client.py +74 -0
- agentcore/assets/python/http/openaiagents/base/model/__init__.py +1 -0
- agentcore/assets/python/http/openaiagents/base/model/load.py +37 -0
- agentcore/assets/python/http/openaiagents/base/pyproject.toml +21 -0
- agentcore/assets/python/http/strands/base/README.md +46 -0
- agentcore/assets/python/http/strands/base/gitignore.template +41 -0
- agentcore/assets/python/http/strands/base/main.py +714 -0
- agentcore/assets/python/http/strands/base/mcp_client/__init__.py +1 -0
- agentcore/assets/python/http/strands/base/mcp_client/client.py +116 -0
- agentcore/assets/python/http/strands/base/model/__init__.py +1 -0
- agentcore/assets/python/http/strands/base/model/load.py +239 -0
- agentcore/assets/python/http/strands/base/model/mantle_compat.py +21 -0
- agentcore/assets/python/http/strands/base/pyproject.toml +31 -0
- agentcore/assets/python/http/strands/base/skills/fetcher.py +279 -0
- agentcore/assets/python/http/strands/capabilities/execution-limits/hooks/execution_limits.py +54 -0
- agentcore/assets/python/http/strands/capabilities/memory/__init__.py +1 -0
- agentcore/assets/python/http/strands/capabilities/memory/session.py +47 -0
- agentcore/assets/python/http/strands/capabilities/payments/__init__.py +4 -0
- agentcore/assets/python/http/strands/capabilities/payments/payments.py +142 -0
- agentcore/assets/python/mcp/standalone/base/README.md +36 -0
- agentcore/assets/python/mcp/standalone/base/gitignore.template +41 -0
- agentcore/assets/python/mcp/standalone/base/main.py +83 -0
- agentcore/assets/python/mcp/standalone/base/pyproject.toml +16 -0
- agentcore/assets/typescript/.gitkeep +0 -0
- agentcore/assets/typescript/http/strands/base/README.md +42 -0
- agentcore/assets/typescript/http/strands/base/gitignore.template +22 -0
- agentcore/assets/typescript/http/strands/base/main.ts +149 -0
- agentcore/assets/typescript/http/strands/base/mcp_client/client.ts +11 -0
- agentcore/assets/typescript/http/strands/base/model/load.ts +102 -0
- agentcore/assets/typescript/http/strands/base/package.json +38 -0
- agentcore/assets/typescript/http/strands/base/tsconfig.json +19 -0
- agentcore/assets/typescript/http/strands/capabilities/memory/memory.ts +52 -0
- agentcore/assets/typescript/http/vercelai/base/README.md +42 -0
- agentcore/assets/typescript/http/vercelai/base/gitignore.template +22 -0
- agentcore/assets/typescript/http/vercelai/base/main.ts +70 -0
- agentcore/assets/typescript/http/vercelai/base/model/load.ts +121 -0
- agentcore/assets/typescript/http/vercelai/base/package.json +35 -0
- agentcore/assets/typescript/http/vercelai/base/tsconfig.json +19 -0
- agentcore/aws/__init__.py +263 -0
- agentcore/aws/_aws_errors.py +72 -0
- agentcore/aws/_http.py +176 -0
- agentcore/aws/_util.py +37 -0
- agentcore/aws/account.py +165 -0
- agentcore/aws/agentcore.py +971 -0
- agentcore/aws/agentcore_ab_tests.py +230 -0
- agentcore/aws/agentcore_batch_evaluation.py +227 -0
- agentcore/aws/agentcore_config_bundles.py +220 -0
- agentcore/aws/agentcore_control.py +994 -0
- agentcore/aws/agentcore_datasets.py +222 -0
- agentcore/aws/agentcore_harness.py +330 -0
- agentcore/aws/agentcore_payments.py +430 -0
- agentcore/aws/agentcore_recommendation.py +140 -0
- agentcore/aws/agui_parser.py +131 -0
- agentcore/aws/agui_types.py +342 -0
- agentcore/aws/api_client.py +87 -0
- agentcore/aws/arn.py +18 -0
- agentcore/aws/aws_context.py +23 -0
- agentcore/aws/bedrock.py +44 -0
- agentcore/aws/bedrock_agent.py +129 -0
- agentcore/aws/bedrock_import.py +252 -0
- agentcore/aws/bedrock_import_types.py +111 -0
- agentcore/aws/cloudwatch.py +136 -0
- agentcore/aws/connect_shell.py +266 -0
- agentcore/aws/iam.py +41 -0
- agentcore/aws/partition.py +58 -0
- agentcore/aws/policy_generation.py +116 -0
- agentcore/aws/region.py +54 -0
- agentcore/aws/retry.py +27 -0
- agentcore/aws/shell_framer.py +136 -0
- agentcore/aws/stage_endpoint.py +39 -0
- agentcore/aws/target_region.py +54 -0
- agentcore/aws/transaction_search.py +97 -0
- agentcore/cdk/__init__.py +10 -0
- agentcore/cdk/constants.py +13 -0
- agentcore/cdk/local_cdk_project.py +48 -0
- agentcore/cdk/toolkit.py +706 -0
- agentcore/cli/__init__.py +0 -0
- agentcore/cli/commands/__init__.py +0 -0
- agentcore/cli/commands/_jobs_common.py +39 -0
- agentcore/cli/commands/_run_wizards.py +639 -0
- agentcore/cli/commands/add/__init__.py +37 -0
- agentcore/cli/commands/add/_commander.py +52 -0
- agentcore/cli/commands/add/_common.py +47 -0
- agentcore/cli/commands/add/agent_wizard.py +528 -0
- agentcore/cli/commands/add/auth_options.py +154 -0
- agentcore/cli/commands/add/skill_action.py +105 -0
- agentcore/cli/commands/add/skill_command.py +87 -0
- agentcore/cli/commands/add/tool_action.py +160 -0
- agentcore/cli/commands/add/tool_command.py +117 -0
- agentcore/cli/commands/add/validate.py +333 -0
- agentcore/cli/commands/capacity_provider/__init__.py +86 -0
- agentcore/cli/commands/capacity_provider/action.py +114 -0
- agentcore/cli/commands/capacity_provider/constants.py +22 -0
- agentcore/cli/commands/config.py +91 -0
- agentcore/cli/commands/config_bundle.py +251 -0
- agentcore/cli/commands/create/__init__.py +643 -0
- agentcore/cli/commands/create/action.py +406 -0
- agentcore/cli/commands/create/dependencies.py +91 -0
- agentcore/cli/commands/create/harness_validate.py +82 -0
- agentcore/cli/commands/create/validate.py +195 -0
- agentcore/cli/commands/create/wizard.py +127 -0
- agentcore/cli/commands/dataset.py +119 -0
- agentcore/cli/commands/deploy/__init__.py +31 -0
- agentcore/cli/commands/deploy/_guards.py +25 -0
- agentcore/cli/commands/deploy/actions.py +840 -0
- agentcore/cli/commands/deploy/command.py +349 -0
- agentcore/cli/commands/deploy/progress.py +115 -0
- agentcore/cli/commands/deploy/types.py +68 -0
- agentcore/cli/commands/deploy/utils.py +43 -0
- agentcore/cli/commands/deploy/validate.py +21 -0
- agentcore/cli/commands/dev/__init__.py +5 -0
- agentcore/cli/commands/dev/_deps.py +50 -0
- agentcore/cli/commands/dev/browser_mode.py +270 -0
- agentcore/cli/commands/dev/command.py +450 -0
- agentcore/cli/commands/dev/terminal_mode.py +379 -0
- agentcore/cli/commands/exec/__init__.py +29 -0
- agentcore/cli/commands/exec/action.py +442 -0
- agentcore/cli/commands/exec/command.py +206 -0
- agentcore/cli/commands/exec/types.py +35 -0
- agentcore/cli/commands/export/__init__.py +114 -0
- agentcore/cli/commands/export/constants.py +21 -0
- agentcore/cli/commands/export/fetch_harness_spec.py +234 -0
- agentcore/cli/commands/export/harness_action.py +385 -0
- agentcore/cli/commands/export/harness_mapper.py +868 -0
- agentcore/cli/commands/export/harness_resolver.py +95 -0
- agentcore/cli/commands/export/types.py +90 -0
- agentcore/cli/commands/export/wizard.py +97 -0
- agentcore/cli/commands/feedback/__init__.py +69 -0
- agentcore/cli/commands/feedback/action.py +30 -0
- agentcore/cli/commands/feedback/consent_prompt.py +35 -0
- agentcore/cli/commands/feedback/wizard.py +49 -0
- agentcore/cli/commands/fetch/__init__.py +69 -0
- agentcore/cli/commands/fetch/action.py +62 -0
- agentcore/cli/commands/help.py +65 -0
- agentcore/cli/commands/import_/__init__.py +167 -0
- agentcore/cli/commands/import_/_js.py +72 -0
- agentcore/cli/commands/import_/actions.py +457 -0
- agentcore/cli/commands/import_/constants.py +45 -0
- agentcore/cli/commands/import_/import_evaluator.py +140 -0
- agentcore/cli/commands/import_/import_gateway.py +520 -0
- agentcore/cli/commands/import_/import_memory.py +128 -0
- agentcore/cli/commands/import_/import_online_eval.py +165 -0
- agentcore/cli/commands/import_/import_pipeline.py +145 -0
- agentcore/cli/commands/import_/import_runtime.py +214 -0
- agentcore/cli/commands/import_/import_utils.py +410 -0
- agentcore/cli/commands/import_/phase1_update.py +110 -0
- agentcore/cli/commands/import_/phase2_import.py +206 -0
- agentcore/cli/commands/import_/resource_import.py +228 -0
- agentcore/cli/commands/import_/template_utils.py +148 -0
- agentcore/cli/commands/import_/types.py +150 -0
- agentcore/cli/commands/import_/yaml_parser.py +265 -0
- agentcore/cli/commands/init.py +196 -0
- agentcore/cli/commands/invoke/__init__.py +32 -0
- agentcore/cli/commands/invoke/_deps.py +73 -0
- agentcore/cli/commands/invoke/action.py +840 -0
- agentcore/cli/commands/invoke/command.py +490 -0
- agentcore/cli/commands/invoke/constants.py +40 -0
- agentcore/cli/commands/invoke/guards.py +23 -0
- agentcore/cli/commands/invoke/interactive.py +604 -0
- agentcore/cli/commands/invoke/resolve.py +149 -0
- agentcore/cli/commands/invoke/resolve_prompt.py +60 -0
- agentcore/cli/commands/invoke/types.py +61 -0
- agentcore/cli/commands/invoke/validate.py +33 -0
- agentcore/cli/commands/job_actions.py +239 -0
- agentcore/cli/commands/job_history.py +380 -0
- agentcore/cli/commands/logs/__init__.py +53 -0
- agentcore/cli/commands/logs/action.py +159 -0
- agentcore/cli/commands/logs/filter_pattern.py +17 -0
- agentcore/cli/commands/logs/guards.py +51 -0
- agentcore/cli/commands/logs_evals.py +42 -0
- agentcore/cli/commands/package.py +118 -0
- agentcore/cli/commands/remove/__init__.py +172 -0
- agentcore/cli/commands/remove/skill_command.py +131 -0
- agentcore/cli/commands/remove/tool_command.py +59 -0
- agentcore/cli/commands/run.py +808 -0
- agentcore/cli/commands/run_ingest.py +97 -0
- agentcore/cli/commands/shared/__init__.py +0 -0
- agentcore/cli/commands/shared/arn_utils.py +9 -0
- agentcore/cli/commands/shared/filesystem_utils.py +421 -0
- agentcore/cli/commands/shared/header_utils.py +87 -0
- agentcore/cli/commands/shared/indexed_key_parser.py +76 -0
- agentcore/cli/commands/shared/lifecycle_utils.py +72 -0
- agentcore/cli/commands/shared/region_utils.py +20 -0
- agentcore/cli/commands/shared/vpc_utils.py +99 -0
- agentcore/cli/commands/status/__init__.py +30 -0
- agentcore/cli/commands/status/_guards.py +25 -0
- agentcore/cli/commands/status/action.py +741 -0
- agentcore/cli/commands/status/command.py +321 -0
- agentcore/cli/commands/status/constants.py +36 -0
- agentcore/cli/commands/status/format_knowledge_base.py +111 -0
- agentcore/cli/commands/telemetry.py +79 -0
- agentcore/cli/commands/traces/__init__.py +155 -0
- agentcore/cli/commands/traces/action.py +123 -0
- agentcore/cli/commands/update/__init__.py +63 -0
- agentcore/cli/commands/update/action.py +164 -0
- agentcore/cli/commands/validate.py +165 -0
- agentcore/cli/constants.py +96 -0
- agentcore/cli/errors.py +118 -0
- agentcore/cli/external_requirements/__init__.py +67 -0
- agentcore/cli/external_requirements/checks.py +280 -0
- agentcore/cli/external_requirements/detect.py +55 -0
- agentcore/cli/external_requirements/versions.py +57 -0
- agentcore/cli/groups.py +23 -0
- agentcore/cli/interactive.py +85 -0
- agentcore/cli/main.py +137 -0
- agentcore/cli/naming.py +11 -0
- agentcore/cli/notices.py +42 -0
- agentcore/cli/project.py +34 -0
- agentcore/cli/run_command.py +27 -0
- agentcore/cli/tree.py +135 -0
- agentcore/cli/update_notifier.py +123 -0
- agentcore/cli/variadic.py +50 -0
- agentcore/cloudformation/__init__.py +84 -0
- agentcore/cloudformation/bootstrap.py +64 -0
- agentcore/cloudformation/logical_ids.py +37 -0
- agentcore/cloudformation/outputs.py +566 -0
- agentcore/cloudformation/stack_discovery.py +75 -0
- agentcore/cloudformation/stack_events.py +107 -0
- agentcore/cloudformation/stack_status.py +98 -0
- agentcore/cloudformation/types.py +44 -0
- agentcore/lib/__init__.py +68 -0
- agentcore/lib/constants.py +77 -0
- agentcore/lib/dependency_management/__init__.py +23 -0
- agentcore/lib/dependency_management/messages.py +92 -0
- agentcore/lib/dependency_management/plan.py +98 -0
- agentcore/lib/dependency_management/semver.py +137 -0
- agentcore/lib/dependency_management/sync.py +139 -0
- agentcore/lib/dependency_management/types.py +56 -0
- agentcore/lib/errors/__init__.py +5 -0
- agentcore/lib/errors/types.py +352 -0
- agentcore/lib/errors/validation.py +121 -0
- agentcore/lib/packaging/__init__.py +81 -0
- agentcore/lib/packaging/build_args.py +23 -0
- agentcore/lib/packaging/build_context.py +26 -0
- agentcore/lib/packaging/build_context_dockerignore.py +45 -0
- agentcore/lib/packaging/container.py +95 -0
- agentcore/lib/packaging/helpers.py +289 -0
- agentcore/lib/packaging/node.py +153 -0
- agentcore/lib/packaging/python.py +135 -0
- agentcore/lib/packaging/types.py +69 -0
- agentcore/lib/packaging/uv.py +45 -0
- agentcore/lib/result.py +104 -0
- agentcore/lib/schemas/__init__.py +1 -0
- agentcore/lib/schemas/io/__init__.py +27 -0
- agentcore/lib/schemas/io/config_io.py +458 -0
- agentcore/lib/schemas/io/global_config.py +239 -0
- agentcore/lib/schemas/io/path_resolver.py +132 -0
- agentcore/lib/secrets/__init__.py +18 -0
- agentcore/lib/secrets/cipher.py +70 -0
- agentcore/lib/secrets/key_provider.py +163 -0
- agentcore/lib/secrets/sensitive_keys.py +55 -0
- agentcore/lib/time_constants.py +4 -0
- agentcore/lib/utils/__init__.py +47 -0
- agentcore/lib/utils/aws_account.py +15 -0
- agentcore/lib/utils/credentials.py +68 -0
- agentcore/lib/utils/dotenv.py +32 -0
- agentcore/lib/utils/env.py +105 -0
- agentcore/lib/utils/json_format.py +29 -0
- agentcore/lib/utils/json_rpc.py +22 -0
- agentcore/lib/utils/platform.py +33 -0
- agentcore/lib/utils/polling.py +86 -0
- agentcore/lib/utils/subprocess.py +135 -0
- agentcore/lib/utils/time_parser.py +48 -0
- agentcore/lib/utils/validation.py +106 -0
- agentcore/logging/__init__.py +10 -0
- agentcore/logging/_common.py +77 -0
- agentcore/logging/cdk_io_host.py +36 -0
- agentcore/logging/create_logger.py +107 -0
- agentcore/logging/dev_logger.py +63 -0
- agentcore/logging/exec_logger.py +159 -0
- agentcore/logging/invoke_logger.py +154 -0
- agentcore/logging/remove_logger.py +95 -0
- agentcore/operations/__init__.py +0 -0
- agentcore/operations/agent/__init__.py +0 -0
- agentcore/operations/agent/config_bundle_defaults.py +31 -0
- agentcore/operations/agent/generate/__init__.py +28 -0
- agentcore/operations/agent/generate/schema_mapper.py +319 -0
- agentcore/operations/agent/generate/types.py +172 -0
- agentcore/operations/agent/generate/write_agent_to_project.py +67 -0
- agentcore/operations/agent/import_/__init__.py +31 -0
- agentcore/operations/agent/import_/base_translator.py +449 -0
- agentcore/operations/agent/import_/constants.py +23 -0
- agentcore/operations/agent/import_/execute.py +127 -0
- agentcore/operations/agent/import_/langgraph_translator.py +294 -0
- agentcore/operations/agent/import_/pyproject_generator.py +73 -0
- agentcore/operations/agent/import_/strands_translator.py +289 -0
- agentcore/operations/config_bundle/__init__.py +1 -0
- agentcore/operations/config_bundle/bundle_name_variants.py +9 -0
- agentcore/operations/config_bundle/diff_versions.py +52 -0
- agentcore/operations/config_bundle/resolve_bundle.py +65 -0
- agentcore/operations/connectors/__init__.py +3 -0
- agentcore/operations/connectors/translators.py +63 -0
- agentcore/operations/dataset/__init__.py +21 -0
- agentcore/operations/dataset/delete.py +7 -0
- agentcore/operations/dataset/publish.py +16 -0
- agentcore/operations/dataset/pull.py +21 -0
- agentcore/operations/dataset/push.py +201 -0
- agentcore/operations/dataset/resolve_dataset.py +65 -0
- agentcore/operations/dataset/status.py +18 -0
- agentcore/operations/dataset/wait.py +25 -0
- agentcore/operations/deploy/__init__.py +152 -0
- agentcore/operations/deploy/backfill_vpc_id.py +90 -0
- agentcore/operations/deploy/change_detection.py +84 -0
- agentcore/operations/deploy/constants.py +58 -0
- agentcore/operations/deploy/dependency_sync.py +105 -0
- agentcore/operations/deploy/ensure_target.py +30 -0
- agentcore/operations/deploy/gateway_status.py +44 -0
- agentcore/operations/deploy/managed_memory_notice.py +36 -0
- agentcore/operations/deploy/payment_connector_authorization.py +106 -0
- agentcore/operations/deploy/post_deploy_datasets.py +96 -0
- agentcore/operations/deploy/post_deploy_knowledge_bases.py +104 -0
- agentcore/operations/deploy/post_deploy_observability.py +28 -0
- agentcore/operations/deploy/post_deploy_online_evals.py +60 -0
- agentcore/operations/deploy/pre_deploy_identity.py +505 -0
- agentcore/operations/deploy/preflight.py +385 -0
- agentcore/operations/deploy/region_override.py +45 -0
- agentcore/operations/deploy/teardown.py +153 -0
- agentcore/operations/dev/__init__.py +61 -0
- agentcore/operations/dev/_http.py +79 -0
- agentcore/operations/dev/_server.py +165 -0
- agentcore/operations/dev/codezip_dev_server.py +151 -0
- agentcore/operations/dev/config.py +128 -0
- agentcore/operations/dev/constants.py +9 -0
- agentcore/operations/dev/container_dev_server.py +237 -0
- agentcore/operations/dev/container_runtime.py +37 -0
- agentcore/operations/dev/dev_server.py +244 -0
- agentcore/operations/dev/gateway_env.py +25 -0
- agentcore/operations/dev/invoke.py +214 -0
- agentcore/operations/dev/invoke_a2a.py +204 -0
- agentcore/operations/dev/invoke_agui.py +88 -0
- agentcore/operations/dev/invoke_mcp.py +145 -0
- agentcore/operations/dev/invoke_types.py +30 -0
- agentcore/operations/dev/load_dev_env.py +26 -0
- agentcore/operations/dev/memory_env.py +19 -0
- agentcore/operations/dev/otel/__init__.py +5 -0
- agentcore/operations/dev/otel/collector.py +234 -0
- agentcore/operations/dev/otel/transforms.py +331 -0
- agentcore/operations/dev/payment_env.py +50 -0
- agentcore/operations/dev/server.py +28 -0
- agentcore/operations/dev/sse_transform.py +30 -0
- agentcore/operations/dev/utils.py +152 -0
- agentcore/operations/dev/web_ui/__init__.py +31 -0
- agentcore/operations/dev/web_ui/constants.py +25 -0
- agentcore/operations/dev/web_ui/handlers/__init__.py +36 -0
- agentcore/operations/dev/web_ui/handlers/_common.py +36 -0
- agentcore/operations/dev/web_ui/handlers/_deployed.py +37 -0
- agentcore/operations/dev/web_ui/handlers/a2a_proxy.py +37 -0
- agentcore/operations/dev/web_ui/handlers/cloudwatch_traces.py +71 -0
- agentcore/operations/dev/web_ui/handlers/harness_invocation.py +89 -0
- agentcore/operations/dev/web_ui/handlers/harness_utils.py +95 -0
- agentcore/operations/dev/web_ui/handlers/invocations.py +327 -0
- agentcore/operations/dev/web_ui/handlers/mcp_proxy.py +119 -0
- agentcore/operations/dev/web_ui/handlers/memory.py +84 -0
- agentcore/operations/dev/web_ui/handlers/resources.py +351 -0
- agentcore/operations/dev/web_ui/handlers/start.py +182 -0
- agentcore/operations/dev/web_ui/handlers/status.py +25 -0
- agentcore/operations/dev/web_ui/handlers/traces.py +50 -0
- agentcore/operations/dev/web_ui/run_web_ui.py +60 -0
- agentcore/operations/dev/web_ui/web_server.py +297 -0
- agentcore/operations/eval/__init__.py +8 -0
- agentcore/operations/eval/list_eval_runs.py +18 -0
- agentcore/operations/eval/logs_eval.py +119 -0
- agentcore/operations/eval/pause_resume.py +90 -0
- agentcore/operations/eval/run_eval.py +354 -0
- agentcore/operations/eval/shared/__init__.py +0 -0
- agentcore/operations/eval/shared/dataset_loader.py +68 -0
- agentcore/operations/eval/shared/dataset_session_provider.py +122 -0
- agentcore/operations/eval/shared/evaluator_runner.py +89 -0
- agentcore/operations/eval/shared/scenario_executor.py +71 -0
- agentcore/operations/eval/shared/span_collector.py +255 -0
- agentcore/operations/eval/storage.py +67 -0
- agentcore/operations/feedback/__init__.py +21 -0
- agentcore/operations/feedback/aperture_client.py +98 -0
- agentcore/operations/feedback/build_payload.py +97 -0
- agentcore/operations/feedback/constants.py +26 -0
- agentcore/operations/feedback/submit_feedback.py +150 -0
- agentcore/operations/fetch_access/__init__.py +36 -0
- agentcore/operations/fetch_access/_target.py +17 -0
- agentcore/operations/fetch_access/fetch_gateway_token.py +75 -0
- agentcore/operations/fetch_access/fetch_harness_token.py +72 -0
- agentcore/operations/fetch_access/fetch_runtime_token.py +76 -0
- agentcore/operations/fetch_access/list_agents.py +18 -0
- agentcore/operations/fetch_access/list_gateways.py +26 -0
- agentcore/operations/fetch_access/list_harnesses.py +23 -0
- agentcore/operations/fetch_access/oauth_token.py +162 -0
- agentcore/operations/fetch_access/types.py +34 -0
- agentcore/operations/harness/__init__.py +1 -0
- agentcore/operations/harness/orphan.py +84 -0
- agentcore/operations/harness/skill_utils.py +56 -0
- agentcore/operations/identity/__init__.py +33 -0
- agentcore/operations/identity/api_key_credential_provider.py +68 -0
- agentcore/operations/identity/oauth2_credential_provider.py +95 -0
- agentcore/operations/ingest/__init__.py +184 -0
- agentcore/operations/init/__init__.py +3 -0
- agentcore/operations/init/files.py +59 -0
- agentcore/operations/insights/__init__.py +21 -0
- agentcore/operations/insights/insights_storage.py +67 -0
- agentcore/operations/insights/run_insights.py +148 -0
- agentcore/operations/invoke/__init__.py +5 -0
- agentcore/operations/invoke/resolve_agent_context.py +85 -0
- agentcore/operations/jobs/__init__.py +38 -0
- agentcore/operations/jobs/ab_test/__init__.py +0 -0
- agentcore/operations/jobs/ab_test/build_options.py +126 -0
- agentcore/operations/jobs/ab_test/format.py +121 -0
- agentcore/operations/jobs/ab_test/handler.py +412 -0
- agentcore/operations/jobs/ab_test/promote.py +142 -0
- agentcore/operations/jobs/ab_test/resolve.py +221 -0
- agentcore/operations/jobs/batch_evaluation/__init__.py +0 -0
- agentcore/operations/jobs/batch_evaluation/build_source.py +68 -0
- agentcore/operations/jobs/batch_evaluation/dataset_phase1.py +95 -0
- agentcore/operations/jobs/batch_evaluation/format.py +58 -0
- agentcore/operations/jobs/batch_evaluation/handler.py +203 -0
- agentcore/operations/jobs/insights/__init__.py +0 -0
- agentcore/operations/jobs/insights/format.py +65 -0
- agentcore/operations/jobs/insights/handler.py +178 -0
- agentcore/operations/jobs/recommendation/__init__.py +0 -0
- agentcore/operations/jobs/recommendation/apply_to_bundle.py +76 -0
- agentcore/operations/jobs/recommendation/build_config.py +271 -0
- agentcore/operations/jobs/recommendation/fetch_session_spans.py +93 -0
- agentcore/operations/jobs/recommendation/format.py +77 -0
- agentcore/operations/jobs/recommendation/handler.py +331 -0
- agentcore/operations/jobs/shared/__init__.py +0 -0
- agentcore/operations/jobs/shared/constants.py +85 -0
- agentcore/operations/jobs/shared/engine.py +187 -0
- agentcore/operations/jobs/shared/format.py +104 -0
- agentcore/operations/jobs/shared/region.py +34 -0
- agentcore/operations/jobs/shared/resolve_agent_state.py +30 -0
- agentcore/operations/jobs/shared/storage.py +117 -0
- agentcore/operations/jobs/shared/wait.py +30 -0
- agentcore/operations/knowledge_base/__init__.py +33 -0
- agentcore/operations/knowledge_base/connector_config.py +105 -0
- agentcore/operations/knowledge_base/hydrate_data_sources.py +59 -0
- agentcore/operations/mcp/__init__.py +4 -0
- agentcore/operations/memory/__init__.py +13 -0
- agentcore/operations/memory/_records.py +72 -0
- agentcore/operations/memory/list_memory_records.py +45 -0
- agentcore/operations/memory/retrieve_memory_records.py +52 -0
- agentcore/operations/node/__init__.py +15 -0
- agentcore/operations/node/setup.py +36 -0
- agentcore/operations/python/__init__.py +17 -0
- agentcore/operations/python/setup.py +47 -0
- agentcore/operations/resolve_agent.py +159 -0
- agentcore/operations/session/__init__.py +86 -0
- agentcore/operations/traces/__init__.py +29 -0
- agentcore/operations/traces/get_trace.py +202 -0
- agentcore/operations/traces/insights_query.py +74 -0
- agentcore/operations/traces/list_traces.py +46 -0
- agentcore/operations/traces/trace_url.py +25 -0
- agentcore/operations/traces/types.py +55 -0
- agentcore/primitives/__init__.py +0 -0
- agentcore/primitives/_gateway_target_wizard.py +293 -0
- agentcore/primitives/_gateway_validation.py +442 -0
- agentcore/primitives/_harness_cli.py +557 -0
- agentcore/primitives/_harness_validation.py +163 -0
- agentcore/primitives/_harness_wizard.py +726 -0
- agentcore/primitives/_knowledge_base_wizard.py +259 -0
- agentcore/primitives/_payment_wizard.py +331 -0
- agentcore/primitives/_policy_form.py +160 -0
- agentcore/primitives/agent.py +817 -0
- agentcore/primitives/auth_utils.py +77 -0
- agentcore/primitives/base.py +178 -0
- agentcore/primitives/capacity_provider.py +501 -0
- agentcore/primitives/config_bundle.py +329 -0
- agentcore/primitives/credential.py +387 -0
- agentcore/primitives/credential_utils.py +45 -0
- agentcore/primitives/dataset.py +211 -0
- agentcore/primitives/deployed_gateways.py +34 -0
- agentcore/primitives/evaluator.py +909 -0
- agentcore/primitives/gateway.py +496 -0
- agentcore/primitives/gateway_target.py +988 -0
- agentcore/primitives/harness.py +706 -0
- agentcore/primitives/knowledge_base.py +477 -0
- agentcore/primitives/memory.py +387 -0
- agentcore/primitives/online_eval_config.py +365 -0
- agentcore/primitives/online_insights.py +275 -0
- agentcore/primitives/payment_connector.py +427 -0
- agentcore/primitives/payment_eligible.py +20 -0
- agentcore/primitives/payment_manager.py +605 -0
- agentcore/primitives/payment_validation.py +68 -0
- agentcore/primitives/policy.py +622 -0
- agentcore/primitives/policy_engine.py +358 -0
- agentcore/primitives/registry.py +56 -0
- agentcore/primitives/runtime_endpoint.py +361 -0
- agentcore/primitives/secret_flag_warning.py +17 -0
- agentcore/schema/__init__.py +14 -0
- agentcore/schema/_zod.py +395 -0
- agentcore/schema/constants.py +306 -0
- agentcore/schema/schemas/__init__.py +40 -0
- agentcore/schema/schemas/agent_env.py +545 -0
- agentcore/schema/schemas/agentcore_project.py +530 -0
- agentcore/schema/schemas/auth.py +286 -0
- agentcore/schema/schemas/aws_targets.py +72 -0
- agentcore/schema/schemas/connections.py +187 -0
- agentcore/schema/schemas/deployed_state.py +322 -0
- agentcore/schema/schemas/mcp.py +650 -0
- agentcore/schema/schemas/mcp_defs.py +54 -0
- agentcore/schema/schemas/primitives/__init__.py +52 -0
- agentcore/schema/schemas/primitives/ab_test.py +162 -0
- agentcore/schema/schemas/primitives/capacity_provider.py +214 -0
- agentcore/schema/schemas/primitives/config_bundle.py +48 -0
- agentcore/schema/schemas/primitives/dataset.py +55 -0
- agentcore/schema/schemas/primitives/evaluator.py +171 -0
- agentcore/schema/schemas/primitives/harness.py +710 -0
- agentcore/schema/schemas/primitives/knowledge_base.py +90 -0
- agentcore/schema/schemas/primitives/memory.py +113 -0
- agentcore/schema/schemas/primitives/online_eval_config.py +77 -0
- agentcore/schema/schemas/primitives/payment.py +114 -0
- agentcore/schema/schemas/primitives/policy.py +83 -0
- agentcore/schema/schemas/primitives/tags.py +50 -0
- agentcore/schema/schemas/zod_util.py +5 -0
- agentcore/schema/types/__init__.py +3 -0
- agentcore/schema/types/path.py +16 -0
- agentcore/templates/__init__.py +115 -0
- agentcore/templates/_handlebars.py +782 -0
- agentcore/templates/_js.py +164 -0
- agentcore/templates/base_renderer.py +107 -0
- agentcore/templates/cdk_renderer.py +129 -0
- agentcore/templates/evaluator_renderer.py +39 -0
- agentcore/templates/gateway_target_renderer.py +69 -0
- agentcore/templates/llm_context/README.md +16 -0
- agentcore/templates/llm_context/agentcore.ts +685 -0
- agentcore/templates/llm_context/aws-targets.ts +51 -0
- agentcore/templates/profiles.py +151 -0
- agentcore/templates/render.py +92 -0
- agentcore/templates/renderers.py +83 -0
- agentcore/templates/schema_assets.py +23 -0
- agentcore/templates/template_root.py +28 -0
- agentcore/templates/types.py +192 -0
- agentcore_cli-0.31.1.dist-info/METADATA +84 -0
- agentcore_cli-0.31.1.dist-info/RECORD +655 -0
- agentcore_cli-0.31.1.dist-info/WHEEL +4 -0
- agentcore_cli-0.31.1.dist-info/entry_points.txt +2 -0
- agentcore_cli-0.31.1.dist-info/licenses/LICENSE +175 -0
- agentcore_cli-0.31.1.dist-info/licenses/NOTICE +88 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Project discovery and AgentCore file paths (port of ``path-resolver.ts``)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
from agentcore.lib.constants import APP_DIR, CLI_LOGS_DIR, CLI_SYSTEM_DIR, CONFIG_DIR, CONFIG_FILES
|
|
9
|
+
from agentcore.lib.errors.types import NoProjectError
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"CONFIG_FILES",
|
|
13
|
+
"PathConfig",
|
|
14
|
+
"PathResolver",
|
|
15
|
+
"default_path_config",
|
|
16
|
+
"find_config_root",
|
|
17
|
+
"find_project_root",
|
|
18
|
+
"get_session_project_root",
|
|
19
|
+
"get_working_directory",
|
|
20
|
+
"require_config_root",
|
|
21
|
+
"set_session_project_root",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_working_directory() -> str:
|
|
26
|
+
"""Directory the user invoked the CLI from (``INIT_CWD`` when launched via an npm script)."""
|
|
27
|
+
return os.environ.get("INIT_CWD") or os.getcwd()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
_session_project_root: str | None = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def set_session_project_root(project_root: str | None) -> None:
|
|
34
|
+
"""Set the project root for this session (after ``create``) so discovery checks it first."""
|
|
35
|
+
global _session_project_root
|
|
36
|
+
_session_project_root = os.fspath(project_root) if project_root is not None else None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_session_project_root() -> str | None:
|
|
40
|
+
return _session_project_root
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass(slots=True)
|
|
44
|
+
class PathConfig:
|
|
45
|
+
"""Where AgentCore files are stored: ``base_dir`` is the ``agentcore/`` directory."""
|
|
46
|
+
|
|
47
|
+
base_dir: str
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _is_valid_config_dir(config_path: str) -> bool:
|
|
51
|
+
return os.path.exists(os.path.join(config_path, CONFIG_FILES.AGENT_ENV))
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def find_config_root(start_dir: str | None = None) -> str | None:
|
|
55
|
+
"""Walk up from ``start_dir`` to the nearest ``agentcore/`` dir containing ``agentcore.json``."""
|
|
56
|
+
if _session_project_root:
|
|
57
|
+
session_config = os.path.join(_session_project_root, CONFIG_DIR)
|
|
58
|
+
if os.path.exists(session_config) and _is_valid_config_dir(session_config):
|
|
59
|
+
return session_config
|
|
60
|
+
|
|
61
|
+
current = os.fspath(start_dir) if start_dir is not None else get_working_directory()
|
|
62
|
+
while True:
|
|
63
|
+
config_path = os.path.join(current, CONFIG_DIR)
|
|
64
|
+
if os.path.exists(config_path) and _is_valid_config_dir(config_path):
|
|
65
|
+
return config_path
|
|
66
|
+
parent = os.path.dirname(current)
|
|
67
|
+
if parent == current:
|
|
68
|
+
return None
|
|
69
|
+
current = parent
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def require_config_root(start_dir: str | None = None) -> str:
|
|
73
|
+
root = find_config_root(start_dir)
|
|
74
|
+
if not root:
|
|
75
|
+
raise NoProjectError()
|
|
76
|
+
return root
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def find_project_root(start_dir: str | None = None) -> str | None:
|
|
80
|
+
"""The project root (parent of ``agentcore/``), or ``None``."""
|
|
81
|
+
config_root = find_config_root(start_dir if start_dir is not None else os.getcwd())
|
|
82
|
+
return os.path.dirname(config_root) if config_root else None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def default_path_config() -> PathConfig:
|
|
86
|
+
"""Default: ``agentcore/`` under the working directory."""
|
|
87
|
+
return PathConfig(base_dir=os.path.join(get_working_directory(), CONFIG_DIR))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class PathResolver:
|
|
91
|
+
def __init__(self, config: PathConfig | None = None, *, base_dir: str | None = None):
|
|
92
|
+
resolved = base_dir or (config.base_dir if config else None)
|
|
93
|
+
self._config = PathConfig(base_dir=os.fspath(resolved) if resolved else default_path_config().base_dir)
|
|
94
|
+
|
|
95
|
+
def get_base_dir(self) -> str:
|
|
96
|
+
return self._config.base_dir
|
|
97
|
+
|
|
98
|
+
def get_project_root(self) -> str:
|
|
99
|
+
return os.path.dirname(self._config.base_dir)
|
|
100
|
+
|
|
101
|
+
def get_agent_config_path(self) -> str:
|
|
102
|
+
return os.path.join(self._config.base_dir, CONFIG_FILES.AGENT_ENV)
|
|
103
|
+
|
|
104
|
+
def get_aws_targets_config_path(self) -> str:
|
|
105
|
+
return os.path.join(self._config.base_dir, CONFIG_FILES.AWS_TARGETS)
|
|
106
|
+
|
|
107
|
+
def get_cli_system_dir(self) -> str:
|
|
108
|
+
return os.path.join(self._config.base_dir, CLI_SYSTEM_DIR)
|
|
109
|
+
|
|
110
|
+
def get_logs_dir(self) -> str:
|
|
111
|
+
return os.path.join(self._config.base_dir, CLI_SYSTEM_DIR, CLI_LOGS_DIR)
|
|
112
|
+
|
|
113
|
+
def get_invoke_logs_dir(self) -> str:
|
|
114
|
+
return os.path.join(self._config.base_dir, CLI_SYSTEM_DIR, CLI_LOGS_DIR, "invoke")
|
|
115
|
+
|
|
116
|
+
def get_state_path(self) -> str:
|
|
117
|
+
return os.path.join(self._config.base_dir, CLI_SYSTEM_DIR, CONFIG_FILES.DEPLOYED_STATE)
|
|
118
|
+
|
|
119
|
+
def get_mcp_defs_path(self) -> str:
|
|
120
|
+
return os.path.join(self._config.base_dir, CONFIG_FILES.MCP_DEFS)
|
|
121
|
+
|
|
122
|
+
def get_harnesses_dir(self) -> str:
|
|
123
|
+
return os.path.join(self.get_project_root(), APP_DIR)
|
|
124
|
+
|
|
125
|
+
def get_harness_dir(self, harness_name: str) -> str:
|
|
126
|
+
return os.path.join(self.get_project_root(), APP_DIR, harness_name)
|
|
127
|
+
|
|
128
|
+
def get_harness_config_path(self, harness_name: str) -> str:
|
|
129
|
+
return os.path.join(self.get_project_root(), APP_DIR, harness_name, "harness.json")
|
|
130
|
+
|
|
131
|
+
def set_base_dir(self, base_dir: str) -> None:
|
|
132
|
+
self._config.base_dir = os.fspath(base_dir)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from agentcore.lib.secrets.cipher import ENC_PREFIX, decrypt_secret, encrypt_secret
|
|
2
|
+
from agentcore.lib.secrets.key_provider import resolve_candidate_keys, resolve_encryption_key
|
|
3
|
+
from agentcore.lib.secrets.sensitive_keys import (
|
|
4
|
+
SENSITIVE_KEY_PATTERNS,
|
|
5
|
+
is_sensitive_key,
|
|
6
|
+
validate_credential_name_encryptable,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"ENC_PREFIX",
|
|
11
|
+
"SENSITIVE_KEY_PATTERNS",
|
|
12
|
+
"decrypt_secret",
|
|
13
|
+
"encrypt_secret",
|
|
14
|
+
"is_sensitive_key",
|
|
15
|
+
"resolve_candidate_keys",
|
|
16
|
+
"resolve_encryption_key",
|
|
17
|
+
"validate_credential_name_encryptable",
|
|
18
|
+
]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""AES-256-GCM envelope for secrets at rest (port of ``src/lib/secrets/cipher.ts``).
|
|
2
|
+
|
|
3
|
+
Envelope: ``enc:v1:`` + base64(IV[12] || tag[16] || ciphertext). ``cryptography``'s AESGCM
|
|
4
|
+
emits ciphertext || tag, so the tag is moved to sit right after the IV to match Node.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import base64
|
|
10
|
+
import binascii
|
|
11
|
+
import os
|
|
12
|
+
from collections.abc import Sequence
|
|
13
|
+
|
|
14
|
+
from cryptography.exceptions import InvalidTag
|
|
15
|
+
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
16
|
+
|
|
17
|
+
from agentcore.lib.errors.types import SecretDecryptionError
|
|
18
|
+
|
|
19
|
+
ENC_PREFIX = "enc:v1:"
|
|
20
|
+
|
|
21
|
+
IV_BYTES = 12
|
|
22
|
+
TAG_BYTES = 16
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def encrypt_secret(plaintext: str, key: bytes) -> str:
|
|
26
|
+
"""Encrypt a plaintext secret to an ``enc:v1:`` envelope."""
|
|
27
|
+
iv = os.urandom(IV_BYTES)
|
|
28
|
+
sealed = AESGCM(key).encrypt(iv, plaintext.encode("utf-8"), None)
|
|
29
|
+
ciphertext, tag = sealed[:-TAG_BYTES], sealed[-TAG_BYTES:]
|
|
30
|
+
return ENC_PREFIX + base64.b64encode(iv + tag + ciphertext).decode("ascii")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _b64decode_lenient(data: str) -> bytes:
|
|
34
|
+
# Node's Buffer.from(..., 'base64') tolerates missing padding and stray characters.
|
|
35
|
+
cleaned = "".join(c for c in data if c.isalnum() or c in "+/-_")
|
|
36
|
+
cleaned = cleaned.replace("-", "+").replace("_", "/")
|
|
37
|
+
return base64.b64decode(cleaned + "=" * (-len(cleaned) % 4))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _try_decrypt(token: str, key: bytes) -> str | None:
|
|
41
|
+
"""Decrypt with one key; ``None`` on any failure."""
|
|
42
|
+
try:
|
|
43
|
+
raw = _b64decode_lenient(token[len(ENC_PREFIX) :])
|
|
44
|
+
iv = raw[:IV_BYTES]
|
|
45
|
+
tag = raw[IV_BYTES : IV_BYTES + TAG_BYTES]
|
|
46
|
+
ciphertext = raw[IV_BYTES + TAG_BYTES :]
|
|
47
|
+
if len(iv) != IV_BYTES or len(tag) != TAG_BYTES:
|
|
48
|
+
return None
|
|
49
|
+
return AESGCM(key).decrypt(iv, ciphertext + tag, None).decode("utf-8")
|
|
50
|
+
except (InvalidTag, ValueError, TypeError, binascii.Error, UnicodeDecodeError):
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def decrypt_secret(token: str, keys: bytes | Sequence[bytes]) -> str:
|
|
55
|
+
"""Decrypt an ``enc:v1:`` envelope, trying each candidate key in turn.
|
|
56
|
+
|
|
57
|
+
A value may have been sealed by the keychain key or the keyfile key; trying all keys lets
|
|
58
|
+
it decrypt even if the active key source changed since it was written.
|
|
59
|
+
"""
|
|
60
|
+
if not token.startswith(ENC_PREFIX):
|
|
61
|
+
raise SecretDecryptionError("Value is not an encrypted secret envelope.")
|
|
62
|
+
candidates = [keys] if isinstance(keys, (bytes, bytearray)) else list(keys)
|
|
63
|
+
for key in candidates:
|
|
64
|
+
plaintext = _try_decrypt(token, bytes(key))
|
|
65
|
+
if plaintext is not None:
|
|
66
|
+
return plaintext
|
|
67
|
+
raise SecretDecryptionError(
|
|
68
|
+
"Could not decrypt a stored secret in agentcore/.env.local — the encryption key may be missing or changed. "
|
|
69
|
+
"Re-add the credential"
|
|
70
|
+
)
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""Machine encryption key resolution (port of ``src/lib/secrets/key-provider.ts``).
|
|
2
|
+
|
|
3
|
+
Encryption key: OS keychain (service ``aws-agentcore``, account ``env-local-secret-key``,
|
|
4
|
+
base64-encoded 32 bytes) unless ``AGENTCORE_DISABLE_KEYCHAIN=1``, else the keyfile
|
|
5
|
+
``$AGENTCORE_CONFIG_DIR/secrets.key`` (default ``~/.agentcore/secrets.key``, raw 32 bytes, 0600).
|
|
6
|
+
Decryption tries every key that exists, without creating any.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import base64
|
|
12
|
+
import os
|
|
13
|
+
import sys
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
from agentcore.lib.errors.types import SecretEncryptionError
|
|
17
|
+
|
|
18
|
+
KEY_BYTES = 32
|
|
19
|
+
KEYCHAIN_SERVICE = "aws-agentcore"
|
|
20
|
+
KEYCHAIN_ACCOUNT = "env-local-secret-key"
|
|
21
|
+
|
|
22
|
+
_cached_key: bytes | None = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _keychain_disabled() -> bool:
|
|
26
|
+
return os.environ.get("AGENTCORE_DISABLE_KEYCHAIN") == "1"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _keychain_service() -> str:
|
|
30
|
+
# @napi-rs/keyring (keyring-rs) stores Windows credentials under the target name
|
|
31
|
+
# "<account>.<service>"; Python keyring's Windows backend uses the service name as the
|
|
32
|
+
# target, so pass the keyring-rs target to address the same credential.
|
|
33
|
+
if sys.platform == "win32":
|
|
34
|
+
return f"{KEYCHAIN_ACCOUNT}.{KEYCHAIN_SERVICE}"
|
|
35
|
+
return KEYCHAIN_SERVICE
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _b64decode(value: str) -> bytes:
|
|
39
|
+
return base64.b64decode(value + "=" * (-len(value) % 4))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _try_keychain_key() -> bytes | None:
|
|
43
|
+
"""Read or create the keychain key. Opt-out and best-effort: any failure returns ``None``."""
|
|
44
|
+
if _keychain_disabled():
|
|
45
|
+
return None
|
|
46
|
+
try:
|
|
47
|
+
import keyring
|
|
48
|
+
|
|
49
|
+
service = _keychain_service()
|
|
50
|
+
try:
|
|
51
|
+
existing = keyring.get_password(service, KEYCHAIN_ACCOUNT)
|
|
52
|
+
if existing:
|
|
53
|
+
return _b64decode(existing)
|
|
54
|
+
except Exception:
|
|
55
|
+
pass # no stored password yet
|
|
56
|
+
key = os.urandom(KEY_BYTES)
|
|
57
|
+
keyring.set_password(service, KEYCHAIN_ACCOUNT, base64.b64encode(key).decode("ascii"))
|
|
58
|
+
# Re-read after writing: if a concurrent process stored a different key in between,
|
|
59
|
+
# trust the persisted value so both processes converge on the same key.
|
|
60
|
+
try:
|
|
61
|
+
persisted = keyring.get_password(service, KEYCHAIN_ACCOUNT)
|
|
62
|
+
if persisted:
|
|
63
|
+
return _b64decode(persisted)
|
|
64
|
+
except Exception:
|
|
65
|
+
pass
|
|
66
|
+
return key
|
|
67
|
+
except Exception:
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def resolve_config_dir() -> Path:
|
|
72
|
+
env_dir = os.environ.get("AGENTCORE_CONFIG_DIR")
|
|
73
|
+
return Path(env_dir) if env_dir is not None else Path.home() / ".agentcore"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def keyfile_path() -> Path:
|
|
77
|
+
return resolve_config_dir() / "secrets.key"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _assert_keyfile_size(key: bytes, path: Path) -> bytes:
|
|
81
|
+
"""A keyfile that exists but isn't KEY_BYTES long is corrupt; never overwrite it."""
|
|
82
|
+
if len(key) == KEY_BYTES:
|
|
83
|
+
return key
|
|
84
|
+
raise SecretEncryptionError(
|
|
85
|
+
f"Encryption key file at {path} is corrupt (expected {KEY_BYTES} bytes, found {len(key)}). "
|
|
86
|
+
"Move it aside and re-add your credentials, or restore the original key file"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _keyfile_key() -> bytes:
|
|
91
|
+
path = keyfile_path()
|
|
92
|
+
try:
|
|
93
|
+
if path.exists():
|
|
94
|
+
# A wrong-sized file is corruption, not a cue to mint a new key: overwriting it
|
|
95
|
+
# would orphan every secret sealed with the real key.
|
|
96
|
+
return _assert_keyfile_size(path.read_bytes(), path)
|
|
97
|
+
resolve_config_dir().mkdir(parents=True, exist_ok=True)
|
|
98
|
+
key = os.urandom(KEY_BYTES)
|
|
99
|
+
try:
|
|
100
|
+
# O_EXCL makes first-time creation race-safe: if another process created the file
|
|
101
|
+
# since the exists() check, read theirs instead of clobbering it.
|
|
102
|
+
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_BINARY", 0), 0o600)
|
|
103
|
+
except FileExistsError:
|
|
104
|
+
return _assert_keyfile_size(path.read_bytes(), path)
|
|
105
|
+
with os.fdopen(fd, "wb") as fh:
|
|
106
|
+
fh.write(key)
|
|
107
|
+
return key
|
|
108
|
+
except SecretEncryptionError:
|
|
109
|
+
raise
|
|
110
|
+
except Exception as exc:
|
|
111
|
+
raise SecretEncryptionError(
|
|
112
|
+
f"Could not create or read the machine encryption key at {path}.", cause=exc
|
|
113
|
+
) from exc
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _read_keyfile_key_if_present() -> bytes | None:
|
|
117
|
+
try:
|
|
118
|
+
path = keyfile_path()
|
|
119
|
+
if path.exists():
|
|
120
|
+
key = path.read_bytes()
|
|
121
|
+
if len(key) == KEY_BYTES:
|
|
122
|
+
return key
|
|
123
|
+
except OSError:
|
|
124
|
+
pass
|
|
125
|
+
return None
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _read_keychain_key_if_present() -> bytes | None:
|
|
129
|
+
if _keychain_disabled():
|
|
130
|
+
return None
|
|
131
|
+
try:
|
|
132
|
+
import keyring
|
|
133
|
+
|
|
134
|
+
existing = keyring.get_password(_keychain_service(), KEYCHAIN_ACCOUNT)
|
|
135
|
+
return _b64decode(existing) if existing else None
|
|
136
|
+
except Exception:
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def resolve_encryption_key() -> bytes:
|
|
141
|
+
"""The single key used to ENCRYPT new values: keychain first, keyfile fallback. Creates one if needed."""
|
|
142
|
+
global _cached_key
|
|
143
|
+
if _cached_key is not None:
|
|
144
|
+
return _cached_key
|
|
145
|
+
_cached_key = _try_keychain_key() or _keyfile_key()
|
|
146
|
+
return _cached_key
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def resolve_candidate_keys() -> list[bytes]:
|
|
150
|
+
"""All keys usable for DECRYPTION (keychain, then keyfile). Read-only; may be empty."""
|
|
151
|
+
keys: list[bytes] = []
|
|
152
|
+
from_keychain = _read_keychain_key_if_present()
|
|
153
|
+
if from_keychain:
|
|
154
|
+
keys.append(from_keychain)
|
|
155
|
+
from_keyfile = _read_keyfile_key_if_present()
|
|
156
|
+
if from_keyfile and from_keyfile not in keys:
|
|
157
|
+
keys.append(from_keyfile)
|
|
158
|
+
return keys
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def reset_key_cache_for_tests() -> None:
|
|
162
|
+
global _cached_key
|
|
163
|
+
_cached_key = None
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Which env keys hold secrets that must be encrypted at rest (port of ``sensitive-keys.ts``)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from typing import Literal
|
|
7
|
+
|
|
8
|
+
# Suffixes whose values are secrets.
|
|
9
|
+
SECRET_SUFFIXES = (
|
|
10
|
+
"_API_KEY_SECRET",
|
|
11
|
+
"_WALLET_SECRET",
|
|
12
|
+
"_AUTHORIZATION_PRIVATE_KEY",
|
|
13
|
+
"_APP_SECRET",
|
|
14
|
+
"_CLIENT_SECRET",
|
|
15
|
+
"_API_KEY",
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# Reference/identifier suffixes that are NOT secrets (stay readable).
|
|
19
|
+
REFERENCE_SUFFIXES = ("_API_KEY_ID", "_APP_ID", "_CLIENT_ID", "_AUTHORIZATION_ID")
|
|
20
|
+
|
|
21
|
+
SENSITIVE_KEY_PATTERNS: list[re.Pattern[str]] = [re.compile(f"{s}$") for s in SECRET_SUFFIXES]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _is_bare_model_credential(key: str) -> bool:
|
|
25
|
+
"""Model-provider API keys are stored as bare ``AGENTCORE_CREDENTIAL_<NAME>`` (no secret suffix)."""
|
|
26
|
+
if not key.startswith("AGENTCORE_CREDENTIAL_"):
|
|
27
|
+
return False
|
|
28
|
+
return not key.endswith(REFERENCE_SUFFIXES)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def is_sensitive_key(key: str) -> bool:
|
|
32
|
+
if key.endswith(REFERENCE_SUFFIXES):
|
|
33
|
+
return False
|
|
34
|
+
if any(p.search(key) for p in SENSITIVE_KEY_PATTERNS):
|
|
35
|
+
return True
|
|
36
|
+
return _is_bare_model_credential(key)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _normalize_credential_name_to_key(name: str) -> str:
|
|
40
|
+
return name.replace("-", "_").upper()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def validate_credential_name_encryptable(name: str) -> Literal[True] | str:
|
|
44
|
+
"""Reject credential names whose env var would end in a reference suffix (and so stay unencrypted).
|
|
45
|
+
|
|
46
|
+
Returns ``True`` if safe, else an error message (the ``True | str`` validator contract).
|
|
47
|
+
"""
|
|
48
|
+
normalized = _normalize_credential_name_to_key(name)
|
|
49
|
+
collision = next((s for s in REFERENCE_SUFFIXES if normalized.endswith(s)), None)
|
|
50
|
+
if collision:
|
|
51
|
+
return (
|
|
52
|
+
f'Credential name "{name}" ends in a reserved reference suffix ({collision}) and its secret would not be '
|
|
53
|
+
"encrypted at rest. Choose a name that does not end in id/client-id/app-id/authorization-id."
|
|
54
|
+
)
|
|
55
|
+
return True
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from agentcore.lib.utils.aws_account import detect_aws_account
|
|
2
|
+
from agentcore.lib.utils.credentials import SecureCredentials
|
|
3
|
+
from agentcore.lib.utils.env import (
|
|
4
|
+
get_env_path,
|
|
5
|
+
get_env_var,
|
|
6
|
+
read_env_file,
|
|
7
|
+
remove_env_vars,
|
|
8
|
+
set_env_var,
|
|
9
|
+
write_env_file,
|
|
10
|
+
)
|
|
11
|
+
from agentcore.lib.utils.json_format import to_json_string
|
|
12
|
+
from agentcore.lib.utils.json_rpc import parse_json_rpc_response
|
|
13
|
+
from agentcore.lib.utils.platform import is_windows
|
|
14
|
+
from agentcore.lib.utils.polling import PollResult, is_throttling_error, poll
|
|
15
|
+
from agentcore.lib.utils.subprocess import (
|
|
16
|
+
SubprocessResult,
|
|
17
|
+
check_subprocess,
|
|
18
|
+
run_subprocess,
|
|
19
|
+
run_subprocess_capture,
|
|
20
|
+
)
|
|
21
|
+
from agentcore.lib.utils.time_parser import parse_time_string
|
|
22
|
+
from agentcore.lib.utils.validation import resilient_parse, validate_agent_schema, validate_project_schema
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"PollResult",
|
|
26
|
+
"SecureCredentials",
|
|
27
|
+
"SubprocessResult",
|
|
28
|
+
"check_subprocess",
|
|
29
|
+
"detect_aws_account",
|
|
30
|
+
"get_env_path",
|
|
31
|
+
"get_env_var",
|
|
32
|
+
"is_throttling_error",
|
|
33
|
+
"is_windows",
|
|
34
|
+
"parse_json_rpc_response",
|
|
35
|
+
"parse_time_string",
|
|
36
|
+
"poll",
|
|
37
|
+
"read_env_file",
|
|
38
|
+
"remove_env_vars",
|
|
39
|
+
"resilient_parse",
|
|
40
|
+
"run_subprocess",
|
|
41
|
+
"run_subprocess_capture",
|
|
42
|
+
"set_env_var",
|
|
43
|
+
"to_json_string",
|
|
44
|
+
"validate_agent_schema",
|
|
45
|
+
"validate_project_schema",
|
|
46
|
+
"write_env_file",
|
|
47
|
+
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def detect_aws_account() -> str | None:
|
|
7
|
+
"""AWS account ID of the current credentials via STS GetCallerIdentity; ``None`` if unavailable."""
|
|
8
|
+
try:
|
|
9
|
+
import boto3
|
|
10
|
+
|
|
11
|
+
region = os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION") or "us-east-1"
|
|
12
|
+
response = boto3.session.Session().client("sts", region_name=region).get_caller_identity()
|
|
13
|
+
return response.get("Account") or None
|
|
14
|
+
except Exception:
|
|
15
|
+
return None
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Redacting container for credential values (port of ``src/lib/utils/credentials.ts``)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from types import MappingProxyType
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SecureCredentials:
|
|
11
|
+
"""Immutable credential store that never exposes values via ``str``/``repr``/JSON."""
|
|
12
|
+
|
|
13
|
+
__slots__ = ("_credentials",)
|
|
14
|
+
|
|
15
|
+
def __init__(self, credentials: Mapping[str, str] | None = None):
|
|
16
|
+
object.__setattr__(self, "_credentials", MappingProxyType(dict(credentials or {})))
|
|
17
|
+
|
|
18
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
|
19
|
+
raise AttributeError("SecureCredentials is immutable")
|
|
20
|
+
|
|
21
|
+
def get(self, key: str) -> str | None:
|
|
22
|
+
return self._credentials.get(key)
|
|
23
|
+
|
|
24
|
+
def has(self, key: str) -> bool:
|
|
25
|
+
return key in self._credentials
|
|
26
|
+
|
|
27
|
+
def __contains__(self, key: object) -> bool:
|
|
28
|
+
return key in self._credentials
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def size(self) -> int:
|
|
32
|
+
return len(self._credentials)
|
|
33
|
+
|
|
34
|
+
def __len__(self) -> int:
|
|
35
|
+
return len(self._credentials)
|
|
36
|
+
|
|
37
|
+
def is_empty(self) -> bool:
|
|
38
|
+
return not self._credentials
|
|
39
|
+
|
|
40
|
+
def keys(self) -> list[str]:
|
|
41
|
+
return list(self._credentials)
|
|
42
|
+
|
|
43
|
+
def merge(self, other: SecureCredentials | Mapping[str, str | None]) -> SecureCredentials:
|
|
44
|
+
"""New instance with ``other`` overlaid on these credentials."""
|
|
45
|
+
merged = dict(self._credentials)
|
|
46
|
+
source = other._credentials if isinstance(other, SecureCredentials) else other
|
|
47
|
+
merged.update({k: v for k, v in source.items() if v is not None})
|
|
48
|
+
return SecureCredentials(merged)
|
|
49
|
+
|
|
50
|
+
def to_plain_object(self) -> dict[str, str]:
|
|
51
|
+
"""WARNING: exposes credential values."""
|
|
52
|
+
return dict(self._credentials)
|
|
53
|
+
|
|
54
|
+
def to_json(self) -> dict[str, Any]:
|
|
55
|
+
return {"_redacted": "[CREDENTIALS REDACTED]", "count": len(self._credentials), "keys": self.keys()}
|
|
56
|
+
|
|
57
|
+
def __str__(self) -> str:
|
|
58
|
+
return f"[SecureCredentials: {len(self._credentials)} credential(s)]"
|
|
59
|
+
|
|
60
|
+
__repr__ = __str__
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def from_env_vars(env_vars: Mapping[str, str]) -> SecureCredentials:
|
|
64
|
+
return SecureCredentials(env_vars)
|
|
65
|
+
|
|
66
|
+
@staticmethod
|
|
67
|
+
def empty() -> SecureCredentials:
|
|
68
|
+
return SecureCredentials()
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Exact port of the ``parse`` function from the ``dotenv`` npm package (v17).
|
|
2
|
+
|
|
3
|
+
``.env.local`` is shared with the TypeScript CLI, so parsing must match byte for byte, including
|
|
4
|
+
its quirks: only ``\\n`` and ``\\r`` are unescaped in double-quoted values.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
|
|
11
|
+
_LINE = re.compile(
|
|
12
|
+
r"(?:^|^)\s*(?:export\s+)?([A-Za-z0-9_.-]+)(?:\s*=\s*?|:\s+?)"
|
|
13
|
+
r"(\s*'(?:\\'|[^'])*'|\s*\"(?:\\\"|[^\"])*\"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?"
|
|
14
|
+
r"\s*(?:#.*)?(?:$|$)",
|
|
15
|
+
re.MULTILINE,
|
|
16
|
+
)
|
|
17
|
+
_SURROUNDING_QUOTES = re.compile(r"^(['\"`])([\s\S]*)\1$", re.MULTILINE)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def parse(src: str | bytes) -> dict[str, str]:
|
|
21
|
+
text = src.decode("utf-8") if isinstance(src, bytes) else src
|
|
22
|
+
text = re.sub(r"\r\n?", "\n", text)
|
|
23
|
+
out: dict[str, str] = {}
|
|
24
|
+
for match in _LINE.finditer(text):
|
|
25
|
+
key = match.group(1)
|
|
26
|
+
value = (match.group(2) or "").strip()
|
|
27
|
+
maybe_quote = value[:1]
|
|
28
|
+
value = _SURROUNDING_QUOTES.sub(r"\2", value)
|
|
29
|
+
if maybe_quote == '"':
|
|
30
|
+
value = value.replace("\\n", "\n").replace("\\r", "\r")
|
|
31
|
+
out[key] = value
|
|
32
|
+
return out
|