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,150 @@
|
|
|
1
|
+
"""Validate and submit feedback (port of submit-feedback.ts)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import base64
|
|
6
|
+
import hashlib
|
|
7
|
+
import os
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import Any
|
|
10
|
+
from urllib.parse import unquote, urlsplit
|
|
11
|
+
|
|
12
|
+
from agentcore.lib.errors.types import ValidationError
|
|
13
|
+
from agentcore.operations.feedback import aperture_client
|
|
14
|
+
from agentcore.operations.feedback.build_payload import (
|
|
15
|
+
CLI_VERSION,
|
|
16
|
+
FeedbackMode,
|
|
17
|
+
build_feedback_payload,
|
|
18
|
+
build_user_agent,
|
|
19
|
+
)
|
|
20
|
+
from agentcore.operations.feedback.constants import (
|
|
21
|
+
ALLOWED_SCREENSHOT_EXTENSIONS,
|
|
22
|
+
APERTURE_FORM_CATEGORY,
|
|
23
|
+
APERTURE_FORM_NAME,
|
|
24
|
+
APERTURE_FORM_VERSION,
|
|
25
|
+
MAX_SCREENSHOT_BYTES,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
FEEDBACK_MESSAGE_MAX_LENGTH = 1000
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class FeedbackValidationError(ValidationError):
|
|
32
|
+
"""User input the feedback command refuses to send."""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def validate_feedback_message(message: str) -> str | None:
|
|
36
|
+
trimmed = message.strip()
|
|
37
|
+
if not trimmed:
|
|
38
|
+
return "Feedback message cannot be empty."
|
|
39
|
+
if len(trimmed) > FEEDBACK_MESSAGE_MAX_LENGTH:
|
|
40
|
+
return f"Feedback message must be {FEEDBACK_MESSAGE_MAX_LENGTH} characters or fewer."
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class LoadedScreenshot:
|
|
46
|
+
data: bytes
|
|
47
|
+
file_name: str
|
|
48
|
+
content_type: str
|
|
49
|
+
sha256_base64: str
|
|
50
|
+
size: int
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _expand_tilde(path: str) -> str:
|
|
54
|
+
if path == "~":
|
|
55
|
+
return os.path.expanduser("~")
|
|
56
|
+
if path.startswith("~/"):
|
|
57
|
+
return os.path.join(os.path.expanduser("~"), path[2:])
|
|
58
|
+
return path
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _os_error_reason(exc: OSError) -> str:
|
|
62
|
+
"""Node-style fs error text (``ENOENT: no such file or directory, stat '<path>'``)."""
|
|
63
|
+
import errno
|
|
64
|
+
|
|
65
|
+
code = errno.errorcode.get(exc.errno or 0, "EIO")
|
|
66
|
+
return f"{code}: {(exc.strerror or str(exc)).lower()}, stat '{exc.filename}'"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def load_and_validate_screenshot(raw_path: str) -> LoadedScreenshot:
|
|
70
|
+
path = _expand_tilde(raw_path)
|
|
71
|
+
try:
|
|
72
|
+
st = os.stat(path)
|
|
73
|
+
except OSError as exc:
|
|
74
|
+
raise FeedbackValidationError(f"Could not read screenshot at {path}: {_os_error_reason(exc)}") from None
|
|
75
|
+
import stat as stat_mod
|
|
76
|
+
|
|
77
|
+
if stat_mod.S_ISDIR(st.st_mode):
|
|
78
|
+
raise FeedbackValidationError(f"Screenshot path is a directory, not a file: {path}")
|
|
79
|
+
if not stat_mod.S_ISREG(st.st_mode):
|
|
80
|
+
raise FeedbackValidationError(f"Screenshot path is not a regular file: {path}")
|
|
81
|
+
ext = os.path.splitext(path)[1].lower()
|
|
82
|
+
if ext not in ALLOWED_SCREENSHOT_EXTENSIONS:
|
|
83
|
+
raise FeedbackValidationError(f"Screenshot must be one of: {', '.join(ALLOWED_SCREENSHOT_EXTENSIONS)}.")
|
|
84
|
+
try:
|
|
85
|
+
with open(path, "rb") as fh:
|
|
86
|
+
data = fh.read()
|
|
87
|
+
except OSError as exc:
|
|
88
|
+
raise FeedbackValidationError(f"Could not read screenshot at {path}: {_os_error_reason(exc)}") from None
|
|
89
|
+
if len(data) > MAX_SCREENSHOT_BYTES:
|
|
90
|
+
raise FeedbackValidationError(
|
|
91
|
+
f"Screenshot is {len(data) / (1024 * 1024):.1f} MB; maximum allowed size is 100 MB."
|
|
92
|
+
)
|
|
93
|
+
return LoadedScreenshot(
|
|
94
|
+
data=data,
|
|
95
|
+
file_name=os.path.basename(path),
|
|
96
|
+
content_type="image/png" if ext == ".png" else "image/jpeg",
|
|
97
|
+
sha256_base64=base64.b64encode(hashlib.sha256(data).digest()).decode(),
|
|
98
|
+
size=len(data),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def validate_screenshot_path(path: str) -> str | None:
|
|
103
|
+
try:
|
|
104
|
+
load_and_validate_screenshot(path)
|
|
105
|
+
return None
|
|
106
|
+
except FeedbackValidationError as exc:
|
|
107
|
+
return str(exc)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _object_key_from_presigned_url(url: str) -> str:
|
|
111
|
+
return unquote(urlsplit(url).path.lstrip("/"))
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def submit_feedback(message: str, screenshot: str | None = None, mode: FeedbackMode = "cli") -> dict[str, Any]:
|
|
115
|
+
"""Returns ``{"id", "timestamp", "reference"}``."""
|
|
116
|
+
error = validate_feedback_message(message)
|
|
117
|
+
if error:
|
|
118
|
+
raise FeedbackValidationError(error)
|
|
119
|
+
|
|
120
|
+
user_agent = build_user_agent(CLI_VERSION)
|
|
121
|
+
reference: str | None = None
|
|
122
|
+
if screenshot:
|
|
123
|
+
file = load_and_validate_screenshot(screenshot)
|
|
124
|
+
presigned = aperture_client.fetch_presigned_url(
|
|
125
|
+
{
|
|
126
|
+
"category": APERTURE_FORM_CATEGORY,
|
|
127
|
+
"name": APERTURE_FORM_NAME,
|
|
128
|
+
"version": APERTURE_FORM_VERSION,
|
|
129
|
+
"fileName": file.file_name,
|
|
130
|
+
"fileSize": file.size,
|
|
131
|
+
"uploadFileSHA256": file.sha256_base64,
|
|
132
|
+
},
|
|
133
|
+
user_agent,
|
|
134
|
+
)
|
|
135
|
+
aperture_client.upload_file_to_s3(presigned, file.data, file.content_type, file.sha256_base64, user_agent)
|
|
136
|
+
reference = _object_key_from_presigned_url(presigned)
|
|
137
|
+
|
|
138
|
+
payload = build_feedback_payload(message.strip(), screenshot_reference=reference, mode=mode)
|
|
139
|
+
response = aperture_client.submit_form(payload, user_agent)
|
|
140
|
+
return {"id": response.get("id"), "timestamp": response.get("timestamp"), "reference": response.get("reference")}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
__all__ = [
|
|
144
|
+
"FEEDBACK_MESSAGE_MAX_LENGTH",
|
|
145
|
+
"FeedbackValidationError",
|
|
146
|
+
"load_and_validate_screenshot",
|
|
147
|
+
"submit_feedback",
|
|
148
|
+
"validate_feedback_message",
|
|
149
|
+
"validate_screenshot_path",
|
|
150
|
+
]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Access info / OAuth tokens for deployed resources (port of src/cli/operations/fetch-access)."""
|
|
2
|
+
|
|
3
|
+
from agentcore.operations.fetch_access.fetch_gateway_token import fetch_gateway_token
|
|
4
|
+
from agentcore.operations.fetch_access.fetch_harness_token import can_fetch_harness_token, fetch_harness_token
|
|
5
|
+
from agentcore.operations.fetch_access.fetch_runtime_token import can_fetch_runtime_token, fetch_runtime_token
|
|
6
|
+
from agentcore.operations.fetch_access.list_agents import list_agents
|
|
7
|
+
from agentcore.operations.fetch_access.list_gateways import list_gateways
|
|
8
|
+
from agentcore.operations.fetch_access.list_harnesses import list_harnesses
|
|
9
|
+
from agentcore.operations.fetch_access.oauth_token import OAuthTokenResult, fetch_oauth_token
|
|
10
|
+
from agentcore.operations.fetch_access.types import (
|
|
11
|
+
AgentInfo,
|
|
12
|
+
FetchResourceType,
|
|
13
|
+
GatewayInfo,
|
|
14
|
+
HarnessInfo,
|
|
15
|
+
ResourceInfo,
|
|
16
|
+
TokenFetchResult,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"AgentInfo",
|
|
21
|
+
"FetchResourceType",
|
|
22
|
+
"GatewayInfo",
|
|
23
|
+
"HarnessInfo",
|
|
24
|
+
"OAuthTokenResult",
|
|
25
|
+
"ResourceInfo",
|
|
26
|
+
"TokenFetchResult",
|
|
27
|
+
"can_fetch_harness_token",
|
|
28
|
+
"can_fetch_runtime_token",
|
|
29
|
+
"fetch_gateway_token",
|
|
30
|
+
"fetch_harness_token",
|
|
31
|
+
"fetch_oauth_token",
|
|
32
|
+
"fetch_runtime_token",
|
|
33
|
+
"list_agents",
|
|
34
|
+
"list_gateways",
|
|
35
|
+
"list_harnesses",
|
|
36
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Shared deployed-target lookup for list_agents/list_gateways/list_harnesses."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from agentcore.lib.schemas.io.config_io import ConfigIO
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _target_resources(config_io: ConfigIO, deploy_target: str | None) -> tuple[Any, Any] | None:
|
|
9
|
+
deployed_state = config_io.read_deployed_state()
|
|
10
|
+
project_spec = config_io.read_project_spec()
|
|
11
|
+
targets = deployed_state.targets or {}
|
|
12
|
+
if not targets:
|
|
13
|
+
return None
|
|
14
|
+
target = targets.get(deploy_target or next(iter(targets)))
|
|
15
|
+
if target is None:
|
|
16
|
+
return None
|
|
17
|
+
return project_spec, target.resources
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Port of src/cli/operations/fetch-access/fetch-gateway-token.ts."""
|
|
2
|
+
|
|
3
|
+
from agentcore.lib.schemas.io.config_io import ConfigIO
|
|
4
|
+
from agentcore.operations.fetch_access import oauth_token
|
|
5
|
+
from agentcore.operations.fetch_access.types import TokenFetchResult
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def fetch_gateway_token(
|
|
9
|
+
gateway_name: str,
|
|
10
|
+
*,
|
|
11
|
+
config_io: ConfigIO | None = None,
|
|
12
|
+
deploy_target: str | None = None,
|
|
13
|
+
identity_name: str | None = None,
|
|
14
|
+
) -> TokenFetchResult:
|
|
15
|
+
config_io = config_io or ConfigIO()
|
|
16
|
+
deployed_state = config_io.read_deployed_state()
|
|
17
|
+
project_spec = config_io.read_project_spec()
|
|
18
|
+
|
|
19
|
+
target_names = list(deployed_state.targets or {})
|
|
20
|
+
if not target_names:
|
|
21
|
+
raise RuntimeError("No deployed targets found. Run `agentcore deploy` first.")
|
|
22
|
+
target_name = deploy_target or target_names[0]
|
|
23
|
+
target = deployed_state.targets.get(target_name)
|
|
24
|
+
if target is None:
|
|
25
|
+
raise RuntimeError(f"Deployment target '{target_name}' not found. Available targets: {', '.join(target_names)}")
|
|
26
|
+
|
|
27
|
+
gateways = project_spec.agent_core_gateways or []
|
|
28
|
+
gateway_spec = next((g for g in gateways if g.name == gateway_name), None)
|
|
29
|
+
if gateway_spec is None:
|
|
30
|
+
available = ", ".join(g.name for g in gateways) or "none"
|
|
31
|
+
raise RuntimeError(f"Gateway '{gateway_name}' not found in MCP configuration. Available gateways: {available}")
|
|
32
|
+
|
|
33
|
+
resources = target.resources
|
|
34
|
+
deployed_gateway = ((resources.gateways if resources else None) or {}).get(gateway_name)
|
|
35
|
+
if deployed_gateway is None and resources and resources.mcp:
|
|
36
|
+
deployed_gateway = (resources.mcp.gateways or {}).get(gateway_name)
|
|
37
|
+
if not (deployed_gateway and deployed_gateway.gateway_url):
|
|
38
|
+
raise RuntimeError(
|
|
39
|
+
f"Gateway '{gateway_name}' does not have a deployed URL. Run `agentcore deploy` to deploy the gateway."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
gateway_url = deployed_gateway.gateway_url
|
|
43
|
+
auth_type = gateway_spec.authorizer_type
|
|
44
|
+
if auth_type == "NONE":
|
|
45
|
+
return {
|
|
46
|
+
"url": gateway_url,
|
|
47
|
+
"authType": "NONE",
|
|
48
|
+
"message": "No authentication required. Send requests directly to the URL.",
|
|
49
|
+
}
|
|
50
|
+
if auth_type == "AWS_IAM":
|
|
51
|
+
return {
|
|
52
|
+
"url": gateway_url,
|
|
53
|
+
"authType": "AWS_IAM",
|
|
54
|
+
"message": "This gateway uses AWS IAM auth. Sign requests with SigV4 using your IAM credentials.",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
config = gateway_spec.authorizer_configuration
|
|
58
|
+
jwt_config = config.custom_jwt_authorizer if config else None
|
|
59
|
+
if jwt_config is None:
|
|
60
|
+
raise RuntimeError(
|
|
61
|
+
f"Gateway '{gateway_name}' is configured as CUSTOM_JWT but has no customJwtAuthorizer configuration."
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
result = oauth_token.fetch_oauth_token(
|
|
65
|
+
resource_name=gateway_name,
|
|
66
|
+
jwt_config=jwt_config,
|
|
67
|
+
deployed_state=deployed_state,
|
|
68
|
+
target_name=target_name,
|
|
69
|
+
credentials=project_spec.credentials or [],
|
|
70
|
+
credential_name=identity_name,
|
|
71
|
+
)
|
|
72
|
+
out: TokenFetchResult = {"url": gateway_url, "authType": "CUSTOM_JWT", "token": result.token}
|
|
73
|
+
if result.expires_in is not None:
|
|
74
|
+
out["expiresIn"] = result.expires_in
|
|
75
|
+
return out
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Port of src/cli/operations/fetch-access/fetch-harness-token.ts."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from agentcore.lib.schemas.io.config_io import ConfigIO
|
|
7
|
+
from agentcore.lib.utils.env import read_env_file
|
|
8
|
+
from agentcore.operations.fetch_access import oauth_token
|
|
9
|
+
from agentcore.operations.fetch_access.oauth_token import OAuthTokenResult
|
|
10
|
+
from agentcore.primitives.credential_utils import (
|
|
11
|
+
compute_default_credential_env_var_name,
|
|
12
|
+
compute_managed_oauth_credential_name,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def can_fetch_harness_token(harness_name: str, *, config_io: ConfigIO | None = None) -> bool:
|
|
17
|
+
"""True when a CUSTOM_JWT harness has its managed OAuth credential and client secret available."""
|
|
18
|
+
try:
|
|
19
|
+
config_io = config_io or ConfigIO()
|
|
20
|
+
spec = config_io.read_harness_spec(harness_name)
|
|
21
|
+
if spec.authorizer_type != "CUSTOM_JWT":
|
|
22
|
+
return False
|
|
23
|
+
if not (spec.authorizer_configuration and spec.authorizer_configuration.custom_jwt_authorizer):
|
|
24
|
+
return False
|
|
25
|
+
project_spec = config_io.read_project_spec()
|
|
26
|
+
cred_name = compute_managed_oauth_credential_name(harness_name)
|
|
27
|
+
if not any(
|
|
28
|
+
c.authorizer_type == "OAuthCredentialProvider" and c.name == cred_name
|
|
29
|
+
for c in project_spec.credentials or []
|
|
30
|
+
):
|
|
31
|
+
return False
|
|
32
|
+
prefix = compute_default_credential_env_var_name(cred_name)
|
|
33
|
+
return bool(read_env_file().get(f"{prefix}_CLIENT_SECRET"))
|
|
34
|
+
except Exception as exc: # noqa: BLE001 - "cannot fetch", as upstream
|
|
35
|
+
if os.environ.get("DEBUG"):
|
|
36
|
+
print("[canFetchHarnessToken]", exc, file=sys.stderr)
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def fetch_harness_token(
|
|
41
|
+
harness_name: str,
|
|
42
|
+
*,
|
|
43
|
+
config_io: ConfigIO | None = None,
|
|
44
|
+
deploy_target: str | None = None,
|
|
45
|
+
identity_name: str | None = None,
|
|
46
|
+
) -> OAuthTokenResult:
|
|
47
|
+
config_io = config_io or ConfigIO()
|
|
48
|
+
deployed_state = config_io.read_deployed_state()
|
|
49
|
+
project_spec = config_io.read_project_spec()
|
|
50
|
+
spec = config_io.read_harness_spec(harness_name)
|
|
51
|
+
|
|
52
|
+
target_names = list(deployed_state.targets or {})
|
|
53
|
+
if not target_names:
|
|
54
|
+
raise RuntimeError("No deployed targets found. Run `agentcore deploy` first.")
|
|
55
|
+
target_name = deploy_target or target_names[0]
|
|
56
|
+
|
|
57
|
+
if spec.authorizer_type != "CUSTOM_JWT":
|
|
58
|
+
raise RuntimeError(f"Harness '{harness_name}' uses {spec.authorizer_type or 'AWS_IAM'} auth, not CUSTOM_JWT.")
|
|
59
|
+
config = spec.authorizer_configuration
|
|
60
|
+
jwt_config = config.custom_jwt_authorizer if config else None
|
|
61
|
+
if jwt_config is None:
|
|
62
|
+
raise RuntimeError(
|
|
63
|
+
f"Harness '{harness_name}' is configured as CUSTOM_JWT but has no customJwtAuthorizer configuration."
|
|
64
|
+
)
|
|
65
|
+
return oauth_token.fetch_oauth_token(
|
|
66
|
+
resource_name=harness_name,
|
|
67
|
+
jwt_config=jwt_config,
|
|
68
|
+
deployed_state=deployed_state,
|
|
69
|
+
target_name=target_name,
|
|
70
|
+
credentials=project_spec.credentials or [],
|
|
71
|
+
credential_name=identity_name,
|
|
72
|
+
)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Port of src/cli/operations/fetch-access/fetch-runtime-token.ts."""
|
|
2
|
+
|
|
3
|
+
from agentcore.lib.schemas.io.config_io import ConfigIO
|
|
4
|
+
from agentcore.lib.utils.env import read_env_file
|
|
5
|
+
from agentcore.operations.fetch_access import oauth_token
|
|
6
|
+
from agentcore.operations.fetch_access.oauth_token import OAuthTokenResult
|
|
7
|
+
from agentcore.primitives.credential_utils import (
|
|
8
|
+
compute_default_credential_env_var_name,
|
|
9
|
+
compute_managed_oauth_credential_name,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def can_fetch_runtime_token(
|
|
14
|
+
agent_name: str, *, config_io: ConfigIO | None = None, identity_name: str | None = None
|
|
15
|
+
) -> bool:
|
|
16
|
+
"""True when a CUSTOM_JWT agent has its managed OAuth credential and client secret available."""
|
|
17
|
+
try:
|
|
18
|
+
config_io = config_io or ConfigIO()
|
|
19
|
+
project_spec = config_io.read_project_spec()
|
|
20
|
+
agent = next((a for a in project_spec.runtimes or [] if a.name == agent_name), None)
|
|
21
|
+
if agent is None or agent.authorizer_type != "CUSTOM_JWT":
|
|
22
|
+
return False
|
|
23
|
+
if not (agent.authorizer_configuration and agent.authorizer_configuration.custom_jwt_authorizer):
|
|
24
|
+
return False
|
|
25
|
+
cred_name = identity_name or compute_managed_oauth_credential_name(agent_name)
|
|
26
|
+
if not any(
|
|
27
|
+
c.authorizer_type == "OAuthCredentialProvider" and c.name == cred_name
|
|
28
|
+
for c in project_spec.credentials or []
|
|
29
|
+
):
|
|
30
|
+
return False
|
|
31
|
+
prefix = compute_default_credential_env_var_name(cred_name)
|
|
32
|
+
return bool(read_env_file().get(f"{prefix}_CLIENT_SECRET"))
|
|
33
|
+
except Exception: # noqa: BLE001 - "cannot fetch", as upstream
|
|
34
|
+
return False
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def fetch_runtime_token(
|
|
38
|
+
agent_name: str,
|
|
39
|
+
*,
|
|
40
|
+
config_io: ConfigIO | None = None,
|
|
41
|
+
deploy_target: str | None = None,
|
|
42
|
+
identity_name: str | None = None,
|
|
43
|
+
) -> OAuthTokenResult:
|
|
44
|
+
config_io = config_io or ConfigIO()
|
|
45
|
+
deployed_state = config_io.read_deployed_state()
|
|
46
|
+
project_spec = config_io.read_project_spec()
|
|
47
|
+
|
|
48
|
+
target_names = list(deployed_state.targets or {})
|
|
49
|
+
if not target_names:
|
|
50
|
+
raise RuntimeError("No deployed targets found. Run `agentcore deploy` first.")
|
|
51
|
+
target_name = deploy_target or target_names[0]
|
|
52
|
+
|
|
53
|
+
runtimes = project_spec.runtimes or []
|
|
54
|
+
agent = next((a for a in runtimes if a.name == agent_name), None)
|
|
55
|
+
if agent is None:
|
|
56
|
+
available = ", ".join(a.name for a in runtimes) or "none"
|
|
57
|
+
raise RuntimeError(f"Agent '{agent_name}' not found in project. Available agents: {available}")
|
|
58
|
+
if agent.authorizer_type != "CUSTOM_JWT":
|
|
59
|
+
raise RuntimeError(
|
|
60
|
+
f"Agent '{agent_name}' uses {agent.authorizer_type or 'AWS_IAM'} auth, not CUSTOM_JWT. "
|
|
61
|
+
"Token fetch is only needed for CUSTOM_JWT agents."
|
|
62
|
+
)
|
|
63
|
+
config = agent.authorizer_configuration
|
|
64
|
+
jwt_config = config.custom_jwt_authorizer if config else None
|
|
65
|
+
if jwt_config is None:
|
|
66
|
+
raise RuntimeError(
|
|
67
|
+
f"Agent '{agent_name}' is configured as CUSTOM_JWT but has no customJwtAuthorizer configuration."
|
|
68
|
+
)
|
|
69
|
+
return oauth_token.fetch_oauth_token(
|
|
70
|
+
resource_name=agent_name,
|
|
71
|
+
jwt_config=jwt_config,
|
|
72
|
+
deployed_state=deployed_state,
|
|
73
|
+
target_name=target_name,
|
|
74
|
+
credentials=project_spec.credentials or [],
|
|
75
|
+
credential_name=identity_name,
|
|
76
|
+
)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Port of src/cli/operations/fetch-access/list-agents.ts."""
|
|
2
|
+
|
|
3
|
+
from agentcore.lib.schemas.io.config_io import ConfigIO
|
|
4
|
+
from agentcore.operations.fetch_access._target import _target_resources
|
|
5
|
+
from agentcore.operations.fetch_access.types import AgentInfo
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def list_agents(*, config_io: ConfigIO | None = None, deploy_target: str | None = None) -> list[AgentInfo]:
|
|
9
|
+
found = _target_resources(config_io or ConfigIO(), deploy_target)
|
|
10
|
+
if found is None:
|
|
11
|
+
return []
|
|
12
|
+
project_spec, resources = found
|
|
13
|
+
deployed = (resources.runtimes if resources else None) or {}
|
|
14
|
+
return [
|
|
15
|
+
{"name": a.name, "authType": a.authorizer_type or "AWS_IAM"}
|
|
16
|
+
for a in project_spec.runtimes or []
|
|
17
|
+
if deployed.get(a.name) and deployed[a.name].runtime_arn
|
|
18
|
+
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Port of src/cli/operations/fetch-access/list-gateways.ts."""
|
|
2
|
+
|
|
3
|
+
from agentcore.lib.schemas.io.config_io import ConfigIO
|
|
4
|
+
from agentcore.operations.fetch_access._target import _target_resources
|
|
5
|
+
from agentcore.operations.fetch_access.types import GatewayInfo
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def list_gateways(*, config_io: ConfigIO | None = None, deploy_target: str | None = None) -> list[GatewayInfo]:
|
|
9
|
+
found = _target_resources(config_io or ConfigIO(), deploy_target)
|
|
10
|
+
if found is None:
|
|
11
|
+
return []
|
|
12
|
+
project_spec, resources = found
|
|
13
|
+
gateways = project_spec.agent_core_gateways or []
|
|
14
|
+
mcp_deployed = (resources.mcp.gateways if resources and resources.mcp else None) or {}
|
|
15
|
+
result: list[GatewayInfo] = []
|
|
16
|
+
for gateway in gateways:
|
|
17
|
+
deployed = mcp_deployed.get(gateway.name)
|
|
18
|
+
if deployed and deployed.gateway_url:
|
|
19
|
+
result.append({"name": gateway.name, "authType": gateway.authorizer_type})
|
|
20
|
+
# HTTP gateways (deployed via CFN under resources.gateways)
|
|
21
|
+
http_deployed = (resources.gateways if resources else None) or {}
|
|
22
|
+
for gateway in (g for g in gateways if g.protocol_type == "None"):
|
|
23
|
+
deployed = http_deployed.get(gateway.name)
|
|
24
|
+
if deployed and deployed.gateway_arn:
|
|
25
|
+
result.append({"name": gateway.name, "authType": gateway.authorizer_type or "NONE"})
|
|
26
|
+
return result
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Port of src/cli/operations/fetch-access/list-harnesses.ts."""
|
|
2
|
+
|
|
3
|
+
from agentcore.lib.schemas.io.config_io import ConfigIO
|
|
4
|
+
from agentcore.operations.fetch_access._target import _target_resources
|
|
5
|
+
from agentcore.operations.fetch_access.types import HarnessInfo
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def list_harnesses(*, config_io: ConfigIO | None = None, deploy_target: str | None = None) -> list[HarnessInfo]:
|
|
9
|
+
config_io = config_io or ConfigIO()
|
|
10
|
+
found = _target_resources(config_io, deploy_target)
|
|
11
|
+
if found is None:
|
|
12
|
+
return []
|
|
13
|
+
project_spec, resources = found
|
|
14
|
+
deployed = (resources.harnesses if resources else None) or {}
|
|
15
|
+
result: list[HarnessInfo] = []
|
|
16
|
+
for harness in project_spec.harnesses or []:
|
|
17
|
+
state = deployed.get(harness.name)
|
|
18
|
+
if not (state and state.harness_arn):
|
|
19
|
+
continue
|
|
20
|
+
# A read failure for a deployed harness is a real config problem: let it propagate.
|
|
21
|
+
spec = config_io.read_harness_spec(harness.name)
|
|
22
|
+
result.append({"name": harness.name, "authType": spec.authorizer_type or "AWS_IAM"})
|
|
23
|
+
return result
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""Port of src/cli/operations/fetch-access/oauth-token.ts (OIDC discovery + client_credentials)."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import urllib.error
|
|
5
|
+
import urllib.request
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Any
|
|
8
|
+
from urllib.parse import urlencode
|
|
9
|
+
|
|
10
|
+
from agentcore.lib.utils.env import read_env_file
|
|
11
|
+
from agentcore.primitives.credential_utils import (
|
|
12
|
+
compute_default_credential_env_var_name,
|
|
13
|
+
compute_managed_oauth_credential_name,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class OAuthTokenResult:
|
|
19
|
+
token: str
|
|
20
|
+
expires_in: int | None = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class HttpResponse:
|
|
25
|
+
status: int
|
|
26
|
+
status_text: str
|
|
27
|
+
body: str
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def ok(self) -> bool:
|
|
31
|
+
return 200 <= self.status < 300
|
|
32
|
+
|
|
33
|
+
def json(self) -> Any:
|
|
34
|
+
return json.loads(self.body)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def http_fetch(url: str, *, method: str = "GET", headers: dict[str, str] | None = None, body: str | None = None):
|
|
38
|
+
"""Minimal ``fetch()``: returns status/statusText/body without raising on HTTP errors."""
|
|
39
|
+
request = urllib.request.Request(
|
|
40
|
+
url, method=method, headers=headers or {}, data=body.encode() if body is not None else None
|
|
41
|
+
)
|
|
42
|
+
try:
|
|
43
|
+
with urllib.request.urlopen(request, timeout=30) as response:
|
|
44
|
+
return HttpResponse(response.status, response.reason or "", response.read().decode("utf-8", "replace"))
|
|
45
|
+
except urllib.error.HTTPError as exc:
|
|
46
|
+
return HttpResponse(exc.code, exc.reason or "", exc.read().decode("utf-8", "replace"))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _field(obj: Any, name: str) -> Any:
|
|
50
|
+
return obj.get(name) if isinstance(obj, dict) else getattr(obj, name, None)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _resolve_client_id(
|
|
54
|
+
deployed_state: Any,
|
|
55
|
+
target_name: str,
|
|
56
|
+
cred_name: str,
|
|
57
|
+
env_var_prefix: str,
|
|
58
|
+
env_vars: dict[str, str],
|
|
59
|
+
allowed_clients: list[str] | None,
|
|
60
|
+
) -> str | None:
|
|
61
|
+
# Tier 1: deployed-state credentials
|
|
62
|
+
target = (deployed_state.targets or {}).get(target_name)
|
|
63
|
+
resources = target.resources if target else None
|
|
64
|
+
deployed_cred = ((resources.credentials if resources else None) or {}).get(cred_name)
|
|
65
|
+
if deployed_cred is not None:
|
|
66
|
+
client_id = getattr(deployed_cred, "client_id", None) or (deployed_cred.model_extra or {}).get("clientId")
|
|
67
|
+
if client_id:
|
|
68
|
+
return client_id
|
|
69
|
+
# Tier 2: env var <prefix>_CLIENT_ID
|
|
70
|
+
env_client_id = env_vars.get(f"{env_var_prefix}_CLIENT_ID")
|
|
71
|
+
if env_client_id:
|
|
72
|
+
return env_client_id
|
|
73
|
+
# Tier 3: allowedClients[0]
|
|
74
|
+
if allowed_clients:
|
|
75
|
+
return allowed_clients[0]
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def fetch_oauth_token(
|
|
80
|
+
*,
|
|
81
|
+
resource_name: str,
|
|
82
|
+
jwt_config: Any,
|
|
83
|
+
deployed_state: Any,
|
|
84
|
+
target_name: str,
|
|
85
|
+
credentials: list[Any],
|
|
86
|
+
credential_name: str | None = None,
|
|
87
|
+
) -> OAuthTokenResult:
|
|
88
|
+
"""``jwt_config`` is a CustomJwtAuthorizer model (discovery_url, allowed_clients, allowed_scopes)."""
|
|
89
|
+
cred_name = credential_name or compute_managed_oauth_credential_name(resource_name)
|
|
90
|
+
oauth_creds = [c for c in credentials if c.authorizer_type == "OAuthCredentialProvider"]
|
|
91
|
+
credential = next((c for c in oauth_creds if c.name == cred_name), None)
|
|
92
|
+
if credential is None:
|
|
93
|
+
available = [c.name for c in oauth_creds]
|
|
94
|
+
hint = (
|
|
95
|
+
f" Available OAuth credentials: {', '.join(available)}. Use --identity-name to specify one."
|
|
96
|
+
if available
|
|
97
|
+
else ""
|
|
98
|
+
)
|
|
99
|
+
raise RuntimeError(
|
|
100
|
+
f"No managed OAuth credential found for '{resource_name}'. Expected credential '{cred_name}'.{hint}"
|
|
101
|
+
+ (" Re-create the resource with --client-id and --client-secret." if not available else "")
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
env_var_prefix = compute_default_credential_env_var_name(cred_name)
|
|
105
|
+
secret_env_var = f"{env_var_prefix}_CLIENT_SECRET"
|
|
106
|
+
env_vars = read_env_file()
|
|
107
|
+
client_secret = env_vars.get(secret_env_var)
|
|
108
|
+
if not client_secret:
|
|
109
|
+
raise RuntimeError(
|
|
110
|
+
f"Client secret not found in environment variable {secret_env_var}. "
|
|
111
|
+
"Ensure .env.local file contains this value."
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
client_id = _resolve_client_id(
|
|
115
|
+
deployed_state, target_name, cred_name, env_var_prefix, env_vars, _field(jwt_config, "allowed_clients")
|
|
116
|
+
)
|
|
117
|
+
if not client_id:
|
|
118
|
+
raise RuntimeError(
|
|
119
|
+
f"Could not determine OAuth client ID for '{resource_name}'. Ensure the resource was created with --client-id."
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
discovery_url = _field(jwt_config, "discovery_url")
|
|
123
|
+
discovery = http_fetch(discovery_url)
|
|
124
|
+
if not discovery.ok:
|
|
125
|
+
raise RuntimeError(f"OIDC discovery failed: {discovery.status} {discovery.status_text} ({discovery_url})")
|
|
126
|
+
discovery_doc = discovery.json()
|
|
127
|
+
token_endpoint = discovery_doc.get("token_endpoint")
|
|
128
|
+
if not token_endpoint:
|
|
129
|
+
raise RuntimeError(f"OIDC discovery response missing 'token_endpoint' field ({discovery_url})")
|
|
130
|
+
|
|
131
|
+
supported = discovery_doc.get("grant_types_supported")
|
|
132
|
+
if supported and "client_credentials" not in supported:
|
|
133
|
+
raise RuntimeError(
|
|
134
|
+
"This OAuth provider does not support the client_credentials grant type. "
|
|
135
|
+
f"Supported grants: {', '.join(supported)}. "
|
|
136
|
+
"Authorization code flows (3-legged OAuth) requiring browser login are not yet supported."
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
params = {"grant_type": "client_credentials", "client_id": client_id, "client_secret": client_secret}
|
|
140
|
+
scopes = _field(jwt_config, "allowed_scopes")
|
|
141
|
+
if scopes:
|
|
142
|
+
params["scope"] = " ".join(scopes)
|
|
143
|
+
|
|
144
|
+
token_response = http_fetch(
|
|
145
|
+
token_endpoint,
|
|
146
|
+
method="POST",
|
|
147
|
+
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
|
148
|
+
body=urlencode(params),
|
|
149
|
+
)
|
|
150
|
+
if not token_response.ok:
|
|
151
|
+
error_body = token_response.body
|
|
152
|
+
if "unsupported_grant_type" in error_body:
|
|
153
|
+
raise RuntimeError(
|
|
154
|
+
"Token request failed: the OAuth provider rejected the client_credentials grant type. "
|
|
155
|
+
"This resource may require an authorization code flow (3-legged OAuth) which is not yet supported."
|
|
156
|
+
)
|
|
157
|
+
raise RuntimeError(f"Token request failed: {token_response.status} {token_response.status_text}. {error_body}")
|
|
158
|
+
|
|
159
|
+
token_data = token_response.json()
|
|
160
|
+
if not token_data.get("access_token"):
|
|
161
|
+
raise RuntimeError("Token response missing access_token field.")
|
|
162
|
+
return OAuthTokenResult(token=token_data["access_token"], expires_in=token_data.get("expires_in"))
|