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,97 @@
|
|
|
1
|
+
"""`agentcore run ingest` (port of the `ingest` subcommand in src/cli/commands/run/command.tsx)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import signal as signal_module
|
|
7
|
+
import sys
|
|
8
|
+
import threading
|
|
9
|
+
|
|
10
|
+
import typer
|
|
11
|
+
|
|
12
|
+
from agentcore.cli.groups import group
|
|
13
|
+
from agentcore.cli.run_command import run_cli_command
|
|
14
|
+
from agentcore.lib.errors.types import ValidationError
|
|
15
|
+
from agentcore.lib.schemas.io.config_io import ConfigIO
|
|
16
|
+
from agentcore.lib.schemas.io.path_resolver import find_config_root
|
|
17
|
+
from agentcore.operations.ingest import RunKbIngestionInput, run_kb_ingestion_by_name
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _empty_state(): # readDeployedState().catch(() => ({ targets: {} }))
|
|
21
|
+
from agentcore.schema import DeployedState
|
|
22
|
+
|
|
23
|
+
return DeployedState(targets={})
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def run_ingest(name: str | None, target: str, data_source: str | None, as_json: bool) -> None:
|
|
27
|
+
if not name:
|
|
28
|
+
raise ValidationError("A --name is required for `agentcore run ingest`.")
|
|
29
|
+
target_name = target or "default"
|
|
30
|
+
|
|
31
|
+
config_io = ConfigIO()
|
|
32
|
+
project = config_io.read_project_spec()
|
|
33
|
+
aws_targets = config_io.read_aws_deployment_targets()
|
|
34
|
+
try:
|
|
35
|
+
deployed_state = config_io.read_deployed_state()
|
|
36
|
+
except Exception: # noqa: BLE001 - missing/invalid state means nothing is deployed
|
|
37
|
+
deployed_state = _empty_state()
|
|
38
|
+
|
|
39
|
+
if not any(kb.name == name for kb in project.knowledge_bases or []):
|
|
40
|
+
raise ValidationError(f"Knowledge base '{name}' is not in agentcore.json.")
|
|
41
|
+
aws_target = next((t for t in aws_targets if t.name == target_name), None)
|
|
42
|
+
if aws_target is None:
|
|
43
|
+
raise ValidationError(f"Deployment target '{target_name}' is not in aws-targets.json.")
|
|
44
|
+
|
|
45
|
+
# Ctrl+C aborts long retry sleeps cleanly. Progress goes to stderr so --json stdout stays parseable.
|
|
46
|
+
abort = threading.Event()
|
|
47
|
+
previous = None
|
|
48
|
+
if threading.current_thread() is threading.main_thread():
|
|
49
|
+
previous = signal_module.signal(signal_module.SIGINT, lambda *_: abort.set())
|
|
50
|
+
try:
|
|
51
|
+
result = run_kb_ingestion_by_name(
|
|
52
|
+
RunKbIngestionInput(
|
|
53
|
+
knowledge_base_name=name,
|
|
54
|
+
deployed_state=deployed_state,
|
|
55
|
+
target_name=target_name,
|
|
56
|
+
region=aws_target.region,
|
|
57
|
+
data_source_uri=data_source,
|
|
58
|
+
signal=abort,
|
|
59
|
+
on_progress=None if as_json else (lambda msg: sys.stderr.write(f"{msg}\n")),
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
finally:
|
|
63
|
+
if previous is not None:
|
|
64
|
+
signal_module.signal(signal_module.SIGINT, previous)
|
|
65
|
+
|
|
66
|
+
if not result.success:
|
|
67
|
+
raise result.error
|
|
68
|
+
|
|
69
|
+
jobs = result.value.started_jobs
|
|
70
|
+
if as_json:
|
|
71
|
+
typer.echo(json.dumps({"success": True, "startedJobs": [j.to_json() for j in jobs]}, separators=(",", ":")))
|
|
72
|
+
else:
|
|
73
|
+
typer.echo(f"Started ingestion for '{name}' ({len(jobs)} data source(s)):")
|
|
74
|
+
for job in jobs:
|
|
75
|
+
typer.echo(f" {job.uri} → {job.ingestion_job_id}")
|
|
76
|
+
typer.echo("\nRun 'agentcore status' to track progress.")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def ingest_command(
|
|
80
|
+
name: str | None = typer.Option(None, "--name", help="Knowledge base name (must exist in agentcore.json)"),
|
|
81
|
+
target: str = typer.Option("default", "--target", help='Deployment target name (defaults to "default")'),
|
|
82
|
+
data_source: str | None = typer.Option(
|
|
83
|
+
None, "--data-source", help="Ingest only the data source with this URI (default: all sources)"
|
|
84
|
+
),
|
|
85
|
+
as_json: bool = typer.Option(False, "--json", help="Output as JSON [non-interactive]"),
|
|
86
|
+
) -> None:
|
|
87
|
+
if not find_config_root():
|
|
88
|
+
typer.echo("No agentcore project found. Run `agentcore create` first.", err=True)
|
|
89
|
+
raise typer.Exit(1)
|
|
90
|
+
run_cli_command(as_json, lambda: run_ingest(name, target, data_source, as_json))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def register(app: typer.Typer) -> None:
|
|
94
|
+
group("run").command(
|
|
95
|
+
"ingest",
|
|
96
|
+
help="Start a fresh ingestion job for every data source on a deployed knowledge base.",
|
|
97
|
+
)(ingest_command)
|
|
File without changes
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""ARN shape check (port of src/cli/commands/shared/arn-utils.ts)."""
|
|
2
|
+
|
|
3
|
+
_ARN_PART_COUNT = 6
|
|
4
|
+
_ARN_FORMAT = "arn:partition:service:region:account:resource"
|
|
5
|
+
ARN_VALIDATION_MESSAGE = f"Must be a valid ARN ({_ARN_FORMAT})"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def is_valid_arn(value: str) -> bool:
|
|
9
|
+
return value.startswith("arn:") and len(value.split(":")) >= _ARN_PART_COUNT
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
"""Filesystem mount helpers for runtimes (port of src/cli/commands/shared/filesystem-utils.ts).
|
|
2
|
+
|
|
3
|
+
Mount entries are camelCase dicts, ready for agentcore.json:
|
|
4
|
+
``{"accessPointArn": ..., "mountPath": ...}`` and ``{"volumeName": ..., "mountPath": ...}``.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
from collections.abc import Callable, Sequence
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from typing import Any, Literal
|
|
13
|
+
|
|
14
|
+
from agentcore.aws.account import create_aws_client
|
|
15
|
+
from agentcore.schema import EFS_ACCESS_POINT_ARN_PATTERN, S3_FILES_ACCESS_POINT_ARN_PATTERN
|
|
16
|
+
from agentcore.schema._zod import js_regex
|
|
17
|
+
|
|
18
|
+
_BYO_MOUNT_PATH = js_regex(r"^\/mnt\/[a-zA-Z0-9._-]+\/?$")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class MountsResult:
|
|
23
|
+
success: bool
|
|
24
|
+
mounts: list[dict[str, str]] = field(default_factory=list)
|
|
25
|
+
error: str | None = None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class SyncResult:
|
|
30
|
+
success: bool
|
|
31
|
+
error: str | None = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _ok() -> SyncResult:
|
|
35
|
+
return SyncResult(True)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _fail(error: str) -> SyncResult:
|
|
39
|
+
return SyncResult(False, error)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _err_message(err: BaseException) -> str:
|
|
43
|
+
return str(err)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# --- sync format checks -------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def validate_efs_access_point_arn(arn: str) -> Literal[True] | str:
|
|
50
|
+
if not EFS_ACCESS_POINT_ARN_PATTERN.search(arn):
|
|
51
|
+
return (
|
|
52
|
+
f'Invalid EFS access point ARN: "{arn}". Expected '
|
|
53
|
+
"arn:[partition]:elasticfilesystem:{region}:{account}:access-point/fsap-{id}"
|
|
54
|
+
)
|
|
55
|
+
return True
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def validate_s3_files_access_point_arn(arn: str) -> Literal[True] | str:
|
|
59
|
+
if not S3_FILES_ACCESS_POINT_ARN_PATTERN.search(arn):
|
|
60
|
+
return (
|
|
61
|
+
f'Invalid S3 Files access point ARN: "{arn}". Expected '
|
|
62
|
+
"arn:[partition]:s3files:{region}:{account}:file-system/fs-{id}/access-point/fsap-{id}"
|
|
63
|
+
)
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def validate_byo_mount_path(path: str) -> Literal[True] | str:
|
|
68
|
+
"""Validate a BYO filesystem mount path (/mnt/<name>)."""
|
|
69
|
+
if len(path) < 6 or len(path) > 200:
|
|
70
|
+
return f'Invalid mount path: "{path}". Must be between 6 and 200 characters'
|
|
71
|
+
if not _BYO_MOUNT_PATH.search(path):
|
|
72
|
+
return f'Invalid mount path: "{path}". Must be /mnt/<name> with exactly one subdirectory (e.g. /mnt/tools)'
|
|
73
|
+
return True
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def zip_access_point_pairs(
|
|
77
|
+
arns: Sequence[str], mount_paths: Sequence[str], label: Literal["EFS", "S3 Files"]
|
|
78
|
+
) -> MountsResult:
|
|
79
|
+
if len(arns) != len(mount_paths):
|
|
80
|
+
arn_flag = "--efs-access-point-arn" if label == "EFS" else "--s3-access-point-arn"
|
|
81
|
+
path_flag = "--efs-mount-path" if label == "EFS" else "--s3-mount-path"
|
|
82
|
+
return MountsResult(
|
|
83
|
+
False,
|
|
84
|
+
error=(
|
|
85
|
+
f"{label}: {arn_flag} and {path_flag} must be provided in matching pairs "
|
|
86
|
+
f"(got {len(arns)} ARN(s) and {len(mount_paths)} path(s))"
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
return MountsResult(True, [{"accessPointArn": a, "mountPath": p} for a, p in zip(arns, mount_paths, strict=True)])
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def zip_capacity_provider_volume_pairs(volume_names: Sequence[str], mount_paths: Sequence[str]) -> MountsResult:
|
|
93
|
+
if len(volume_names) != len(mount_paths):
|
|
94
|
+
return MountsResult(
|
|
95
|
+
False,
|
|
96
|
+
error=(
|
|
97
|
+
"Capacity provider volumes: --cp-volume-name and --cp-volume-mount-path must be provided in "
|
|
98
|
+
f"matching pairs (got {len(volume_names)} name(s) and {len(mount_paths)} path(s))"
|
|
99
|
+
),
|
|
100
|
+
)
|
|
101
|
+
return MountsResult(
|
|
102
|
+
True, [{"volumeName": n, "mountPath": p} for n, p in zip(volume_names, mount_paths, strict=True)]
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def validate_capacity_provider_volume_mounts(mounts: Sequence[dict[str, str]]) -> SyncResult:
|
|
107
|
+
for mount in mounts:
|
|
108
|
+
name = mount.get("volumeName") or ""
|
|
109
|
+
if not name.strip():
|
|
110
|
+
return _fail("Capacity provider volume name must not be empty")
|
|
111
|
+
path_result = validate_byo_mount_path(mount.get("mountPath", ""))
|
|
112
|
+
if path_result is not True:
|
|
113
|
+
return _fail(path_result)
|
|
114
|
+
return _ok()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def validate_access_point_mounts(
|
|
118
|
+
mounts: Sequence[dict[str, str]], arn_validator: Callable[[str], Literal[True] | str]
|
|
119
|
+
) -> SyncResult:
|
|
120
|
+
for mount in mounts:
|
|
121
|
+
arn_result = arn_validator(mount["accessPointArn"])
|
|
122
|
+
if arn_result is not True:
|
|
123
|
+
return _fail(arn_result)
|
|
124
|
+
path_result = validate_byo_mount_path(mount["mountPath"])
|
|
125
|
+
if path_result is not True:
|
|
126
|
+
return _fail(path_result)
|
|
127
|
+
return _ok()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def build_filesystem_configurations(
|
|
131
|
+
session_storage_mount_path: str | None = None,
|
|
132
|
+
efs_access_points: Sequence[dict[str, str]] | None = None,
|
|
133
|
+
s3_access_points: Sequence[dict[str, str]] | None = None,
|
|
134
|
+
capacity_provider_volumes: Sequence[dict[str, str]] | None = None,
|
|
135
|
+
) -> dict[str, Any]:
|
|
136
|
+
"""``{"filesystemConfigurations": [...]}`` when any mount is present, else ``{}``."""
|
|
137
|
+
|
|
138
|
+
def norm(p: str) -> str:
|
|
139
|
+
return p[:-1] if p.endswith("/") else p
|
|
140
|
+
|
|
141
|
+
fcs: list[dict[str, Any]] = []
|
|
142
|
+
if session_storage_mount_path:
|
|
143
|
+
fcs.append({"sessionStorage": {"mountPath": norm(session_storage_mount_path)}})
|
|
144
|
+
for ap in efs_access_points or []:
|
|
145
|
+
fcs.append({"efsAccessPoint": {**ap, "mountPath": norm(ap["mountPath"])}})
|
|
146
|
+
for ap in s3_access_points or []:
|
|
147
|
+
fcs.append({"s3FilesAccessPoint": {**ap, "mountPath": norm(ap["mountPath"])}})
|
|
148
|
+
for vol in capacity_provider_volumes or []:
|
|
149
|
+
fcs.append({"capacityProviderVolume": {**vol, "mountPath": norm(vol["mountPath"])}})
|
|
150
|
+
return {"filesystemConfigurations": fcs} if fcs else {}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# --- async validators (Level 1-3) ---------------------------------------------------------------
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@dataclass
|
|
157
|
+
class _MountTargetData:
|
|
158
|
+
mount_target_id: str
|
|
159
|
+
subnet_id: str
|
|
160
|
+
vpc_id: str
|
|
161
|
+
availability_zone_id: str | None
|
|
162
|
+
security_group_ids: list[str]
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _region_from_arn(arn: str) -> str:
|
|
166
|
+
return arn.split(":")[3]
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _access_point_id(arn: str) -> str:
|
|
170
|
+
return arn.split("/")[-1]
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _allows_2049(rule: dict[str, Any]) -> bool:
|
|
174
|
+
proto = rule.get("IpProtocol")
|
|
175
|
+
from_port = rule.get("FromPort", 0)
|
|
176
|
+
to_port = rule.get("ToPort", 65535)
|
|
177
|
+
return proto == "-1" or (proto in ("tcp", "6") and from_port <= 2049 and to_port >= 2049)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _from_anywhere(rule: dict[str, Any]) -> bool:
|
|
181
|
+
return any(r.get("CidrIp") == "0.0.0.0/0" for r in rule.get("IpRanges") or []) or any(
|
|
182
|
+
r.get("CidrIpv6") == "::/0" for r in rule.get("Ipv6Ranges") or []
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def validate_efs_access_point_exists(arn: str, region: str) -> SyncResult:
|
|
187
|
+
"""Level 1: the EFS access point exists (DescribeAccessPoints)."""
|
|
188
|
+
try:
|
|
189
|
+
client = create_aws_client("efs", region)
|
|
190
|
+
resp = client.describe_access_points(AccessPointId=_access_point_id(arn))
|
|
191
|
+
if not resp.get("AccessPoints"):
|
|
192
|
+
return _fail(f"EFS access point not found: {arn}")
|
|
193
|
+
return _ok()
|
|
194
|
+
except Exception as exc: # noqa: BLE001
|
|
195
|
+
return _fail(f"EFS access point lookup failed for {arn}: {_err_message(exc)}")
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def validate_s3_files_access_point_exists(arn: str, region: str) -> SyncResult:
|
|
199
|
+
"""Level 1: the S3 Files access point has mount targets (ListMountTargets)."""
|
|
200
|
+
try:
|
|
201
|
+
client = create_aws_client("s3files", region)
|
|
202
|
+
resp = client.list_mount_targets(accessPointId=_access_point_id(arn))
|
|
203
|
+
if not resp.get("mountTargets"):
|
|
204
|
+
return _fail(f"S3 Files access point has no mount targets: {arn}")
|
|
205
|
+
return _ok()
|
|
206
|
+
except Exception as exc: # noqa: BLE001
|
|
207
|
+
return _fail(f"S3 Files access point lookup failed for {arn}: {_err_message(exc)}")
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def validate_security_group_egress_port_2049(security_group_ids: Sequence[str], region: str) -> SyncResult:
|
|
211
|
+
"""Level 1: at least one agent SG allows outbound TCP 2049 (NFS)."""
|
|
212
|
+
try:
|
|
213
|
+
ec2 = create_aws_client("ec2", region)
|
|
214
|
+
resp = ec2.describe_security_groups(GroupIds=list(security_group_ids))
|
|
215
|
+
for sg in resp.get("SecurityGroups") or []:
|
|
216
|
+
for rule in sg.get("IpPermissionsEgress") or []:
|
|
217
|
+
has_destination = _from_anywhere(rule) or len(rule.get("UserIdGroupPairs") or []) > 0
|
|
218
|
+
if _allows_2049(rule) and has_destination:
|
|
219
|
+
return _ok()
|
|
220
|
+
return _fail(
|
|
221
|
+
f"Agent security groups [{', '.join(security_group_ids)}] do not allow outbound TCP 2049 (NFS). "
|
|
222
|
+
"Add an egress rule for port 2049."
|
|
223
|
+
)
|
|
224
|
+
except Exception as exc: # noqa: BLE001
|
|
225
|
+
return _fail(f"Security group egress check failed: {_err_message(exc)}")
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _resolve_efs_data(arn: str, region: str) -> _MountTargetData | str:
|
|
229
|
+
try:
|
|
230
|
+
client = create_aws_client("efs", region)
|
|
231
|
+
mt_resp = client.describe_mount_targets(AccessPointId=_access_point_id(arn))
|
|
232
|
+
mts = mt_resp.get("MountTargets") or []
|
|
233
|
+
mt = mts[0] if mts else {}
|
|
234
|
+
if not mt.get("MountTargetId") or not mt.get("SubnetId") or not mt.get("VpcId"):
|
|
235
|
+
return f"EFS access point {arn} has no available mount targets"
|
|
236
|
+
sg_resp = client.describe_mount_target_security_groups(MountTargetId=mt["MountTargetId"])
|
|
237
|
+
return _MountTargetData(
|
|
238
|
+
mt["MountTargetId"],
|
|
239
|
+
mt["SubnetId"],
|
|
240
|
+
mt["VpcId"],
|
|
241
|
+
mt.get("AvailabilityZoneId"),
|
|
242
|
+
list(sg_resp.get("SecurityGroups") or []),
|
|
243
|
+
)
|
|
244
|
+
except Exception as exc: # noqa: BLE001
|
|
245
|
+
return f"Failed to resolve EFS mount target for {arn}: {_err_message(exc)}"
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _resolve_s3_files_data(arn: str, region: str) -> _MountTargetData | str:
|
|
249
|
+
try:
|
|
250
|
+
client = create_aws_client("s3files", region)
|
|
251
|
+
list_resp = client.list_mount_targets(accessPointId=_access_point_id(arn))
|
|
252
|
+
mts = list_resp.get("mountTargets") or []
|
|
253
|
+
mt = mts[0] if mts else {}
|
|
254
|
+
if not mt.get("mountTargetId"):
|
|
255
|
+
return f"S3 Files access point {arn} has no available mount targets"
|
|
256
|
+
get_resp = client.get_mount_target(mountTargetId=mt["mountTargetId"])
|
|
257
|
+
if not get_resp.get("subnetId") or not get_resp.get("vpcId"):
|
|
258
|
+
return f"S3 Files mount target {mt['mountTargetId']} is missing subnet or VPC info"
|
|
259
|
+
return _MountTargetData(
|
|
260
|
+
mt["mountTargetId"],
|
|
261
|
+
get_resp["subnetId"],
|
|
262
|
+
get_resp["vpcId"],
|
|
263
|
+
get_resp.get("availabilityZoneId"),
|
|
264
|
+
list(get_resp.get("securityGroups") or []),
|
|
265
|
+
)
|
|
266
|
+
except Exception as exc: # noqa: BLE001
|
|
267
|
+
return f"Failed to resolve S3 Files mount target for {arn}: {_err_message(exc)}"
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _validate_mount_target_in_vpc_and_az(
|
|
271
|
+
data: _MountTargetData, agent_subnet_ids: Sequence[str], agent_vpc_id: str, region: str, label: str
|
|
272
|
+
) -> SyncResult:
|
|
273
|
+
"""Level 2: mount target in the agent VPC, with an agent subnet in its AZ."""
|
|
274
|
+
if data.vpc_id != agent_vpc_id:
|
|
275
|
+
return _fail(f"{label} mount target VPC ({data.vpc_id}) does not match agent VPC ({agent_vpc_id})")
|
|
276
|
+
if not data.availability_zone_id:
|
|
277
|
+
return _ok()
|
|
278
|
+
try:
|
|
279
|
+
ec2 = create_aws_client("ec2", region)
|
|
280
|
+
resp = ec2.describe_subnets(SubnetIds=list(agent_subnet_ids))
|
|
281
|
+
agent_az_ids = {s.get("AvailabilityZoneId") for s in resp.get("Subnets") or [] if s.get("AvailabilityZoneId")}
|
|
282
|
+
if data.availability_zone_id not in agent_az_ids:
|
|
283
|
+
az = data.availability_zone_id
|
|
284
|
+
return _fail(
|
|
285
|
+
f"{label} mount target is in AZ {az} but no agent subnet is in that AZ. "
|
|
286
|
+
f"Add a subnet in AZ {az} to your agent configuration."
|
|
287
|
+
)
|
|
288
|
+
except Exception as exc: # noqa: BLE001
|
|
289
|
+
return _fail(f"Subnet AZ validation failed for {label}: {_err_message(exc)}")
|
|
290
|
+
return _ok()
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def _validate_mount_target_inbound_from_agent_sg(
|
|
294
|
+
mount_sg_ids: Sequence[str], agent_sg_ids: Sequence[str], region: str, label: str
|
|
295
|
+
) -> SyncResult:
|
|
296
|
+
"""Level 3: mount target SGs allow inbound TCP 2049 from an agent SG."""
|
|
297
|
+
if not mount_sg_ids:
|
|
298
|
+
return _ok()
|
|
299
|
+
try:
|
|
300
|
+
ec2 = create_aws_client("ec2", region)
|
|
301
|
+
resp = ec2.describe_security_groups(GroupIds=list(mount_sg_ids))
|
|
302
|
+
agent_set = set(agent_sg_ids)
|
|
303
|
+
for sg in resp.get("SecurityGroups") or []:
|
|
304
|
+
for rule in sg.get("IpPermissions") or []:
|
|
305
|
+
if not _allows_2049(rule):
|
|
306
|
+
continue
|
|
307
|
+
from_agent = any(p.get("GroupId") in agent_set for p in rule.get("UserIdGroupPairs") or [])
|
|
308
|
+
if from_agent or _from_anywhere(rule):
|
|
309
|
+
return _ok()
|
|
310
|
+
return _fail(
|
|
311
|
+
f"{label} mount target security groups [{', '.join(mount_sg_ids)}] do not allow inbound TCP 2049 "
|
|
312
|
+
f"from agent security groups [{', '.join(agent_sg_ids)}]. Add an inbound rule for port 2049 from the "
|
|
313
|
+
"agent SG."
|
|
314
|
+
)
|
|
315
|
+
except Exception as exc: # noqa: BLE001
|
|
316
|
+
return _fail(f"Mount target inbound SG check failed for {label}: {_err_message(exc)}")
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def validate_filesystem_mounts_configuration(
|
|
320
|
+
*,
|
|
321
|
+
efs_mounts: Sequence[dict[str, str]],
|
|
322
|
+
s3_files_mounts: Sequence[dict[str, str]],
|
|
323
|
+
region: str,
|
|
324
|
+
agent_vpc_id: str | None = None,
|
|
325
|
+
agent_subnet_ids: Sequence[str] | None = None,
|
|
326
|
+
agent_security_group_ids: Sequence[str] | None = None,
|
|
327
|
+
skip_topology_checks: bool = False,
|
|
328
|
+
skip_inbound_sg_checks: bool = False,
|
|
329
|
+
) -> SyncResult:
|
|
330
|
+
"""Levels 1-3 of filesystem validation; returns the first error. Levels lacking data are skipped."""
|
|
331
|
+
if agent_security_group_ids and (efs_mounts or s3_files_mounts):
|
|
332
|
+
egress = validate_security_group_egress_port_2049(agent_security_group_ids, region)
|
|
333
|
+
if not egress.success:
|
|
334
|
+
return egress
|
|
335
|
+
|
|
336
|
+
checks: list[tuple[Sequence[dict[str, str]], str, Callable[[str, str], SyncResult], Callable[..., Any]]] = [
|
|
337
|
+
(efs_mounts, "EFS", validate_efs_access_point_exists, _resolve_efs_data),
|
|
338
|
+
(s3_files_mounts, "S3 Files", validate_s3_files_access_point_exists, _resolve_s3_files_data),
|
|
339
|
+
]
|
|
340
|
+
for mounts, label, exists, resolve in checks:
|
|
341
|
+
for mount in mounts:
|
|
342
|
+
arn = mount["accessPointArn"]
|
|
343
|
+
mount_region = _region_from_arn(arn)
|
|
344
|
+
result = exists(arn, mount_region)
|
|
345
|
+
if not result.success:
|
|
346
|
+
return result
|
|
347
|
+
if not skip_topology_checks and agent_vpc_id and agent_subnet_ids:
|
|
348
|
+
data = resolve(arn, mount_region)
|
|
349
|
+
if isinstance(data, str):
|
|
350
|
+
return _fail(data)
|
|
351
|
+
vpc_result = _validate_mount_target_in_vpc_and_az(data, agent_subnet_ids, agent_vpc_id, region, label)
|
|
352
|
+
if not vpc_result.success:
|
|
353
|
+
return vpc_result
|
|
354
|
+
if not skip_inbound_sg_checks and agent_security_group_ids:
|
|
355
|
+
# Mount target SGs live in the mount's region, not the agent region.
|
|
356
|
+
sg_result = _validate_mount_target_inbound_from_agent_sg(
|
|
357
|
+
data.security_group_ids, agent_security_group_ids, mount_region, label
|
|
358
|
+
)
|
|
359
|
+
if not sg_result.success:
|
|
360
|
+
return sg_result
|
|
361
|
+
return _ok()
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def resolve_and_validate_filesystem_mounts(
|
|
365
|
+
options: dict[str, Any],
|
|
366
|
+
parse_comma_separated_list: Callable[[str | None], list[str] | None],
|
|
367
|
+
) -> dict[str, list[dict[str, str]]]:
|
|
368
|
+
"""Zip CLI flag pairs, resolve the agent VPC from subnets and run Levels 1-3. Raises on failure."""
|
|
369
|
+
efs = zip_access_point_pairs(options.get("efsAccessPointArn") or [], options.get("efsMountPath") or [], "EFS")
|
|
370
|
+
if not efs.success:
|
|
371
|
+
raise Exception(efs.error)
|
|
372
|
+
s3 = zip_access_point_pairs(options.get("s3AccessPointArn") or [], options.get("s3MountPath") or [], "S3 Files")
|
|
373
|
+
if not s3.success:
|
|
374
|
+
raise Exception(s3.error)
|
|
375
|
+
|
|
376
|
+
if efs.mounts or s3.mounts:
|
|
377
|
+
region = (
|
|
378
|
+
options.get("region") or os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION") or "us-east-1"
|
|
379
|
+
)
|
|
380
|
+
subnets = parse_comma_separated_list(options.get("subnets"))
|
|
381
|
+
security_groups = parse_comma_separated_list(options.get("securityGroups"))
|
|
382
|
+
agent_vpc_id: str | None = None
|
|
383
|
+
if subnets:
|
|
384
|
+
try:
|
|
385
|
+
ec2 = create_aws_client("ec2", region)
|
|
386
|
+
resp = ec2.describe_subnets(SubnetIds=list(subnets))
|
|
387
|
+
found = resp.get("Subnets") or []
|
|
388
|
+
agent_vpc_id = found[0].get("VpcId") if found else None
|
|
389
|
+
except Exception: # noqa: BLE001 - Level 2 is skipped when the VPC can't be resolved
|
|
390
|
+
pass
|
|
391
|
+
result = validate_filesystem_mounts_configuration(
|
|
392
|
+
efs_mounts=efs.mounts,
|
|
393
|
+
s3_files_mounts=s3.mounts,
|
|
394
|
+
agent_vpc_id=agent_vpc_id,
|
|
395
|
+
agent_subnet_ids=subnets,
|
|
396
|
+
agent_security_group_ids=security_groups,
|
|
397
|
+
region=region,
|
|
398
|
+
)
|
|
399
|
+
if not result.success:
|
|
400
|
+
raise Exception(result.error)
|
|
401
|
+
|
|
402
|
+
return {"efsMounts": efs.mounts, "s3Mounts": s3.mounts}
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
__all__ = [
|
|
406
|
+
"MountsResult",
|
|
407
|
+
"SyncResult",
|
|
408
|
+
"build_filesystem_configurations",
|
|
409
|
+
"resolve_and_validate_filesystem_mounts",
|
|
410
|
+
"validate_access_point_mounts",
|
|
411
|
+
"validate_byo_mount_path",
|
|
412
|
+
"validate_capacity_provider_volume_mounts",
|
|
413
|
+
"validate_efs_access_point_arn",
|
|
414
|
+
"validate_efs_access_point_exists",
|
|
415
|
+
"validate_filesystem_mounts_configuration",
|
|
416
|
+
"validate_s3_files_access_point_arn",
|
|
417
|
+
"validate_s3_files_access_point_exists",
|
|
418
|
+
"validate_security_group_egress_port_2049",
|
|
419
|
+
"zip_access_point_pairs",
|
|
420
|
+
"zip_capacity_provider_volume_pairs",
|
|
421
|
+
]
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Request header helpers (port of src/cli/commands/shared/header-utils.ts)."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
|
|
6
|
+
from agentcore.schema.schemas.agent_env import (
|
|
7
|
+
HEADER_ALLOWLIST_PREFIX,
|
|
8
|
+
HEADER_NAME_PATTERN,
|
|
9
|
+
MAX_HEADER_ALLOWLIST_SIZE,
|
|
10
|
+
check_allowlist_header,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"HEADER_ALLOWLIST_PREFIX",
|
|
15
|
+
"HEADER_NAME_PATTERN",
|
|
16
|
+
"MAX_HEADER_ALLOWLIST_SIZE",
|
|
17
|
+
"HeaderValidationResult",
|
|
18
|
+
"normalize_header_name",
|
|
19
|
+
"parse_and_normalize_headers",
|
|
20
|
+
"parse_header_flag",
|
|
21
|
+
"parse_header_flags",
|
|
22
|
+
"validate_header_allowlist",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class HeaderValidationResult:
|
|
28
|
+
success: bool
|
|
29
|
+
error: str | None = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def normalize_header_name(value: str) -> str:
|
|
33
|
+
if value.lower() == "authorization":
|
|
34
|
+
return "Authorization"
|
|
35
|
+
if value.lower().startswith(HEADER_ALLOWLIST_PREFIX.lower()):
|
|
36
|
+
return f"{HEADER_ALLOWLIST_PREFIX}{value[len(HEADER_ALLOWLIST_PREFIX) :]}"
|
|
37
|
+
if re.match(r"^x-", value, re.IGNORECASE):
|
|
38
|
+
return value
|
|
39
|
+
return f"{HEADER_ALLOWLIST_PREFIX}{value}"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def parse_and_normalize_headers(value: str) -> list[str]:
|
|
43
|
+
"""Split, normalize and de-duplicate (case-insensitively) a comma-separated header list."""
|
|
44
|
+
seen: set[str] = set()
|
|
45
|
+
result: list[str] = []
|
|
46
|
+
for header in (normalize_header_name(s.strip()) for s in value.split(",") if s.strip()):
|
|
47
|
+
if header.lower() not in seen:
|
|
48
|
+
seen.add(header.lower())
|
|
49
|
+
result.append(header)
|
|
50
|
+
return result
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def validate_header_allowlist(value: str) -> HeaderValidationResult:
|
|
54
|
+
trimmed = value.strip()
|
|
55
|
+
if trimmed == "":
|
|
56
|
+
return HeaderValidationResult(True)
|
|
57
|
+
names = [s.strip() for s in trimmed.split(",") if s.strip()]
|
|
58
|
+
for name in names:
|
|
59
|
+
error = check_allowlist_header(name)
|
|
60
|
+
if error:
|
|
61
|
+
return HeaderValidationResult(False, error)
|
|
62
|
+
if len(names) > MAX_HEADER_ALLOWLIST_SIZE:
|
|
63
|
+
return HeaderValidationResult(
|
|
64
|
+
False, f"Header allowlist cannot exceed {MAX_HEADER_ALLOWLIST_SIZE} headers. Provided: {len(names)}"
|
|
65
|
+
)
|
|
66
|
+
return HeaderValidationResult(True)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def parse_header_flag(raw: str) -> tuple[str, str] | None:
|
|
70
|
+
"""Parse "Key: Value" into (normalized name, value); None when malformed."""
|
|
71
|
+
idx = raw.find(":")
|
|
72
|
+
if idx < 1:
|
|
73
|
+
return None
|
|
74
|
+
name = raw[:idx].strip()
|
|
75
|
+
if not name:
|
|
76
|
+
return None
|
|
77
|
+
return normalize_header_name(name), raw[idx + 1 :].strip()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def parse_header_flags(raw_headers: list[str]) -> dict[str, str]:
|
|
81
|
+
result: dict[str, str] = {}
|
|
82
|
+
for raw in raw_headers:
|
|
83
|
+
parsed = parse_header_flag(raw)
|
|
84
|
+
if parsed is None:
|
|
85
|
+
raise ValueError(f'Invalid header format: "{raw}". Expected "Header-Name: value" or "Header-Name:value".')
|
|
86
|
+
result[parsed[0]] = parsed[1]
|
|
87
|
+
return result
|