apx-aws-lambda 0.1.0__tar.gz → 0.3.0__tar.gz
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.
- apx_aws_lambda-0.3.0/PKG-INFO +93 -0
- apx_aws_lambda-0.3.0/README.md +75 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/lambda_.py +96 -10
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/overlays/cloud/aws/lambda/{{cookiecutter.project_slug}}/_lang/python/lambda_handler.py +2 -1
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/plugin.py +3 -3
- apx_aws_lambda-0.3.0/apx_aws_lambda/shell.py +66 -0
- apx_aws_lambda-0.3.0/apx_aws_lambda.egg-info/PKG-INFO +93 -0
- apx_aws_lambda-0.3.0/apx_aws_lambda.egg-info/requires.txt +8 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/pyproject.toml +2 -2
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/tests/test_targets.py +51 -1
- apx_aws_lambda-0.1.0/PKG-INFO +0 -56
- apx_aws_lambda-0.1.0/README.md +0 -40
- apx_aws_lambda-0.1.0/apx_aws_lambda/shell.py +0 -46
- apx_aws_lambda-0.1.0/apx_aws_lambda.egg-info/PKG-INFO +0 -56
- apx_aws_lambda-0.1.0/apx_aws_lambda.egg-info/requires.txt +0 -6
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/LICENSE +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/__init__.py +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/cli.py +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/overlays/cloud/aws/lambda/cookiecutter.json +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/overlays/cloud/aws/lambda/hooks/post_gen_project.py +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/overlays/cloud/aws/lambda/{{cookiecutter.project_slug}}/.github/workflows/deploy.yml +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/overlays/cloud/aws/lambda/{{cookiecutter.project_slug}}/DEPLOY.md +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/overlays/cloud/aws/lambda/{{cookiecutter.project_slug}}/_lang/python/Makefile +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/overlays/cloud/aws/lambda/{{cookiecutter.project_slug}}/requirements/policy.json +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/overlays/cloud/aws/lambda/{{cookiecutter.project_slug}}/requirements/trust.json +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/overlays/cloud/aws/lambda/{{cookiecutter.project_slug}}/samconfig.toml +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/overlays/cloud/aws/lambda/{{cookiecutter.project_slug}}/template.yaml +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/overlays/index.json +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda/tools.py +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda.egg-info/SOURCES.txt +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda.egg-info/dependency_links.txt +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda.egg-info/entry_points.txt +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/apx_aws_lambda.egg-info/top_level.txt +0 -0
- {apx_aws_lambda-0.1.0 → apx_aws_lambda-0.3.0}/setup.cfg +0 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: apx-aws-lambda
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: AWS Lambda for Action Platform: the aws/lambda deploy target (SAM) with its overlay, and tools to read stacks and functions.
|
|
5
|
+
Author-email: Action Platform <cloud@actionplatform.io>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: action-platform>=0.17
|
|
11
|
+
Requires-Dist: awscli>=1.34
|
|
12
|
+
Requires-Dist: aws-sam-cli>=1.120
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
15
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
16
|
+
Requires-Dist: action-platform[mcp]; extra == "dev"
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# apx-aws-lambda
|
|
20
|
+
|
|
21
|
+
AWS Lambda for [Action Platform](https://github.com/actionplatform/action-platform): the `aws/lambda` deploy target (SAM) with its overlay, read-only tools and commands. `apx-` is the prefix every Action Platform extension carries.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
action-platform plugin install aws-lambda
|
|
25
|
+
action-platform cloud set aws/lambda # overlay files come from this plugin
|
|
26
|
+
action-platform deploy --dry-run # preflight: sam validate, credentials
|
|
27
|
+
action-platform deploy # sam build + sam deploy --config-env <stage>
|
|
28
|
+
action-platform diagnose
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| | |
|
|
32
|
+
|---|---|
|
|
33
|
+
| Overlay | `template.yaml`, `samconfig.toml`, `lambda_handler.py`, `Makefile`, `requirements/` (IAM), `.github/workflows/deploy.yml` |
|
|
34
|
+
| Deploy | `sam build` + `sam deploy --config-env <stage>` (`dev` → `default`, `prod` → `prod`) |
|
|
35
|
+
| Rollback | CloudFormation `rollback-stack` — previous stack state |
|
|
36
|
+
| Diagnose | stack status and the HTTP API url |
|
|
37
|
+
| Destroy | `sam delete` |
|
|
38
|
+
|
|
39
|
+
`[deploy]` in platform.toml:
|
|
40
|
+
|
|
41
|
+
```toml
|
|
42
|
+
[deploy]
|
|
43
|
+
target = "aws/lambda"
|
|
44
|
+
region = "us-east-1" # optional; samconfig.toml / AWS_REGION otherwise
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Credentials without keys
|
|
48
|
+
|
|
49
|
+
Set `role_arn` and nothing else: the target assumes that role with a short-lived OIDC token the platform signs (`sts assume-role-with-web-identity`). No access key on the platform, on your machine or in the repository; what the app may do is the role's policy.
|
|
50
|
+
|
|
51
|
+
```toml
|
|
52
|
+
[deploy]
|
|
53
|
+
target = "aws/lambda"
|
|
54
|
+
role_arn = "arn:aws:iam::123456789012:role/shop-deploy"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Once per AWS account, register the platform as an identity provider — its discovery document is `https://<platform>/.well-known/openid-configuration`:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
aws iam create-open-id-connect-provider --url https://platform.example.com --client-id-list sts.amazonaws.com
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Then a role per app (or per project) whose trust policy names the platform and the app; `requirements/policy.json` from the overlay is its permission policy:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"Version": "2012-10-17",
|
|
68
|
+
"Statement": [{
|
|
69
|
+
"Effect": "Allow",
|
|
70
|
+
"Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/platform.example.com" },
|
|
71
|
+
"Action": "sts:AssumeRoleWithWebIdentity",
|
|
72
|
+
"Condition": {
|
|
73
|
+
"StringEquals": { "platform.example.com:aud": "sts.amazonaws.com" },
|
|
74
|
+
"StringLike": { "platform.example.com:sub": "org:acme:project:shop:app:orders" }
|
|
75
|
+
}
|
|
76
|
+
}]
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`sub` is `org:<org>:project:<project>:app:<app>` for a deploy the platform runs; `org:<org>` plus an `actor` claim for `action-platform deploy` from a logged-in machine (`StringLike` with `org:acme:*` covers both). Without `role_arn` the AWS CLI's own chain applies: `aws sso login`, a profile, an instance role — still no key in a file when you use SSO.
|
|
81
|
+
|
|
82
|
+
Tools (`action-platform mcp`): `aws_lambda_stacks`, `aws_lambda_functions`. Commands: `action-platform aws-lambda stacks|functions`. Deploying itself goes through the core's `deploy` / `rollback` / `diagnose`, which drive the target.
|
|
83
|
+
|
|
84
|
+
Needs: `aws` and `sam` — on PATH when present, otherwise the `awscli` and `aws-sam-cli` packages the plugin depends on run as `python -m`, which is how the hosted platform deploys without the CLIs in its image; `AWS_REGION` (or `region` under `[deploy]`), and either `role_arn` (OIDC, no keys) or the AWS CLI's own credentials. Talks to `*.amazonaws.com` only.
|
|
85
|
+
|
|
86
|
+
## Development
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pip install -e ".[dev]"
|
|
90
|
+
pytest
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The tests fake `aws` and `sam`; nothing reaches AWS.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# apx-aws-lambda
|
|
2
|
+
|
|
3
|
+
AWS Lambda for [Action Platform](https://github.com/actionplatform/action-platform): the `aws/lambda` deploy target (SAM) with its overlay, read-only tools and commands. `apx-` is the prefix every Action Platform extension carries.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
action-platform plugin install aws-lambda
|
|
7
|
+
action-platform cloud set aws/lambda # overlay files come from this plugin
|
|
8
|
+
action-platform deploy --dry-run # preflight: sam validate, credentials
|
|
9
|
+
action-platform deploy # sam build + sam deploy --config-env <stage>
|
|
10
|
+
action-platform diagnose
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
| | |
|
|
14
|
+
|---|---|
|
|
15
|
+
| Overlay | `template.yaml`, `samconfig.toml`, `lambda_handler.py`, `Makefile`, `requirements/` (IAM), `.github/workflows/deploy.yml` |
|
|
16
|
+
| Deploy | `sam build` + `sam deploy --config-env <stage>` (`dev` → `default`, `prod` → `prod`) |
|
|
17
|
+
| Rollback | CloudFormation `rollback-stack` — previous stack state |
|
|
18
|
+
| Diagnose | stack status and the HTTP API url |
|
|
19
|
+
| Destroy | `sam delete` |
|
|
20
|
+
|
|
21
|
+
`[deploy]` in platform.toml:
|
|
22
|
+
|
|
23
|
+
```toml
|
|
24
|
+
[deploy]
|
|
25
|
+
target = "aws/lambda"
|
|
26
|
+
region = "us-east-1" # optional; samconfig.toml / AWS_REGION otherwise
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Credentials without keys
|
|
30
|
+
|
|
31
|
+
Set `role_arn` and nothing else: the target assumes that role with a short-lived OIDC token the platform signs (`sts assume-role-with-web-identity`). No access key on the platform, on your machine or in the repository; what the app may do is the role's policy.
|
|
32
|
+
|
|
33
|
+
```toml
|
|
34
|
+
[deploy]
|
|
35
|
+
target = "aws/lambda"
|
|
36
|
+
role_arn = "arn:aws:iam::123456789012:role/shop-deploy"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Once per AWS account, register the platform as an identity provider — its discovery document is `https://<platform>/.well-known/openid-configuration`:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
aws iam create-open-id-connect-provider --url https://platform.example.com --client-id-list sts.amazonaws.com
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Then a role per app (or per project) whose trust policy names the platform and the app; `requirements/policy.json` from the overlay is its permission policy:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"Version": "2012-10-17",
|
|
50
|
+
"Statement": [{
|
|
51
|
+
"Effect": "Allow",
|
|
52
|
+
"Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/platform.example.com" },
|
|
53
|
+
"Action": "sts:AssumeRoleWithWebIdentity",
|
|
54
|
+
"Condition": {
|
|
55
|
+
"StringEquals": { "platform.example.com:aud": "sts.amazonaws.com" },
|
|
56
|
+
"StringLike": { "platform.example.com:sub": "org:acme:project:shop:app:orders" }
|
|
57
|
+
}
|
|
58
|
+
}]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`sub` is `org:<org>:project:<project>:app:<app>` for a deploy the platform runs; `org:<org>` plus an `actor` claim for `action-platform deploy` from a logged-in machine (`StringLike` with `org:acme:*` covers both). Without `role_arn` the AWS CLI's own chain applies: `aws sso login`, a profile, an instance role — still no key in a file when you use SSO.
|
|
63
|
+
|
|
64
|
+
Tools (`action-platform mcp`): `aws_lambda_stacks`, `aws_lambda_functions`. Commands: `action-platform aws-lambda stacks|functions`. Deploying itself goes through the core's `deploy` / `rollback` / `diagnose`, which drive the target.
|
|
65
|
+
|
|
66
|
+
Needs: `aws` and `sam` — on PATH when present, otherwise the `awscli` and `aws-sam-cli` packages the plugin depends on run as `python -m`, which is how the hosted platform deploys without the CLIs in its image; `AWS_REGION` (or `region` under `[deploy]`), and either `role_arn` (OIDC, no keys) or the AWS CLI's own credentials. Talks to `*.amazonaws.com` only.
|
|
67
|
+
|
|
68
|
+
## Development
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install -e ".[dev]"
|
|
72
|
+
pytest
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The tests fake `aws` and `sam`; nothing reaches AWS.
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
"""`aws/lambda`: a SAM stack per stage. Deploy = `sam build` + `sam deploy --config-env <stage>`; rollback = CloudFormation rollback to the previous stack state; diagnose = stack status and the HTTP API url.
|
|
1
|
+
"""`aws/lambda`: a SAM stack per stage. Deploy = `sam build` + `sam deploy --config-env <stage>`; rollback = CloudFormation rollback to the previous stack state; diagnose = stack status and the HTTP API url.
|
|
2
|
+
|
|
3
|
+
Credentials: with `role_arn` under `[deploy]`, the target assumes that role with a short-lived OIDC token the platform signs (`sts assume-role-with-web-identity`) — no access key anywhere. Without it, the AWS CLI's own chain applies (profile, SSO, instance role)."""
|
|
2
4
|
|
|
3
5
|
from __future__ import annotations
|
|
4
6
|
|
|
@@ -7,7 +9,8 @@ import tomllib
|
|
|
7
9
|
|
|
8
10
|
from action_platform.abc import DeployTarget
|
|
9
11
|
from action_platform.core.context import Context, DeployResult, Diagnosis
|
|
10
|
-
from action_platform.core.exception import DeployError
|
|
12
|
+
from action_platform.core.exception import ActionPlatformError, DeployError
|
|
13
|
+
from action_platform.remote.client import Remote
|
|
11
14
|
|
|
12
15
|
from apx_aws_lambda import shell
|
|
13
16
|
|
|
@@ -16,7 +19,12 @@ class LambdaTarget(DeployTarget):
|
|
|
16
19
|
name = "aws/lambda"
|
|
17
20
|
|
|
18
21
|
def __init__(
|
|
19
|
-
self,
|
|
22
|
+
self,
|
|
23
|
+
region: str | None = None,
|
|
24
|
+
config: str = "samconfig.toml",
|
|
25
|
+
role_arn: str | None = None,
|
|
26
|
+
session_name: str = "action-platform",
|
|
27
|
+
**_: object,
|
|
20
28
|
) -> None:
|
|
21
29
|
self.region = (
|
|
22
30
|
region
|
|
@@ -24,6 +32,22 @@ class LambdaTarget(DeployTarget):
|
|
|
24
32
|
or os.environ.get("AWS_DEFAULT_REGION")
|
|
25
33
|
)
|
|
26
34
|
self.config = config
|
|
35
|
+
self.role_arn = role_arn or os.environ.get("AWS_ROLE_ARN")
|
|
36
|
+
self.session_name = session_name
|
|
37
|
+
self._env: dict[str, str] | None = None
|
|
38
|
+
|
|
39
|
+
def env(self, ctx: Context) -> dict[str, str] | None:
|
|
40
|
+
"""The environment `aws` and `sam` run with: temporary credentials from `role_arn` when set, the caller's own otherwise."""
|
|
41
|
+
if not self.role_arn:
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
if self._env is None:
|
|
45
|
+
self._env = {
|
|
46
|
+
**os.environ,
|
|
47
|
+
**assume_role(ctx, self.role_arn, self.session_name, self.region),
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return self._env
|
|
27
51
|
|
|
28
52
|
def _stage(self, ctx: Context) -> str:
|
|
29
53
|
return "prod" if ctx.stage == "prod" else "default"
|
|
@@ -72,19 +96,30 @@ class LambdaTarget(DeployTarget):
|
|
|
72
96
|
)
|
|
73
97
|
|
|
74
98
|
self._stack(ctx)
|
|
75
|
-
shell.aws(
|
|
76
|
-
|
|
99
|
+
shell.aws(
|
|
100
|
+
"sts", "get-caller-identity", region=self._region(ctx), env=self.env(ctx)
|
|
101
|
+
)
|
|
102
|
+
shell.run(
|
|
103
|
+
[*shell.require("sam", ""), "validate", "--lint"],
|
|
104
|
+
cwd=ctx.repo_root,
|
|
105
|
+
env=self.env(ctx),
|
|
106
|
+
)
|
|
77
107
|
|
|
78
108
|
def deploy(self, ctx: Context) -> DeployResult:
|
|
79
109
|
sam = shell.require("sam", "pip install aws-sam-cli")
|
|
80
110
|
stage = self._stage(ctx)
|
|
81
|
-
shell.run([sam, "build"], cwd=ctx.repo_root)
|
|
82
|
-
args = [
|
|
111
|
+
shell.run([*sam, "build"], cwd=ctx.repo_root, env=self.env(ctx))
|
|
112
|
+
args = [
|
|
113
|
+
*sam,
|
|
114
|
+
"deploy",
|
|
115
|
+
"--no-confirm-changeset",
|
|
116
|
+
"--no-fail-on-empty-changeset",
|
|
117
|
+
]
|
|
83
118
|
|
|
84
119
|
if stage != "default":
|
|
85
120
|
args += ["--config-env", stage]
|
|
86
121
|
|
|
87
|
-
shell.run(args, cwd=ctx.repo_root)
|
|
122
|
+
shell.run(args, cwd=ctx.repo_root, env=self.env(ctx))
|
|
88
123
|
url = self._url(ctx)
|
|
89
124
|
|
|
90
125
|
return DeployResult(
|
|
@@ -104,6 +139,7 @@ class LambdaTarget(DeployTarget):
|
|
|
104
139
|
"--stack-name",
|
|
105
140
|
self._stack(ctx),
|
|
106
141
|
region=self._region(ctx),
|
|
142
|
+
env=self.env(ctx),
|
|
107
143
|
)
|
|
108
144
|
|
|
109
145
|
def diagnose(self, ctx: Context) -> Diagnosis:
|
|
@@ -116,6 +152,7 @@ class LambdaTarget(DeployTarget):
|
|
|
116
152
|
"--stack-name",
|
|
117
153
|
stack,
|
|
118
154
|
region=self._region(ctx),
|
|
155
|
+
env=self.env(ctx),
|
|
119
156
|
)
|
|
120
157
|
except DeployError as e:
|
|
121
158
|
return Diagnosis(
|
|
@@ -145,16 +182,65 @@ class LambdaTarget(DeployTarget):
|
|
|
145
182
|
|
|
146
183
|
def delete(self, ctx: Context) -> None:
|
|
147
184
|
sam = shell.require("sam", "pip install aws-sam-cli")
|
|
148
|
-
args = [sam, "delete", "--no-prompts", "--stack-name", self._stack(ctx)]
|
|
185
|
+
args = [*sam, "delete", "--no-prompts", "--stack-name", self._stack(ctx)]
|
|
149
186
|
region = self._region(ctx)
|
|
150
187
|
|
|
151
188
|
if region:
|
|
152
189
|
args += ["--region", region]
|
|
153
190
|
|
|
154
|
-
shell.run(args, cwd=ctx.repo_root)
|
|
191
|
+
shell.run(args, cwd=ctx.repo_root, env=self.env(ctx))
|
|
155
192
|
|
|
156
193
|
def _url(self, ctx: Context) -> str | None:
|
|
157
194
|
try:
|
|
158
195
|
return self.diagnose(ctx).url
|
|
159
196
|
except DeployError:
|
|
160
197
|
return None
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def assume_role(
|
|
201
|
+
ctx: Context, role_arn: str, session_name: str, region: str | None
|
|
202
|
+
) -> dict[str, str]:
|
|
203
|
+
"""Temporary credentials for `role_arn` from an OIDC token: the platform's for a deploy it runs, the platform the CLI is logged in to otherwise."""
|
|
204
|
+
token = ctx.identity_token("sts.amazonaws.com")
|
|
205
|
+
|
|
206
|
+
if token is None:
|
|
207
|
+
try:
|
|
208
|
+
token = Remote.from_credentials().identity_token("sts.amazonaws.com")[
|
|
209
|
+
"token"
|
|
210
|
+
]
|
|
211
|
+
except ActionPlatformError as e:
|
|
212
|
+
raise DeployError(
|
|
213
|
+
f"role_arn is set but nothing can sign an identity token here: {e}. "
|
|
214
|
+
"Deploy from the platform, or log in with `action-platform login`."
|
|
215
|
+
) from e
|
|
216
|
+
|
|
217
|
+
data = shell.aws(
|
|
218
|
+
"sts",
|
|
219
|
+
"assume-role-with-web-identity",
|
|
220
|
+
"--role-arn",
|
|
221
|
+
role_arn,
|
|
222
|
+
"--role-session-name",
|
|
223
|
+
session_name,
|
|
224
|
+
"--web-identity-token",
|
|
225
|
+
token,
|
|
226
|
+
"--duration-seconds",
|
|
227
|
+
"3600",
|
|
228
|
+
region=region,
|
|
229
|
+
env={
|
|
230
|
+
k: v
|
|
231
|
+
for k, v in os.environ.items()
|
|
232
|
+
if not k.startswith("AWS_ACCESS") and k != "AWS_SESSION_TOKEN"
|
|
233
|
+
},
|
|
234
|
+
)
|
|
235
|
+
creds = data.get("Credentials") or {}
|
|
236
|
+
|
|
237
|
+
if not creds.get("AccessKeyId"):
|
|
238
|
+
raise DeployError(
|
|
239
|
+
f"assume-role-with-web-identity gave no credentials for {role_arn}"
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
"AWS_ACCESS_KEY_ID": creds["AccessKeyId"],
|
|
244
|
+
"AWS_SECRET_ACCESS_KEY": creds["SecretAccessKey"],
|
|
245
|
+
"AWS_SESSION_TOKEN": creds["SessionToken"],
|
|
246
|
+
}
|
|
@@ -15,10 +15,10 @@ class AwsLambdaPlugin(Plugin):
|
|
|
15
15
|
description = (
|
|
16
16
|
"Deploy to AWS Lambda with SAM; read CloudFormation stacks and functions"
|
|
17
17
|
)
|
|
18
|
-
min_core = "0.
|
|
18
|
+
min_core = "0.17"
|
|
19
19
|
needs = [
|
|
20
|
-
"tool: aws (
|
|
21
|
-
"env:
|
|
20
|
+
"tool: aws, sam (bundled as Python packages when not on PATH)",
|
|
21
|
+
"env: AWS_REGION; credentials from role_arn (OIDC, no keys) or the AWS CLI chain (SSO, profile, instance role)",
|
|
22
22
|
"net: *.amazonaws.com",
|
|
23
23
|
]
|
|
24
24
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Running `aws` and `sam` — the two CLIs the targets drive — and reading their JSON."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib.util
|
|
6
|
+
import json
|
|
7
|
+
import shutil
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from action_platform.core.exception import DeployError
|
|
14
|
+
|
|
15
|
+
MODULES = {"aws": "awscli", "sam": "samcli"}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def require(tool: str, hint: str) -> list[str]:
|
|
19
|
+
"""How to run `tool`: the binary on PATH, else the Python module the plugin depends on (`python -m awscli` / `python -m samcli`) — what makes the hosted platform work without the CLIs in its image."""
|
|
20
|
+
path = shutil.which(tool)
|
|
21
|
+
|
|
22
|
+
if path:
|
|
23
|
+
return [path]
|
|
24
|
+
|
|
25
|
+
module = MODULES.get(tool)
|
|
26
|
+
|
|
27
|
+
if module and importlib.util.find_spec(module) is not None:
|
|
28
|
+
return [sys.executable, "-m", module]
|
|
29
|
+
|
|
30
|
+
raise DeployError(f"{tool} is not installed: {hint}")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def run(
|
|
34
|
+
args: list[str], cwd: Path | None = None, env: dict[str, str] | None = None
|
|
35
|
+
) -> str:
|
|
36
|
+
result = subprocess.run(
|
|
37
|
+
args, cwd=cwd, env=env, capture_output=True, text=True, check=False
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if result.returncode != 0:
|
|
41
|
+
raise DeployError(
|
|
42
|
+
f"{' '.join(args[:2])} failed: {(result.stderr or result.stdout).strip()[-2000:]}"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
return result.stdout
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def aws(
|
|
49
|
+
*args: str,
|
|
50
|
+
region: str | None = None,
|
|
51
|
+
cwd: Path | None = None,
|
|
52
|
+
env: dict[str, str] | None = None,
|
|
53
|
+
) -> Any:
|
|
54
|
+
command = [
|
|
55
|
+
*require("aws", "https://aws.amazon.com/cli/"),
|
|
56
|
+
*args,
|
|
57
|
+
"--output",
|
|
58
|
+
"json",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
if region:
|
|
62
|
+
command += ["--region", region]
|
|
63
|
+
|
|
64
|
+
out = run(command, cwd=cwd, env=env)
|
|
65
|
+
|
|
66
|
+
return json.loads(out) if out.strip() else {}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: apx-aws-lambda
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: AWS Lambda for Action Platform: the aws/lambda deploy target (SAM) with its overlay, and tools to read stacks and functions.
|
|
5
|
+
Author-email: Action Platform <cloud@actionplatform.io>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: action-platform>=0.17
|
|
11
|
+
Requires-Dist: awscli>=1.34
|
|
12
|
+
Requires-Dist: aws-sam-cli>=1.120
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
15
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
16
|
+
Requires-Dist: action-platform[mcp]; extra == "dev"
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# apx-aws-lambda
|
|
20
|
+
|
|
21
|
+
AWS Lambda for [Action Platform](https://github.com/actionplatform/action-platform): the `aws/lambda` deploy target (SAM) with its overlay, read-only tools and commands. `apx-` is the prefix every Action Platform extension carries.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
action-platform plugin install aws-lambda
|
|
25
|
+
action-platform cloud set aws/lambda # overlay files come from this plugin
|
|
26
|
+
action-platform deploy --dry-run # preflight: sam validate, credentials
|
|
27
|
+
action-platform deploy # sam build + sam deploy --config-env <stage>
|
|
28
|
+
action-platform diagnose
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| | |
|
|
32
|
+
|---|---|
|
|
33
|
+
| Overlay | `template.yaml`, `samconfig.toml`, `lambda_handler.py`, `Makefile`, `requirements/` (IAM), `.github/workflows/deploy.yml` |
|
|
34
|
+
| Deploy | `sam build` + `sam deploy --config-env <stage>` (`dev` → `default`, `prod` → `prod`) |
|
|
35
|
+
| Rollback | CloudFormation `rollback-stack` — previous stack state |
|
|
36
|
+
| Diagnose | stack status and the HTTP API url |
|
|
37
|
+
| Destroy | `sam delete` |
|
|
38
|
+
|
|
39
|
+
`[deploy]` in platform.toml:
|
|
40
|
+
|
|
41
|
+
```toml
|
|
42
|
+
[deploy]
|
|
43
|
+
target = "aws/lambda"
|
|
44
|
+
region = "us-east-1" # optional; samconfig.toml / AWS_REGION otherwise
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Credentials without keys
|
|
48
|
+
|
|
49
|
+
Set `role_arn` and nothing else: the target assumes that role with a short-lived OIDC token the platform signs (`sts assume-role-with-web-identity`). No access key on the platform, on your machine or in the repository; what the app may do is the role's policy.
|
|
50
|
+
|
|
51
|
+
```toml
|
|
52
|
+
[deploy]
|
|
53
|
+
target = "aws/lambda"
|
|
54
|
+
role_arn = "arn:aws:iam::123456789012:role/shop-deploy"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Once per AWS account, register the platform as an identity provider — its discovery document is `https://<platform>/.well-known/openid-configuration`:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
aws iam create-open-id-connect-provider --url https://platform.example.com --client-id-list sts.amazonaws.com
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Then a role per app (or per project) whose trust policy names the platform and the app; `requirements/policy.json` from the overlay is its permission policy:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"Version": "2012-10-17",
|
|
68
|
+
"Statement": [{
|
|
69
|
+
"Effect": "Allow",
|
|
70
|
+
"Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/platform.example.com" },
|
|
71
|
+
"Action": "sts:AssumeRoleWithWebIdentity",
|
|
72
|
+
"Condition": {
|
|
73
|
+
"StringEquals": { "platform.example.com:aud": "sts.amazonaws.com" },
|
|
74
|
+
"StringLike": { "platform.example.com:sub": "org:acme:project:shop:app:orders" }
|
|
75
|
+
}
|
|
76
|
+
}]
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`sub` is `org:<org>:project:<project>:app:<app>` for a deploy the platform runs; `org:<org>` plus an `actor` claim for `action-platform deploy` from a logged-in machine (`StringLike` with `org:acme:*` covers both). Without `role_arn` the AWS CLI's own chain applies: `aws sso login`, a profile, an instance role — still no key in a file when you use SSO.
|
|
81
|
+
|
|
82
|
+
Tools (`action-platform mcp`): `aws_lambda_stacks`, `aws_lambda_functions`. Commands: `action-platform aws-lambda stacks|functions`. Deploying itself goes through the core's `deploy` / `rollback` / `diagnose`, which drive the target.
|
|
83
|
+
|
|
84
|
+
Needs: `aws` and `sam` — on PATH when present, otherwise the `awscli` and `aws-sam-cli` packages the plugin depends on run as `python -m`, which is how the hosted platform deploys without the CLIs in its image; `AWS_REGION` (or `region` under `[deploy]`), and either `role_arn` (OIDC, no keys) or the AWS CLI's own credentials. Talks to `*.amazonaws.com` only.
|
|
85
|
+
|
|
86
|
+
## Development
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pip install -e ".[dev]"
|
|
90
|
+
pytest
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The tests fake `aws` and `sam`; nothing reaches AWS.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "apx-aws-lambda"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "AWS Lambda for Action Platform: the aws/lambda deploy target (SAM) with its overlay, and tools to read stacks and functions."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
7
7
|
requires-python = ">=3.11"
|
|
8
8
|
authors = [{ name = "Action Platform", email = "cloud@actionplatform.io" }]
|
|
9
|
-
dependencies = ["action-platform>=0.
|
|
9
|
+
dependencies = ["action-platform>=0.17", "awscli>=1.34", "aws-sam-cli>=1.120"]
|
|
10
10
|
|
|
11
11
|
[project.optional-dependencies]
|
|
12
12
|
dev = ["pytest>=8", "ruff>=0.6", "action-platform[mcp]"]
|
|
@@ -43,7 +43,7 @@ class LambdaTargetTest(unittest.TestCase):
|
|
|
43
43
|
return json.dumps(answers.get(key, {}))
|
|
44
44
|
|
|
45
45
|
return mock.patch.multiple(
|
|
46
|
-
shell, run=run, require=lambda tool, hint: f"/usr/bin/{tool}"
|
|
46
|
+
shell, run=run, require=lambda tool, hint: [f"/usr/bin/{tool}"]
|
|
47
47
|
)
|
|
48
48
|
|
|
49
49
|
def ctx(self, stage="dev"):
|
|
@@ -141,3 +141,53 @@ class PluginTest(unittest.TestCase):
|
|
|
141
141
|
names = {t.name for t in asyncio.run(server.build().list_tools())}
|
|
142
142
|
|
|
143
143
|
self.assertLessEqual({"aws_lambda_stacks", "aws_lambda_functions"}, names)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class AssumeRoleTest(unittest.TestCase):
|
|
147
|
+
def test_role_arn_turns_the_platform_token_into_temporary_credentials(self):
|
|
148
|
+
calls: list[list[str]] = []
|
|
149
|
+
|
|
150
|
+
def run(args, cwd=None, env=None):
|
|
151
|
+
calls.append([Path(args[0]).name, *args[1:]])
|
|
152
|
+
if args[1:3] == ["sts", "assume-role-with-web-identity"]:
|
|
153
|
+
return json.dumps(
|
|
154
|
+
{
|
|
155
|
+
"Credentials": {
|
|
156
|
+
"AccessKeyId": "AKIA",
|
|
157
|
+
"SecretAccessKey": "s",
|
|
158
|
+
"SessionToken": "t",
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
)
|
|
162
|
+
return json.dumps(
|
|
163
|
+
{"Stacks": [{"StackStatus": "UPDATE_COMPLETE", "Outputs": []}]}
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
ctx = Context(repo_root=Path("."), identity=lambda aud: f"jwt-for-{aud}")
|
|
167
|
+
|
|
168
|
+
with mock.patch.multiple(
|
|
169
|
+
shell, run=run, require=lambda t, h: [f"/usr/bin/{t}"]
|
|
170
|
+
):
|
|
171
|
+
env = LambdaTarget(
|
|
172
|
+
role_arn="arn:aws:iam::1:role/deploy", region="us-east-1"
|
|
173
|
+
).env(ctx)
|
|
174
|
+
|
|
175
|
+
self.assertEqual(env["AWS_ACCESS_KEY_ID"], "AKIA")
|
|
176
|
+
self.assertEqual(env["AWS_SESSION_TOKEN"], "t")
|
|
177
|
+
sts = next(
|
|
178
|
+
c for c in calls if c[1:3] == ["sts", "assume-role-with-web-identity"]
|
|
179
|
+
)
|
|
180
|
+
self.assertIn("jwt-for-sts.amazonaws.com", sts)
|
|
181
|
+
self.assertIn("arn:aws:iam::1:role/deploy", sts)
|
|
182
|
+
|
|
183
|
+
def test_without_an_issuer_or_a_login_it_says_so(self):
|
|
184
|
+
with (
|
|
185
|
+
mock.patch.object(shell, "require", lambda t, h: "/usr/bin/aws"),
|
|
186
|
+
mock.patch.dict("os.environ", {"AP_HOME": "/nonexistent"}, clear=False),
|
|
187
|
+
):
|
|
188
|
+
with self.assertRaises(DeployError) as caught:
|
|
189
|
+
LambdaTarget(role_arn="arn:aws:iam::1:role/deploy").env(
|
|
190
|
+
Context(repo_root=Path("."))
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
self.assertIn("log in", str(caught.exception))
|
apx_aws_lambda-0.1.0/PKG-INFO
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: apx-aws-lambda
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: AWS Lambda for Action Platform: the aws/lambda deploy target (SAM) with its overlay, and tools to read stacks and functions.
|
|
5
|
-
Author-email: Action Platform <cloud@actionplatform.io>
|
|
6
|
-
License-Expression: Apache-2.0
|
|
7
|
-
Requires-Python: >=3.11
|
|
8
|
-
Description-Content-Type: text/markdown
|
|
9
|
-
License-File: LICENSE
|
|
10
|
-
Requires-Dist: action-platform>=0.16
|
|
11
|
-
Provides-Extra: dev
|
|
12
|
-
Requires-Dist: pytest>=8; extra == "dev"
|
|
13
|
-
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
14
|
-
Requires-Dist: action-platform[mcp]; extra == "dev"
|
|
15
|
-
Dynamic: license-file
|
|
16
|
-
|
|
17
|
-
# apx-aws-lambda
|
|
18
|
-
|
|
19
|
-
AWS Lambda for [Action Platform](https://github.com/actionplatform/action-platform): the `aws/lambda` deploy target (SAM) with its overlay, read-only tools and commands. `apx-` is the prefix every Action Platform extension carries.
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
action-platform plugin install aws-lambda
|
|
23
|
-
action-platform cloud set aws/lambda # overlay files come from this plugin
|
|
24
|
-
action-platform deploy --dry-run # preflight: sam validate, credentials
|
|
25
|
-
action-platform deploy # sam build + sam deploy --config-env <stage>
|
|
26
|
-
action-platform diagnose
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
| | |
|
|
30
|
-
|---|---|
|
|
31
|
-
| Overlay | `template.yaml`, `samconfig.toml`, `lambda_handler.py`, `Makefile`, `requirements/` (IAM), `.github/workflows/deploy.yml` |
|
|
32
|
-
| Deploy | `sam build` + `sam deploy --config-env <stage>` (`dev` → `default`, `prod` → `prod`) |
|
|
33
|
-
| Rollback | CloudFormation `rollback-stack` — previous stack state |
|
|
34
|
-
| Diagnose | stack status and the HTTP API url |
|
|
35
|
-
| Destroy | `sam delete` |
|
|
36
|
-
|
|
37
|
-
`[deploy]` in platform.toml:
|
|
38
|
-
|
|
39
|
-
```toml
|
|
40
|
-
[deploy]
|
|
41
|
-
target = "aws/lambda"
|
|
42
|
-
region = "us-east-1" # optional; samconfig.toml / AWS_REGION otherwise
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Tools (`action-platform mcp`): `aws_lambda_stacks`, `aws_lambda_functions`. Commands: `action-platform aws-lambda stacks|functions`. Deploying itself goes through the core's `deploy` / `rollback` / `diagnose`, which drive the target.
|
|
46
|
-
|
|
47
|
-
Needs: AWS CLI v2 (`aws`), SAM CLI (`sam`), credentials in the environment (`AWS_PROFILE` or keys), `AWS_REGION`. Talks to `*.amazonaws.com` only.
|
|
48
|
-
|
|
49
|
-
## Development
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
pip install -e ".[dev]"
|
|
53
|
-
pytest
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
The tests fake `aws` and `sam`; nothing reaches AWS.
|
apx_aws_lambda-0.1.0/README.md
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# apx-aws-lambda
|
|
2
|
-
|
|
3
|
-
AWS Lambda for [Action Platform](https://github.com/actionplatform/action-platform): the `aws/lambda` deploy target (SAM) with its overlay, read-only tools and commands. `apx-` is the prefix every Action Platform extension carries.
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
action-platform plugin install aws-lambda
|
|
7
|
-
action-platform cloud set aws/lambda # overlay files come from this plugin
|
|
8
|
-
action-platform deploy --dry-run # preflight: sam validate, credentials
|
|
9
|
-
action-platform deploy # sam build + sam deploy --config-env <stage>
|
|
10
|
-
action-platform diagnose
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
| | |
|
|
14
|
-
|---|---|
|
|
15
|
-
| Overlay | `template.yaml`, `samconfig.toml`, `lambda_handler.py`, `Makefile`, `requirements/` (IAM), `.github/workflows/deploy.yml` |
|
|
16
|
-
| Deploy | `sam build` + `sam deploy --config-env <stage>` (`dev` → `default`, `prod` → `prod`) |
|
|
17
|
-
| Rollback | CloudFormation `rollback-stack` — previous stack state |
|
|
18
|
-
| Diagnose | stack status and the HTTP API url |
|
|
19
|
-
| Destroy | `sam delete` |
|
|
20
|
-
|
|
21
|
-
`[deploy]` in platform.toml:
|
|
22
|
-
|
|
23
|
-
```toml
|
|
24
|
-
[deploy]
|
|
25
|
-
target = "aws/lambda"
|
|
26
|
-
region = "us-east-1" # optional; samconfig.toml / AWS_REGION otherwise
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Tools (`action-platform mcp`): `aws_lambda_stacks`, `aws_lambda_functions`. Commands: `action-platform aws-lambda stacks|functions`. Deploying itself goes through the core's `deploy` / `rollback` / `diagnose`, which drive the target.
|
|
30
|
-
|
|
31
|
-
Needs: AWS CLI v2 (`aws`), SAM CLI (`sam`), credentials in the environment (`AWS_PROFILE` or keys), `AWS_REGION`. Talks to `*.amazonaws.com` only.
|
|
32
|
-
|
|
33
|
-
## Development
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
pip install -e ".[dev]"
|
|
37
|
-
pytest
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
The tests fake `aws` and `sam`; nothing reaches AWS.
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
"""Running `aws` and `sam` — the two CLIs the targets drive — and reading their JSON."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
import shutil
|
|
7
|
-
import subprocess
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
from typing import Any
|
|
10
|
-
|
|
11
|
-
from action_platform.core.exception import DeployError
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def require(tool: str, hint: str) -> str:
|
|
15
|
-
path = shutil.which(tool)
|
|
16
|
-
|
|
17
|
-
if not path:
|
|
18
|
-
raise DeployError(f"{tool} is not installed: {hint}")
|
|
19
|
-
|
|
20
|
-
return path
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def run(
|
|
24
|
-
args: list[str], cwd: Path | None = None, env: dict[str, str] | None = None
|
|
25
|
-
) -> str:
|
|
26
|
-
result = subprocess.run(
|
|
27
|
-
args, cwd=cwd, env=env, capture_output=True, text=True, check=False
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
if result.returncode != 0:
|
|
31
|
-
raise DeployError(
|
|
32
|
-
f"{' '.join(args[:2])} failed: {(result.stderr or result.stdout).strip()[-2000:]}"
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
return result.stdout
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def aws(*args: str, region: str | None = None, cwd: Path | None = None) -> Any:
|
|
39
|
-
command = [require("aws", "https://aws.amazon.com/cli/"), *args, "--output", "json"]
|
|
40
|
-
|
|
41
|
-
if region:
|
|
42
|
-
command += ["--region", region]
|
|
43
|
-
|
|
44
|
-
out = run(command, cwd=cwd)
|
|
45
|
-
|
|
46
|
-
return json.loads(out) if out.strip() else {}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: apx-aws-lambda
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: AWS Lambda for Action Platform: the aws/lambda deploy target (SAM) with its overlay, and tools to read stacks and functions.
|
|
5
|
-
Author-email: Action Platform <cloud@actionplatform.io>
|
|
6
|
-
License-Expression: Apache-2.0
|
|
7
|
-
Requires-Python: >=3.11
|
|
8
|
-
Description-Content-Type: text/markdown
|
|
9
|
-
License-File: LICENSE
|
|
10
|
-
Requires-Dist: action-platform>=0.16
|
|
11
|
-
Provides-Extra: dev
|
|
12
|
-
Requires-Dist: pytest>=8; extra == "dev"
|
|
13
|
-
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
14
|
-
Requires-Dist: action-platform[mcp]; extra == "dev"
|
|
15
|
-
Dynamic: license-file
|
|
16
|
-
|
|
17
|
-
# apx-aws-lambda
|
|
18
|
-
|
|
19
|
-
AWS Lambda for [Action Platform](https://github.com/actionplatform/action-platform): the `aws/lambda` deploy target (SAM) with its overlay, read-only tools and commands. `apx-` is the prefix every Action Platform extension carries.
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
action-platform plugin install aws-lambda
|
|
23
|
-
action-platform cloud set aws/lambda # overlay files come from this plugin
|
|
24
|
-
action-platform deploy --dry-run # preflight: sam validate, credentials
|
|
25
|
-
action-platform deploy # sam build + sam deploy --config-env <stage>
|
|
26
|
-
action-platform diagnose
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
| | |
|
|
30
|
-
|---|---|
|
|
31
|
-
| Overlay | `template.yaml`, `samconfig.toml`, `lambda_handler.py`, `Makefile`, `requirements/` (IAM), `.github/workflows/deploy.yml` |
|
|
32
|
-
| Deploy | `sam build` + `sam deploy --config-env <stage>` (`dev` → `default`, `prod` → `prod`) |
|
|
33
|
-
| Rollback | CloudFormation `rollback-stack` — previous stack state |
|
|
34
|
-
| Diagnose | stack status and the HTTP API url |
|
|
35
|
-
| Destroy | `sam delete` |
|
|
36
|
-
|
|
37
|
-
`[deploy]` in platform.toml:
|
|
38
|
-
|
|
39
|
-
```toml
|
|
40
|
-
[deploy]
|
|
41
|
-
target = "aws/lambda"
|
|
42
|
-
region = "us-east-1" # optional; samconfig.toml / AWS_REGION otherwise
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Tools (`action-platform mcp`): `aws_lambda_stacks`, `aws_lambda_functions`. Commands: `action-platform aws-lambda stacks|functions`. Deploying itself goes through the core's `deploy` / `rollback` / `diagnose`, which drive the target.
|
|
46
|
-
|
|
47
|
-
Needs: AWS CLI v2 (`aws`), SAM CLI (`sam`), credentials in the environment (`AWS_PROFILE` or keys), `AWS_REGION`. Talks to `*.amazonaws.com` only.
|
|
48
|
-
|
|
49
|
-
## Development
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
pip install -e ".[dev]"
|
|
53
|
-
pytest
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
The tests fake `aws` and `sam`; nothing reaches AWS.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|