From bb7904625f341e4aebaa111c491857e91ba8e945 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Mon, 30 Jun 2025 13:43:56 +0100 Subject: [PATCH 1/2] Remove v2 deployment files --- .github/workflows/reusable_deploy_v3_sar.yml | 2 +- layer/.gitignore | 10 - layer/README.md | 27 -- layer/app.py | 36 -- layer/cdk.json | 35 -- layer/layer/__init__.py | 0 layer/layer/canary/app.py | 132 ------ layer/layer/canary_stack.py | 176 -------- layer/layer/layer_stack.py | 175 -------- layer/poetry.lock | 446 ------------------- layer/pyproject.toml | 18 - layer/sar/template.txt | 40 -- layer/scripts/update_layer_arn.sh | 78 ---- 13 files changed, 1 insertion(+), 1174 deletions(-) delete mode 100644 layer/.gitignore delete mode 100644 layer/README.md delete mode 100644 layer/app.py delete mode 100644 layer/cdk.json delete mode 100644 layer/layer/__init__.py delete mode 100644 layer/layer/canary/app.py delete mode 100644 layer/layer/canary_stack.py delete mode 100644 layer/layer/layer_stack.py delete mode 100644 layer/poetry.lock delete mode 100644 layer/pyproject.toml delete mode 100644 layer/sar/template.txt delete mode 100755 layer/scripts/update_layer_arn.sh diff --git a/.github/workflows/reusable_deploy_v3_sar.yml b/.github/workflows/reusable_deploy_v3_sar.yml index d43472f65dd..f81bb48a2fa 100644 --- a/.github/workflows/reusable_deploy_v3_sar.yml +++ b/.github/workflows/reusable_deploy_v3_sar.yml @@ -151,7 +151,7 @@ jobs: -e "s||./cdk.out/$asset|g" \ -e "s||${{ matrix.python-version }}|g" \ -e "s||${{ matrix.architecture }}|g" \ - layer/sar/template.txt > template.yml + layer_v3/sar/template.txt > template.yml # SAR needs a README and a LICENSE, so just copy the ones from the repo cp README.md LICENSE "./cdk.out/$asset/" diff --git a/layer/.gitignore b/layer/.gitignore deleted file mode 100644 index 37833f8beb2..00000000000 --- a/layer/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -*.swp -package-lock.json -__pycache__ -.pytest_cache -.venv -*.egg-info - -# CDK asset staging directory -.cdk.staging -cdk.out diff --git a/layer/README.md b/layer/README.md deleted file mode 100644 index 3d43a66a7f1..00000000000 --- a/layer/README.md +++ /dev/null @@ -1,27 +0,0 @@ - -# CDK Powertools for AWS Lambda (Python) layer - -This is a CDK project to build and deploy Powertools for AWS Lambda (Python) [Lambda layer](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-concepts.html#gettingstarted-concepts-layer) to multiple commercial regions. - -## Build the layer - -To build the layer construct you need to provide the Powertools for AWS Lambda (Python) version that is [available in PyPi](https://pypi.org/project/aws-lambda-powertools/). -You can pass it as a context variable when running `synth` or `deploy`, - -```shell -cdk synth --context version=1.25.1 -``` - -## Canary stack - -We use a canary stack to verify that the deployment is successful and we can use the layer by adding it to a newly created Lambda function. -The canary is deployed after the layer construct. Because the layer ARN is created during the deploy we need to pass this information async via SSM parameter. -To achieve that we use SSM parameter store to pass the layer ARN to the canary. -The layer stack writes the layer ARN after the deployment as SSM parameter and the canary stacks reads this information and adds the layer to the function. - -## Version tracking - -AWS Lambda versions Lambda layers by incrementing a number at the end of the ARN. -This makes it challenging to know which Powertools for AWS Lambda (Python) version a layer contains. -For better tracking of the ARNs and the corresponding version we need to keep track which Powertools for AWS Lambda (Python) version was deployed to which layer. -To achieve that we created two components. First, we created a version tracking app which receives events via EventBridge. Second, after a successful canary deployment we send the layer ARN, Powertools for AWS Lambda (Python) version, and the region to this EventBridge. diff --git a/layer/app.py b/layer/app.py deleted file mode 100644 index 7bc5d8b0103..00000000000 --- a/layer/app.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 - -import aws_cdk as cdk - -from layer.canary_stack import CanaryStack -from layer.layer_stack import LayerStack - -app = cdk.App() - -POWERTOOLS_VERSION: str = app.node.try_get_context("version") -SSM_PARAM_LAYER_ARN: str = "/layers/powertools-layer-v2-arn" -SSM_PARAM_LAYER_ARM64_ARN: str = "/layers/powertools-layer-v2-arm64-arn" - -if not POWERTOOLS_VERSION: - raise ValueError( - "Please set the version for Powertools for AWS Lambda (Python) by passing the '--context version=' parameter to the CDK " - "synth step." - ) - -LayerStack( - app, - "LayerV2Stack", - powertools_version=POWERTOOLS_VERSION, - ssm_parameter_layer_arn=SSM_PARAM_LAYER_ARN, - ssm_parameter_layer_arm64_arn=SSM_PARAM_LAYER_ARM64_ARN, -) - -CanaryStack( - app, - "CanaryV2Stack", - powertools_version=POWERTOOLS_VERSION, - ssm_paramter_layer_arn=SSM_PARAM_LAYER_ARN, - ssm_parameter_layer_arm64_arn=SSM_PARAM_LAYER_ARM64_ARN, -) - -app.synth() diff --git a/layer/cdk.json b/layer/cdk.json deleted file mode 100644 index c120c5f4765..00000000000 --- a/layer/cdk.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "app": "python3 app.py", - "watch": { - "include": [ - "**" - ], - "exclude": [ - "README.md", - "cdk*.json", - "requirements*.txt", - "source.bat", - "**/__init__.py", - "python/__pycache__", - "tests" - ] - }, - "context": { - "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, - "@aws-cdk/core:stackRelativeExports": true, - "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, - "@aws-cdk/aws-lambda:recognizeVersionProps": true, - "@aws-cdk/aws-lambda:recognizeLayerVersion": true, - "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, - "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, - "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, - "@aws-cdk/core:checkSecretUsage": true, - "@aws-cdk/aws-iam:minimizePolicies": true, - "@aws-cdk/core:validateSnapshotRemovalPolicy": true, - "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, - "@aws-cdk/core:target-partitions": [ - "aws", - "aws-cn" - ] - } -} diff --git a/layer/layer/__init__.py b/layer/layer/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/layer/layer/canary/app.py b/layer/layer/canary/app.py deleted file mode 100644 index 9dea0297690..00000000000 --- a/layer/layer/canary/app.py +++ /dev/null @@ -1,132 +0,0 @@ -import datetime -import json -import os -import platform -from importlib.metadata import version - -import boto3 -from pydantic import HttpUrl - -from aws_lambda_powertools import Logger, Metrics, Tracer -from aws_lambda_powertools.utilities.parser import BaseModel, envelopes, event_parser -from aws_lambda_powertools.utilities.typing import LambdaContext -from aws_lambda_powertools.utilities.validation import validator - -logger = Logger(service="version-track") -tracer = Tracer() # this checks for aws-xray-sdk presence -metrics = Metrics(namespace="powertools-layer-canary", service="PowertoolsLayerCanary") - -layer_arn = os.getenv("POWERTOOLS_LAYER_ARN") -powertools_version = os.getenv("POWERTOOLS_VERSION") -stage = os.getenv("LAYER_PIPELINE_STAGE") -event_bus_arn = os.getenv("VERSION_TRACKING_EVENT_BUS_ARN") - - -# Model to check parser imports correctly, tests for pydantic -class OrderItem(BaseModel): - order_id: int - quantity: int - description: str - url: HttpUrl - - -# Tests for jmespath presence -@event_parser(model=OrderItem, envelope=envelopes.EventBridgeEnvelope) -def envelope_handler(event: OrderItem, context: LambdaContext): - assert event.order_id != 1 - - -# Tests for fastjsonschema presence -@validator(inbound_schema={}, envelope="detail") -def validator_handler(event, context: LambdaContext): - pass - - -def handler(event): - logger.info("Running checks") - check_envs() - verify_powertools_version() - send_notification() - return True - - -@logger.inject_lambda_context(log_event=True) -def on_event(event, context): - request_type = event["RequestType"] - # we handle only create events, because we recreate the canary on each run - if request_type == "Create": - return on_create(event) - - return "Nothing to be processed" - - -def on_create(event): - props = event["ResourceProperties"] - logger.info("create new resource with properties %s" % props) - handler(event) - - -def check_envs(): - logger.info('Checking required envs ["POWERTOOLS_LAYER_ARN", "AWS_REGION", "STAGE"]') - if not layer_arn: - raise ValueError("POWERTOOLS_LAYER_ARN is not set. Aborting...") - if not powertools_version: - raise ValueError("POWERTOOLS_VERSION is not set. Aborting...") - if not stage: - raise ValueError("LAYER_PIPELINE_STAGE is not set. Aborting...") - if not event_bus_arn: - raise ValueError("VERSION_TRACKING_EVENT_BUS_ARN is not set. Aborting...") - logger.info("All envs configured, continue...") - - -def verify_powertools_version() -> None: - """ - fetches the version that we import from the Powertools for AWS Lambda (Python) layer and compares - it with expected version set in environment variable, which we pass during deployment. - :raise ValueError if the expected version is not the same as the version we get from the layer - """ - logger.info("Checking Powertools for AWS Lambda (Python) version in library...") - current_version = version("aws_lambda_powertools") - if powertools_version != current_version: - raise ValueError( - f'Expected Powertools for AWS Lambda (Python) version is "{powertools_version}", but layer contains version "{current_version}"' - ) - logger.info(f"Current Powertools for AWS Lambda (Python) version is: {current_version} [{_get_architecture()}]") - - -def send_notification(): - """ - sends an event to version tracking event bridge - """ - if stage != "PROD": - logger.info("Not sending notification to event bus, because this is not the PROD stage") - return - - event = { - "Time": datetime.datetime.now(), - "Source": "powertools.layer.canary", - "EventBusName": event_bus_arn, - "DetailType": "deployment", - "Detail": json.dumps( - { - "version": powertools_version, - "region": os.environ["AWS_REGION"], - "layerArn": layer_arn, - "architecture": _get_architecture(), - } - ), - } - - logger.info(f"sending notification event: {event}") - - client = boto3.client("events", region_name="eu-central-1") - resp = client.put_events(Entries=[event]) - logger.info(resp) - if resp["FailedEntryCount"] != 0: - logger.error(resp) - raise ValueError("Failed to send deployment notification to version tracking") - - -def _get_architecture() -> str: - """Returns aarch64, x86_64""" - return platform.uname()[4] diff --git a/layer/layer/canary_stack.py b/layer/layer/canary_stack.py deleted file mode 100644 index 9ba94f7920c..00000000000 --- a/layer/layer/canary_stack.py +++ /dev/null @@ -1,176 +0,0 @@ -import uuid - -import jsii -from aws_cdk import ( - Aspects, - CfnCondition, - CfnParameter, - CfnResource, - CustomResource, - Duration, - Fn, - IAspect, - Stack, -) -from aws_cdk.aws_iam import ( - Effect, - ManagedPolicy, - PolicyStatement, - Role, - ServicePrincipal, -) -from aws_cdk.aws_lambda import Architecture, Code, Function, LayerVersion, Runtime -from aws_cdk.aws_logs import RetentionDays -from aws_cdk.aws_ssm import StringParameter -from aws_cdk.custom_resources import Provider -from constructs import Construct - -VERSION_TRACKING_EVENT_BUS_ARN: str = ( - "arn:aws:events:eu-central-1:027876851704:event-bus/VersionTrackingEventBus" -) - - -@jsii.implements(IAspect) -class ApplyCondition: - def __init__(self, condition: CfnCondition): - self.condition = condition - - def visit(self, node): - if isinstance(node, CfnResource): - node.cfn_options.condition = self.condition - - -class CanaryStack(Stack): - def __init__( - self, - scope: Construct, - construct_id: str, - powertools_version: str, - ssm_paramter_layer_arn: str, - ssm_parameter_layer_arm64_arn: str, - **kwargs, - ) -> None: - super().__init__(scope, construct_id, **kwargs) - - deploy_stage = CfnParameter( - self, "DeployStage", description="Deployment stage for canary" - ).value_as_string - - has_arm64_support = CfnParameter( - self, - "HasARM64Support", - description="Has ARM64 Support Condition", - type="String", - allowed_values=["true", "false"], - ) - - has_arm64_condition = CfnCondition( - self, - "HasARM64SupportCondition", - expression=Fn.condition_equals(has_arm64_support, "true"), - ) - - layer_arn = StringParameter.from_string_parameter_attributes( - self, "LayerVersionArnParam", parameter_name=ssm_paramter_layer_arn - ).string_value - Canary( - self, - "Canary-x86-64", - layer_arn=layer_arn, - powertools_version=powertools_version, - architecture=Architecture.X86_64, - stage=deploy_stage, - ) - - layer_arm64_arn = StringParameter.from_string_parameter_attributes( - self, - "LayerArm64VersionArnParam", - parameter_name=ssm_parameter_layer_arm64_arn, - ).string_value - - arm64_canary = Canary( - self, - "Canary-arm64", - layer_arn=layer_arm64_arn, - powertools_version=powertools_version, - architecture=Architecture.ARM_64, - stage=deploy_stage, - ) - Aspects.of(arm64_canary).add(ApplyCondition(has_arm64_condition)) - - -class Canary(Construct): - def __init__( - self, - scope: Construct, - construct_id: str, - layer_arn: str, - powertools_version: str, - architecture: Architecture, - stage: str, - ): - super().__init__(scope, construct_id) - - layer = LayerVersion.from_layer_version_arn( - self, "PowertoolsLayer", layer_version_arn=layer_arn - ) - - execution_role = Role( - self, - "LambdaExecutionRole", - assumed_by=ServicePrincipal("lambda.amazonaws.com"), - ) - - execution_role.add_managed_policy( - ManagedPolicy.from_aws_managed_policy_name( - "service-role/AWSLambdaBasicExecutionRole" - ) - ) - - execution_role.add_to_policy( - PolicyStatement( - effect=Effect.ALLOW, actions=["lambda:GetFunction"], resources=["*"] - ) - ) - - canary_lambda = Function( - self, - "CanaryLambdaFunction", - code=Code.from_asset("layer/canary"), - handler="app.on_event", - layers=[layer], - memory_size=512, - timeout=Duration.seconds(10), - runtime=Runtime.PYTHON_3_9, - architecture=architecture, - log_retention=RetentionDays.TEN_YEARS, - role=execution_role, - environment={ - "POWERTOOLS_VERSION": powertools_version, - "POWERTOOLS_LAYER_ARN": layer_arn, - "VERSION_TRACKING_EVENT_BUS_ARN": VERSION_TRACKING_EVENT_BUS_ARN, - "LAYER_PIPELINE_STAGE": stage, - }, - ) - - canary_lambda.add_to_role_policy( - PolicyStatement( - effect=Effect.ALLOW, - actions=["events:PutEvents"], - resources=[VERSION_TRACKING_EVENT_BUS_ARN], - ) - ) - - # custom resource provider configuration - provider = Provider( - self, - "CanaryCustomResource", - on_event_handler=canary_lambda, - log_retention=RetentionDays.TEN_YEARS, - ) - # force to recreate resource on each deployment with randomized name - CustomResource( - self, - f"CanaryTrigger-{str(uuid.uuid4())[0:7]}", - service_token=provider.service_token, - ) diff --git a/layer/layer/layer_stack.py b/layer/layer/layer_stack.py deleted file mode 100644 index a2a08437051..00000000000 --- a/layer/layer/layer_stack.py +++ /dev/null @@ -1,175 +0,0 @@ -from typing import Optional - -import jsii -from aws_cdk import ( - Aspects, - CfnCondition, - CfnOutput, - CfnParameter, - CfnResource, - Fn, - IAspect, - RemovalPolicy, - Stack, -) -from aws_cdk.aws_lambda import Architecture, CfnLayerVersionPermission -from aws_cdk.aws_ssm import StringParameter -from cdk_aws_lambda_powertools_layer import LambdaPowertoolsLayer -from constructs import Construct - - -@jsii.implements(IAspect) -class ApplyCondition: - def __init__(self, condition: CfnCondition): - self.condition = condition - - def visit(self, node): - if isinstance(node, CfnResource): - node.cfn_options.condition = self.condition - if isinstance(node, CfnOutput): - node.condition = self.condition - - -class Layer(Construct): - def __init__( - self, - scope: Construct, - construct_id: str, - layer_version_name: str, - powertools_version: str, - architecture: Optional[Architecture] = None, - **kwargs - ) -> None: - super().__init__(scope, construct_id, **kwargs) - - layer = LambdaPowertoolsLayer( - self, - "Layer", - layer_version_name=layer_version_name, - version=powertools_version, - include_extras=True, - compatible_architectures=[architecture] if architecture else [], - ) - layer.apply_removal_policy(RemovalPolicy.RETAIN) - - self.layer_version_arn = layer.layer_version_arn - - layer_permission = CfnLayerVersionPermission( - self, - "PublicLayerAccess", - action="lambda:GetLayerVersion", - layer_version_arn=layer.layer_version_arn, - principal="*", - ) - layer_permission.apply_removal_policy(RemovalPolicy.RETAIN) - - -class LayerStack(Stack): - def __init__( - self, - scope: Construct, - construct_id: str, - powertools_version: str, - ssm_parameter_layer_arn: str, - ssm_parameter_layer_arm64_arn: str, - **kwargs - ) -> None: - super().__init__(scope, construct_id, **kwargs) - - has_arm64_support = CfnParameter( - self, - "HasARM64Support", - description="Has ARM64 Support Condition", - type="String", - allowed_values=["true", "false"], - ) - - has_arm64_condition = CfnCondition( - self, - "HasARM64SupportCondition", - expression=Fn.condition_equals(has_arm64_support, "true"), - ) - has_no_arm64_condition = CfnCondition( - self, - "HasNOArm64SupportCondition", - expression=Fn.condition_equals(has_arm64_support, "false"), - ) - - # The following code is used when the region does not support ARM64 Lambdas. We make sure to only create the - # X86_64 Layer without specifying any compatible architecture, which would result in a CloudFormation error. - - layer_single = Layer( - self, - "LayerSingle", - layer_version_name="AWSLambdaPowertoolsPythonV2", - powertools_version=powertools_version, - ) - Aspects.of(layer_single).add(ApplyCondition(has_no_arm64_condition)) - - Aspects.of( - StringParameter( - self, - "SingleVersionArn", - parameter_name=ssm_parameter_layer_arn, - string_value=layer_single.layer_version_arn, - ) - ).add(ApplyCondition(has_no_arm64_condition)) - - # The following code is used when the region has support for ARM64 Lambdas. In this case, we explicitly - # create a Layer for both X86_64 and ARM64, specifying the compatible architectures. - - # X86_64 layer - - layer = Layer( - self, - "Layer", - layer_version_name="AWSLambdaPowertoolsPythonV2", - powertools_version=powertools_version, - architecture=Architecture.X86_64, - ) - Aspects.of(layer).add(ApplyCondition(has_arm64_condition)) - - Aspects.of( - StringParameter( - self, - "VersionArn", - parameter_name=ssm_parameter_layer_arn, - string_value=layer.layer_version_arn, - ) - ).add(ApplyCondition(has_arm64_condition)) - - CfnOutput( - self, - "LatestLayerArn", - value=Fn.condition_if( - has_arm64_condition.logical_id, - layer.layer_version_arn, - layer_single.layer_version_arn, - ).to_string(), - ) - - # ARM64 layer - - layer_arm64 = Layer( - self, - "Layer-ARM64", - layer_version_name="AWSLambdaPowertoolsPythonV2-Arm64", - powertools_version=powertools_version, - architecture=Architecture.ARM_64, - ) - Aspects.of(layer_arm64).add(ApplyCondition(has_arm64_condition)) - - StringParameter( - self, - "Arm64VersionArn", - parameter_name=ssm_parameter_layer_arm64_arn, - string_value=Fn.condition_if( - has_arm64_condition.logical_id, - layer_arm64.layer_version_arn, - "none", - ).to_string(), - ) - - Aspects.of( - CfnOutput(self, "LatestLayerArm64Arn", value=layer_arm64.layer_version_arn) - ).add(ApplyCondition(has_arm64_condition)) diff --git a/layer/poetry.lock b/layer/poetry.lock deleted file mode 100644 index 9b442babc99..00000000000 --- a/layer/poetry.lock +++ /dev/null @@ -1,446 +0,0 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. - -[[package]] -name = "attrs" -version = "23.1.0" -description = "Classes Without Boilerplate" -optional = false -python-versions = ">=3.7" -files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, -] - -[package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] - -[[package]] -name = "aws-cdk-asset-awscli-v1" -version = "2.2.201" -description = "A library that contains the AWS CLI for use in Lambda Layers" -optional = false -python-versions = "~=3.7" -files = [ - {file = "aws-cdk.asset-awscli-v1-2.2.201.tar.gz", hash = "sha256:88d1c269fd5cf8c9f6e0464ed22e2d4f269dfd5b36b8c4d37687bdba9c269839"}, - {file = "aws_cdk.asset_awscli_v1-2.2.201-py3-none-any.whl", hash = "sha256:56fe2ef91d3c8d33559aa32d2130e5f35f23af1fb82f06648ebbc82ffe0a5879"}, -] - -[package.dependencies] -jsii = ">=1.91.0,<2.0.0" -publication = ">=0.0.3" -typeguard = ">=2.13.3,<2.14.0" - -[[package]] -name = "aws-cdk-asset-kubectl-v20" -version = "2.1.2" -description = "A library that contains kubectl for use in Lambda Layers" -optional = false -python-versions = "~=3.7" -files = [ - {file = "aws-cdk.asset-kubectl-v20-2.1.2.tar.gz", hash = "sha256:346283e43018a43e3b3ca571de3f44e85d49c038dc20851894cb8f9b2052b164"}, - {file = "aws_cdk.asset_kubectl_v20-2.1.2-py3-none-any.whl", hash = "sha256:7f0617ab6cb942b066bd7174bf3e1f377e57878c3e1cddc21d6b2d13c92d0cc1"}, -] - -[package.dependencies] -jsii = ">=1.70.0,<2.0.0" -publication = ">=0.0.3" -typeguard = ">=2.13.3,<2.14.0" - -[[package]] -name = "aws-cdk-asset-node-proxy-agent-v6" -version = "2.0.1" -description = "@aws-cdk/asset-node-proxy-agent-v6" -optional = false -python-versions = "~=3.7" -files = [ - {file = "aws-cdk.asset-node-proxy-agent-v6-2.0.1.tar.gz", hash = "sha256:42cdbc1de2ed3f845e3eb883a72f58fc7e5554c2e0b6fcdb366c159778dce74d"}, - {file = "aws_cdk.asset_node_proxy_agent_v6-2.0.1-py3-none-any.whl", hash = "sha256:e442673d4f93137ab165b75386761b1d46eea25fc5015e5145ae3afa9da06b6e"}, -] - -[package.dependencies] -jsii = ">=1.86.1,<2.0.0" -publication = ">=0.0.3" -typeguard = ">=2.13.3,<2.14.0" - -[[package]] -name = "aws-cdk-lib" -version = "2.108.1" -description = "Version 2 of the AWS Cloud Development Kit library" -optional = false -python-versions = "~=3.7" -files = [ - {file = "aws-cdk-lib-2.108.1.tar.gz", hash = "sha256:86bb6488de1830d8212d33f09eea494bca138182bc4db1a151fc7925598554b7"}, - {file = "aws_cdk_lib-2.108.1-py3-none-any.whl", hash = "sha256:0c0ffa0e129782c3e69cc320297b338bbc6c994025f31d3ce310badd662e44be"}, -] - -[package.dependencies] -"aws-cdk.asset-awscli-v1" = ">=2.2.201,<3.0.0" -"aws-cdk.asset-kubectl-v20" = ">=2.1.2,<3.0.0" -"aws-cdk.asset-node-proxy-agent-v6" = ">=2.0.1,<3.0.0" -constructs = ">=10.0.0,<11.0.0" -jsii = ">=1.91.0,<2.0.0" -publication = ">=0.0.3" -typeguard = ">=2.13.3,<2.14.0" - -[[package]] -name = "boto3" -version = "1.29.0" -description = "The AWS SDK for Python" -optional = false -python-versions = ">= 3.7" -files = [ - {file = "boto3-1.29.0-py3-none-any.whl", hash = "sha256:91c72fa4848eda9311c273db667946bd9d953285ae8d54b7bbad541b74adc254"}, - {file = "boto3-1.29.0.tar.gz", hash = "sha256:3e90ea2faa3e9892b9140f857911f9ef0013192a106f50d0ec7b71e8d1afc90a"}, -] - -[package.dependencies] -botocore = ">=1.32.0,<1.33.0" -jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.7.0,<0.8.0" - -[package.extras] -crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] - -[[package]] -name = "botocore" -version = "1.32.0" -description = "Low-level, data-driven core of boto 3." -optional = false -python-versions = ">= 3.7" -files = [ - {file = "botocore-1.32.0-py3-none-any.whl", hash = "sha256:9c1e143feb6a04235cec342d2acb31a0f44df3c89f309f839e03e38a75f3f44e"}, - {file = "botocore-1.32.0.tar.gz", hash = "sha256:95fe3357b9ddc4559941dbea0f0a6b8fc043305f013b7ae2a85dff0c3b36ee92"}, -] - -[package.dependencies] -jmespath = ">=0.7.1,<2.0.0" -python-dateutil = ">=2.1,<3.0.0" -urllib3 = [ - {version = ">=1.25.4,<1.27", markers = "python_version < \"3.10\""}, - {version = ">=1.25.4,<2.1", markers = "python_version >= \"3.10\""}, -] - -[package.extras] -crt = ["awscrt (==0.19.12)"] - -[[package]] -name = "cattrs" -version = "23.1.2" -description = "Composable complex class support for attrs and dataclasses." -optional = false -python-versions = ">=3.7" -files = [ - {file = "cattrs-23.1.2-py3-none-any.whl", hash = "sha256:b2bb14311ac17bed0d58785e5a60f022e5431aca3932e3fc5cc8ed8639de50a4"}, - {file = "cattrs-23.1.2.tar.gz", hash = "sha256:db1c821b8c537382b2c7c66678c3790091ca0275ac486c76f3c8f3920e83c657"}, -] - -[package.dependencies] -attrs = ">=20" -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} -typing_extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} - -[package.extras] -bson = ["pymongo (>=4.2.0,<5.0.0)"] -cbor2 = ["cbor2 (>=5.4.6,<6.0.0)"] -msgpack = ["msgpack (>=1.0.2,<2.0.0)"] -orjson = ["orjson (>=3.5.2,<4.0.0)"] -pyyaml = ["PyYAML (>=6.0,<7.0)"] -tomlkit = ["tomlkit (>=0.11.4,<0.12.0)"] -ujson = ["ujson (>=5.4.0,<6.0.0)"] - -[[package]] -name = "cdk-aws-lambda-powertools-layer" -version = "3.7.0" -description = "Powertools for AWS Lambda layer for python and typescript" -optional = false -python-versions = "~=3.7" -files = [ - {file = "cdk-aws-lambda-powertools-layer-3.7.0.tar.gz", hash = "sha256:1225f8f9086412a620fb27fe59de5537456d636b435b496bffc76e544b1fda1f"}, - {file = "cdk_aws_lambda_powertools_layer-3.7.0-py3-none-any.whl", hash = "sha256:353b010f0681a6d626721ce8f934fe17a649f845fefb276ea7451cfa1932b19e"}, -] - -[package.dependencies] -aws-cdk-lib = ">=2.108.1,<3.0.0" -constructs = ">=10.0.5,<11.0.0" -jsii = ">=1.90.0,<2.0.0" -publication = ">=0.0.3" -typeguard = ">=2.13.3,<2.14.0" - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "constructs" -version = "10.3.0" -description = "A programming model for software-defined state" -optional = false -python-versions = "~=3.7" -files = [ - {file = "constructs-10.3.0-py3-none-any.whl", hash = "sha256:2972f514837565ff5b09171cfba50c0159dfa75ee86a42921ea8c86f2941b3d2"}, - {file = "constructs-10.3.0.tar.gz", hash = "sha256:518551135ec236f9cc6b86500f4fbbe83b803ccdc6c2cb7684e0b7c4d234e7b1"}, -] - -[package.dependencies] -jsii = ">=1.90.0,<2.0.0" -publication = ">=0.0.3" -typeguard = ">=2.13.3,<2.14.0" - -[[package]] -name = "exceptiongroup" -version = "1.1.3" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, -] - -[package.extras] -test = ["pytest (>=6)"] - -[[package]] -name = "importlib-resources" -version = "6.1.1" -description = "Read resources from Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"}, - {file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"}, -] - -[package.dependencies] -zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "zipp (>=3.17)"] - -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.7" -files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, -] - -[[package]] -name = "jmespath" -version = "1.0.1" -description = "JSON Matching Expressions" -optional = false -python-versions = ">=3.7" -files = [ - {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, - {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, -] - -[[package]] -name = "jsii" -version = "1.91.0" -description = "Python client for jsii runtime" -optional = false -python-versions = "~=3.7" -files = [ - {file = "jsii-1.91.0-py3-none-any.whl", hash = "sha256:2905a4ea030ae7289b859e97003c01f4569650b4865c51e7f83d975b95c5b20a"}, - {file = "jsii-1.91.0.tar.gz", hash = "sha256:9600ac7d04b237ee229c74ffde65ece27202ceec5df5e7eebd88a532d2cb28d6"}, -] - -[package.dependencies] -attrs = ">=21.2,<24.0" -cattrs = ">=1.8,<23.2" -importlib-resources = ">=5.2.0" -publication = ">=0.0.3" -python-dateutil = "*" -typeguard = ">=2.13.3,<2.14.0" -typing-extensions = ">=3.7,<5.0" - -[[package]] -name = "packaging" -version = "23.2" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.7" -files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, -] - -[[package]] -name = "pluggy" -version = "1.3.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "publication" -version = "0.0.3" -description = "Publication helps you maintain public-api-friendly modules by preventing unintentional access to private implementation details via introspection." -optional = false -python-versions = "*" -files = [ - {file = "publication-0.0.3-py2.py3-none-any.whl", hash = "sha256:0248885351febc11d8a1098d5c8e3ab2dabcf3e8c0c96db1e17ecd12b53afbe6"}, - {file = "publication-0.0.3.tar.gz", hash = "sha256:68416a0de76dddcdd2930d1c8ef853a743cc96c82416c4e4d3b5d901c6276dc4"}, -] - -[[package]] -name = "pytest" -version = "7.4.3" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} - -[package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "python-dateutil" -version = "2.8.2" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "s3transfer" -version = "0.7.0" -description = "An Amazon S3 Transfer Manager" -optional = false -python-versions = ">= 3.7" -files = [ - {file = "s3transfer-0.7.0-py3-none-any.whl", hash = "sha256:10d6923c6359175f264811ef4bf6161a3156ce8e350e705396a7557d6293c33a"}, - {file = "s3transfer-0.7.0.tar.gz", hash = "sha256:fd3889a66f5fe17299fe75b82eae6cf722554edca744ca5d5fe308b104883d2e"}, -] - -[package.dependencies] -botocore = ">=1.12.36,<2.0a.0" - -[package.extras] -crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - -[[package]] -name = "typeguard" -version = "2.13.3" -description = "Run-time type checker for Python" -optional = false -python-versions = ">=3.5.3" -files = [ - {file = "typeguard-2.13.3-py3-none-any.whl", hash = "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1"}, - {file = "typeguard-2.13.3.tar.gz", hash = "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4"}, -] - -[package.extras] -doc = ["sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["mypy", "pytest", "typing-extensions"] - -[[package]] -name = "typing-extensions" -version = "4.8.0" -description = "Backported and Experimental Type Hints for Python 3.8+" -optional = false -python-versions = ">=3.8" -files = [ - {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, - {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, -] - -[[package]] -name = "urllib3" -version = "1.26.19" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -files = [ - {file = "urllib3-1.26.19-py2.py3-none-any.whl", hash = "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3"}, - {file = "urllib3-1.26.19.tar.gz", hash = "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"}, -] - -[package.extras] -brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] - -[[package]] -name = "zipp" -version = "3.19.1" -description = "Backport of pathlib-compatible object wrapper for zip files" -optional = false -python-versions = ">=3.8" -files = [ - {file = "zipp-3.19.1-py3-none-any.whl", hash = "sha256:2828e64edb5386ea6a52e7ba7cdb17bb30a73a858f5eb6eb93d8d36f5ea26091"}, - {file = "zipp-3.19.1.tar.gz", hash = "sha256:35427f6d5594f4acf82d25541438348c26736fa9b3afa2754bcd63cdb99d8e8f"}, -] - -[package.extras] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] - -[metadata] -lock-version = "2.0" -python-versions = "^3.9" -content-hash = "1ce9cd0461793bbd8c624f9baf2a0118a148df95441269538efa50a7c72d19f0" diff --git a/layer/pyproject.toml b/layer/pyproject.toml deleted file mode 100644 index 3fa6981a3d1..00000000000 --- a/layer/pyproject.toml +++ /dev/null @@ -1,18 +0,0 @@ -[tool.poetry] -name = "aws-lambda-powertools-python-layer" -version = "1.1.0" -description = "Powertools for AWS Lambda (Python) Lambda Layers" -authors = ["Powertools for AWS Maintainers "] - -license = "MIT" -[tool.poetry.dependencies] -python = "^3.9" -cdk-aws-lambda-powertools-layer = "^3.7.0" - -[tool.poetry.dev-dependencies] -pytest = "^7.1.2" -boto3 = "^1.24.46" - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" diff --git a/layer/sar/template.txt b/layer/sar/template.txt deleted file mode 100644 index c4e4d2f5128..00000000000 --- a/layer/sar/template.txt +++ /dev/null @@ -1,40 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' - -Metadata: - AWS::ServerlessRepo::Application: - Name: - Description: "AWS Lambda Layer for aws-lambda-powertools" - Author: AWS - SpdxLicenseId: Apache-2.0 - LicenseUrl: /LICENSE - ReadmeUrl: /README.md - Labels: ['layer','lambda','powertools','python', 'aws'] - HomePageUrl: https://github.com/aws-powertools/powertools-lambda-python - SemanticVersion: - SourceCodeUrl: https://github.com/aws-powertools/powertools-lambda-python - -Transform: AWS::Serverless-2016-10-31 -Description: AWS Lambda Layer for aws-lambda-powertools with python 3.13, 3.12, 3.11, 3.10 or 3.9 - -Resources: - LambdaLayer: - Type: AWS::Serverless::LayerVersion - Properties: - Description: "AWS Lambda Layer for aws-lambda-powertools version " - LayerName: - ContentUri: - CompatibleRuntimes: - - python3.13 - - python3.12 - - python3.11 - - python3.10 - - python3.9 - LicenseInfo: 'Available under the Apache-2.0 license.' - RetentionPolicy: Retain - -Outputs: - LayerVersionArn: - Description: ARN for the published Layer version - Value: !Ref LambdaLayer - Export: - Name: !Sub 'LayerVersionArn-${AWS::StackName}' diff --git a/layer/scripts/update_layer_arn.sh b/layer/scripts/update_layer_arn.sh deleted file mode 100755 index 1bbf63c2b88..00000000000 --- a/layer/scripts/update_layer_arn.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/bash - -# This script is run during the publish_v2_layer.yml CI job, -# and it is responsible for replacing the layer ARN in our documentation, -# based on the output files generated by CDK when deploying to each pseudo_region. -# -# see .github/workflows/reusable_deploy_v2_layer_stack.yml - -set -eo pipefail -set -x - -if [[ $# -ne 1 ]]; then - cat < line - # sed doesn't support \d+ in a portable way, so we cheat with (:digit: :digit: *) - sed -i -e "s/$prefix:[[:digit:]][[:digit:]]*/$line/g" docs/index.md - - # We use the eu-central-1 layer as the version for all the frameworks (SAM, CDK, SLS, etc) - # We could have used any other region. What's important is the version at the end. - - # Examples of strings found in the documentation with pseudo regions: - # arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPython:39 - # arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPython:39 - # arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPython:39 - # arn:aws:lambda:{env.region}:017000801446:layer:AWSLambdaPowertoolsPython:39 - if [[ "$line" == *"eu-central-1"* ]]; then - # These are all the framework pseudo parameters currently found in the docs - for pseudo_region in '{region}' '${AWS::Region}' '${aws:region}' '{env.region}'; do - prefix_pseudo_region=$(echo "$prefix" | sed "s/eu-central-1/${pseudo_region}/") - # prefix_pseudo_region = arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPython - - line_pseudo_region=$(echo "$line" | sed "s/eu-central-1/${pseudo_region}/") - # line_pseudo_region = arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPython:49 - - # Replace all the "prefix_pseudo_region"'s in the file - # prefix_pseudo_region:\d+ ==> line_pseudo_region - sed -i -e "s/$prefix_pseudo_region:[[:digit:]][[:digit:]]*/$line_pseudo_region/g" docs/index.md - - # The same strings can also be found in examples on Logger, Tracer and Metrics - sed -i -e "s/$prefix_pseudo_region:[[:digit:]][[:digit:]]*/$line_pseudo_region/g" examples/logger/sam/template.yaml - sed -i -e "s/$prefix_pseudo_region:[[:digit:]][[:digit:]]*/$line_pseudo_region/g" examples/metrics/sam/template.yaml - sed -i -e "s/$prefix_pseudo_region:[[:digit:]][[:digit:]]*/$line_pseudo_region/g" examples/tracer/sam/template.yaml - done - fi - done -done From 72d233a63beab5acdf559f3f35adf581fedebb65 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Mon, 30 Jun 2025 13:44:27 +0100 Subject: [PATCH 2/2] Remove v2 deployment files --- .github/workflows/publish_v2_layer.yml | 317 --------------- .github/workflows/release.yml | 376 ------------------ .../reusable_deploy_v2_layer_stack.yml | 208 ---------- .github/workflows/reusable_deploy_v2_sar.yml | 211 ---------- 4 files changed, 1112 deletions(-) delete mode 100644 .github/workflows/publish_v2_layer.yml delete mode 100644 .github/workflows/release.yml delete mode 100644 .github/workflows/reusable_deploy_v2_layer_stack.yml delete mode 100644 .github/workflows/reusable_deploy_v2_sar.yml diff --git a/.github/workflows/publish_v2_layer.yml b/.github/workflows/publish_v2_layer.yml deleted file mode 100644 index 77d785368f4..00000000000 --- a/.github/workflows/publish_v2_layer.yml +++ /dev/null @@ -1,317 +0,0 @@ -name: Deploy v2 layer to all regions - -# PROCESS -# -# 1. Compile Layer using cdk-aws-lambda-powertools-layer CDK construct for x86_64 and ARM (uses custom runner as it's CPU heavy) -# 2. Kick off pipeline for beta, prod, and canary releases -# 3. Create PR to update trunk so staged docs also point to the latest Layer ARN, when merged -# 4. Builds and publishes docs with latest Layer ARN using given version (generally coming from release) - - -# USAGE -# -# NOTE: meant to be used with ./.github/workflows/release.yml -# -# publish_layer: -# needs: [seal, release, create_tag] -# secrets: inherit -# permissions: -# id-token: write -# contents: write -# pages: write -# pull-requests: write -# uses: ./.github/workflows/publish_v2_layer.yml -# with: -# latest_published_version: ${{ needs.seal.outputs.RELEASE_VERSION }} -# pre_release: ${{ inputs.pre_release }} -# source_code_artifact_name: ${{ needs.seal.outputs.artifact_name }} -# source_code_integrity_hash: ${{ needs.seal.outputs.integrity_hash }} - - -on: - workflow_dispatch: - inputs: - latest_published_version: - description: "Latest PyPi published version to rebuild latest docs for, e.g. 2.0.0, 2.0.0a1 (pre-release)" - required: true - source_code_artifact_name: - description: "Artifact name to restore sealed source code" - type: string - required: true - source_code_integrity_hash: - description: "Sealed source code integrity hash" - type: string - required: true - pre_release: - description: "Publishes documentation using a pre-release tag (2.0.0a1)." - default: false - type: boolean - required: false - workflow_call: - inputs: - latest_published_version: - type: string - description: "Latest PyPi published version to rebuild latest docs for, e.g. 2.0.0, 2.0.0a1 (pre-release)" - required: true - pre_release: - description: "Publishes documentation using a pre-release tag (2.0.0a1)." - default: false - type: boolean - required: false - source_code_artifact_name: - description: "Artifact name to restore sealed source code" - type: string - required: true - source_code_integrity_hash: - description: "Sealed source code integrity hash" - type: string - required: true - -permissions: - contents: read - - -env: - RELEASE_COMMIT: ${{ github.sha }} - -jobs: - build-layer: - permissions: - # lower privilege propagated from parent workflow (release.yml) - contents: read - id-token: write - pages: none - pull-requests: none - runs-on: aws-powertools_ubuntu-latest_8-core - defaults: - run: - working-directory: ./layer - steps: - - name: checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ env.RELEASE_COMMIT }} - - - name: Restore sealed source code - uses: ./.github/actions/seal-restore - with: - integrity_hash: ${{ inputs.source_code_integrity_hash }} - artifact_name: ${{ inputs.source_code_artifact_name }} - - - name: Install poetry - run: pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1 - - name: Setup Node.js - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version: "16.12" - - name: Setup python - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 - with: - python-version: "3.12" - cache: "pip" - - name: Resolve and install project dependencies - # CDK spawns system python when compiling stack - # therefore it ignores both activated virtual env and cached interpreter by GH - run: | - poetry export --format requirements.txt --output requirements.txt - pip install --require-hashes -r requirements.txt - - - name: Set up QEMU - uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v2.0.0 - with: - platforms: arm64 - # NOTE: we need QEMU to build Layer against a different architecture (e.g., ARM) - - - name: Set up Docker Buildx - id: builder - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - with: - install: true - driver: docker - platforms: linux/amd64,linux/arm64 - - - name: Install CDK - working-directory: ./ - run: | - npm ci - npx cdk --version - - # Baking time for PyPi eventual consistency; 60s seemed more than enough - # https://github.com/aws-powertools/powertools-lambda-python/issues/2491 - - name: Baking time (PyPi) - run: sleep 60 - - - name: CDK build - run: npx cdk synth --verbose --context version="${{ inputs.latest_published_version }}" -o cdk.out - - name: zip output - run: zip -r cdk.out.zip cdk.out - - name: Archive CDK artifacts - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: cdk-layer-artefact - path: layer/cdk.out.zip - - beta: - needs: build-layer - # lower privilege propagated from parent workflow (release.yml) - permissions: - id-token: write - contents: read - pages: write # docs will be updated with latest Layer ARNs - pull-requests: write # creation-action will create a PR with Layer ARN updates - uses: ./.github/workflows/reusable_deploy_v2_layer_stack.yml - secrets: inherit - with: - stage: "BETA" - artefact-name: "cdk-layer-artefact" - environment: "layer-beta" - latest_published_version: ${{ inputs.latest_published_version }} - source_code_artifact_name: ${{ inputs.source_code_artifact_name }} - source_code_integrity_hash: ${{ inputs.source_code_integrity_hash }} - - prod: - needs: beta - # lower privilege propagated from parent workflow (release.yml) - permissions: - id-token: write - contents: read - pages: write # docs will be updated with latest Layer ARNs - pull-requests: write # creation-action will create a PR with Layer ARN updates - uses: ./.github/workflows/reusable_deploy_v2_layer_stack.yml - secrets: inherit - with: - stage: "PROD" - artefact-name: "cdk-layer-artefact" - environment: "layer-prod" - latest_published_version: ${{ inputs.latest_published_version }} - source_code_artifact_name: ${{ inputs.source_code_artifact_name }} - source_code_integrity_hash: ${{ inputs.source_code_integrity_hash }} - - sar-beta: - needs: beta # canaries run on Layer Beta env - permissions: - # lower privilege propagated from parent workflow (release.yml) - id-token: write - contents: read - pull-requests: none - pages: none - uses: ./.github/workflows/reusable_deploy_v2_sar.yml - secrets: inherit - with: - stage: "BETA" - artefact-name: "cdk-layer-artefact" - environment: "layer-beta" - package-version: ${{ inputs.latest_published_version }} - source_code_artifact_name: ${{ inputs.source_code_artifact_name }} - source_code_integrity_hash: ${{ inputs.source_code_integrity_hash }} - - - sar-prod: - needs: sar-beta - permissions: - # lower privilege propagated from parent workflow (release.yml) - id-token: write - contents: read - pull-requests: none - pages: none - uses: ./.github/workflows/reusable_deploy_v2_sar.yml - secrets: inherit - with: - stage: "PROD" - artefact-name: "cdk-layer-artefact" - environment: "layer-prod" - package-version: ${{ inputs.latest_published_version }} - source_code_artifact_name: ${{ inputs.source_code_artifact_name }} - source_code_integrity_hash: ${{ inputs.source_code_integrity_hash }} - - - # Updating the documentation with the latest Layer ARNs is a two-phase process - # - # 1. Update layer ARNs with latest deployed locally and create a PR with these changes - # 2. Pull from temporary branch with these changes and update the docs we're releasing - # - # This keeps our permissions tight and we don't run into a conflict, - # where a new release creates a new doc (2.16.0) while layers are still pointing to 2.15 - # because the PR has to be merged while release process is running - - update_v2_layer_arn_docs: - needs: prod - outputs: - temp_branch: ${{ steps.create-pr.outputs.temp_branch }} - runs-on: ubuntu-latest - permissions: - # lower privilege propagated from parent workflow (release.yml) - contents: write - pull-requests: write - id-token: none - pages: none - steps: - - name: Checkout repository # reusable workflows start clean, so we need to checkout again - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ env.RELEASE_COMMIT }} - - - name: Restore sealed source code - uses: ./.github/actions/seal-restore - with: - integrity_hash: ${{ inputs.source_code_integrity_hash }} - artifact_name: ${{ inputs.source_code_artifact_name }} - - - name: Download CDK layer artifacts - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - path: cdk-layer-stack - pattern: cdk-layer-stack-* # merge all Layer artifacts created per region earlier (reusable_deploy_v2_layer_stack.yml; step "Save Layer ARN artifact") - merge-multiple: true - - name: Replace layer versions in documentation - run: | - ls -la cdk-layer-stack/ - ./layer/scripts/update_layer_arn.sh cdk-layer-stack - # NOTE: It felt unnecessary creating yet another PR to update changelog w/ latest tag - # since this is the only step in the release where we update docs from a temp branch - - name: Update changelog with latest tag - run: make changelog - - name: Create PR - id: create-pr - uses: ./.github/actions/create-pr - with: - files: "docs/index.md examples CHANGELOG.md" - temp_branch_prefix: "ci-layer-docs" - pull_request_title: "chore(ci): layer docs update" - github_token: ${{ secrets.GITHUB_TOKEN }} - - - prepare_docs_alias: - runs-on: ubuntu-latest - permissions: - # lower privilege propagated from parent workflow (release.yml) - contents: read - pages: none - id-token: none - pull-requests: none - outputs: - DOCS_ALIAS: ${{ steps.set-alias.outputs.DOCS_ALIAS }} - steps: - - name: Set docs alias - id: set-alias - run: | - DOCS_ALIAS=latest - if [[ "${{ inputs.pre_release }}" == true ]] ; then - DOCS_ALIAS=alpha - fi - echo DOCS_ALIAS="$DOCS_ALIAS" >> "$GITHUB_OUTPUT" - - release_docs: - needs: [update_v2_layer_arn_docs, prepare_docs_alias] - permissions: - # lower privilege propagated from parent workflow (release.yml) - contents: write - pages: write - pull-requests: none - id-token: write - secrets: inherit - uses: ./.github/workflows/reusable_publish_docs.yml - with: - version: ${{ inputs.latest_published_version }} - alias: ${{ needs.prepare_docs_alias.outputs.DOCS_ALIAS }} - git_ref: ${{ needs.update_v2_layer_arn_docs.outputs.temp_branch }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 7beaaa8a1e5..00000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,376 +0,0 @@ -name: Release - -# RELEASE PROCESS -# -# === Automated activities === -# -# 1. [Seal] Bump to release version and export source code with integrity hash -# 2. [Quality check] Restore sealed source code, run tests, linting, security and complexity base line -# 3. [Build] Restore sealed source code, create and export hashed build artifact for PyPi release (wheel, tarball) -# 4. [Provenance] Generates provenance for build, signs attestation with GitHub OIDC claims to confirm it came from this release pipeline, commit, org, repo, branch, hash, etc. -# 5. [Release] Restore built artifact, and publish package to PyPi prod repository -# 6. [Create Tag] Restore sealed source code, create a new git tag using released version, uploads provenance to latest draft release -# 7. [PR to bump version] Restore sealed source code, and create a PR to update trunk with latest released project metadata -# 8. [Publish Layer] Compile Layer and kick off pipeline for beta, prod, and canary releases -# 9. [Publish Layer] Update docs with latest Layer ARNs and Changelog -# 10. [Publish Layer] Create PR to update trunk so staged docs also point to the latest Layer ARN, when merged -# 12. [Post release] Close all issues labeled "pending-release" and notify customers about the release -# -# === Manual activities === -# -# 1. Kick off this workflow with the intended version -# 2. Update draft release notes after this workflow completes -# 3. If not already set, use `v` as a tag, e.g., v1.26.4, and select develop as target branch - -# NOTE -# -# See MAINTAINERS.md "Releasing a new version" for release mechanisms -# -# Every job is isolated and starts a new fresh container. - -env: - RELEASE_COMMIT: ${{ github.sha }} - RELEASE_TAG_VERSION: ${{ inputs.version_to_publish }} - -on: - workflow_dispatch: - inputs: - version_to_publish: - description: "Version to be released in PyPi, Docs, and Lambda Layer, e.g. v2.0.0, v2.0.0a0 (pre-release)" - default: v2.0.0 - required: true - skip_pypi: - description: "Skip publishing to PyPi as it can't publish more than once. Useful for semi-failed releases" - default: false - type: boolean - required: false - skip_code_quality: - description: "Skip tests, linting, and baseline. Only use if release fail for reasons beyond our control and you need a quick release." - default: false - type: boolean - required: false - pre_release: - description: "Publishes documentation using a pre-release tag (v2.0.0a0). You are still responsible for passing a pre-release version tag to the workflow." - default: false - type: boolean - required: false - -permissions: - contents: read - -jobs: - - # This job bumps the package version to the release version - # creates an integrity hash from the source code - # uploads the artifact with the integrity hash as the key name - # so subsequent jobs can restore from a trusted point in time to prevent tampering - seal: - runs-on: ubuntu-latest - permissions: - contents: read - outputs: - integrity_hash: ${{ steps.seal_source_code.outputs.integrity_hash }} - artifact_name: ${{ steps.seal_source_code.outputs.artifact_name }} - RELEASE_VERSION: ${{ steps.release_version.outputs.RELEASE_VERSION }} - steps: - - name: Export release version - id: release_version - # transform tag format `v` - run: | - RELEASE_VERSION="${RELEASE_TAG_VERSION:1}" - echo "RELEASE_VERSION=${RELEASE_VERSION}" >> "$GITHUB_OUTPUT" - - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ env.RELEASE_COMMIT }} - - # We use a pinned version of Poetry to be certain it won't modify source code before we create a hash - - name: Install poetry - run: | - pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1 - pipx inject poetry git+https://github.com/monim67/poetry-bumpversion@348de6f247222e2953d649932426e63492e0a6bf # v0.3.3 - - - name: Bump package version - id: versioning - run: poetry version "${RELEASE_VERSION}" - env: - RELEASE_VERSION: ${{ steps.release_version.outputs.RELEASE_VERSION}} - - - name: Seal and upload - id: seal_source_code - uses: ./.github/actions/seal - with: - artifact_name_prefix: "source" - - # This job runs our automated test suite, complexity and security baselines - # it ensures previously merged have been tested as part of the pull request process - # - # NOTE - # - # we don't upload the artifact after testing to prevent any tampering of our source code dependencies - quality_check: - needs: seal - runs-on: ubuntu-latest - permissions: - contents: read - steps: - # NOTE: we need actions/checkout to configure git first (pre-commit hooks in make dev) - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ env.RELEASE_COMMIT }} - - - name: Restore sealed source code - uses: ./.github/actions/seal-restore - with: - integrity_hash: ${{ needs.seal.outputs.integrity_hash }} - artifact_name: ${{ needs.seal.outputs.artifact_name }} - - - name: Debug cache restore - run: cat pyproject.toml - - - name: Install poetry - run: pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1 - - name: Set up Python - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 - with: - python-version: "3.12" - cache: "poetry" - - name: Install dependencies - run: make dev - - name: Run all tests, linting and baselines - run: make pr - - # This job creates a release artifact (tar.gz, wheel) - # it checks out code from release commit for custom actions to work - # then restores the sealed source code (overwrites any potential tampering) - # it's done separately from release job to enforce least privilege. - # We export just the final build artifact for release - build: - runs-on: ubuntu-latest - needs: [quality_check, seal] - permissions: - contents: read - outputs: - integrity_hash: ${{ steps.seal_build.outputs.integrity_hash }} - artifact_name: ${{ steps.seal_build.outputs.artifact_name }} - attestation_hashes: ${{ steps.encoded_hash.outputs.attestation_hashes }} - steps: - # NOTE: we need actions/checkout to configure git first (pre-commit hooks in make dev) - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ env.RELEASE_COMMIT }} - - - name: Restore sealed source code - uses: ./.github/actions/seal-restore - with: - integrity_hash: ${{ needs.seal.outputs.integrity_hash }} - artifact_name: ${{ needs.seal.outputs.artifact_name }} - - - name: Install poetry - run: pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1 - - name: Set up Python - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 - with: - python-version: "3.12" - cache: "poetry" - - - name: Build python package and wheel - run: poetry build - - - name: Seal and upload - id: seal_build - uses: ./.github/actions/seal - with: - artifact_name_prefix: "build" - files: "dist/" - - # NOTE: SLSA retraces our build to its artifact to ensure it wasn't tampered - # coupled with GitHub OIDC, SLSA can then confidently sign it came from this release pipeline+commit+branch+org+repo+actor+integrity hash - - name: Create attestation encoded hash for provenance - id: encoded_hash - working-directory: dist - run: echo "attestation_hashes=$(sha256sum ./* | base64 -w0)" >> "$GITHUB_OUTPUT" - - # This job creates a provenance file that describes how our release was built (all steps) - # after it verifies our build is reproducible within the same pipeline - # it confirms that its own software and the CI build haven't been tampered with (Trust but verify) - # lastly, it creates and sign an attestation (multiple.intoto.jsonl) that confirms - # this build artifact came from this GitHub org, branch, actor, commit ID, inputs that triggered this pipeline, and matches its integrity hash - # NOTE: supply chain threats review (we protect against all of them now): https://slsa.dev/spec/v1.0/threats-overview - provenance: - needs: [seal, build] - permissions: - contents: write # nested job explicitly require despite upload assets being set to false - actions: read # To read the workflow path. - id-token: write # To sign the provenance. - # NOTE: provenance fails if we use action pinning... it's a Github limitation - # because SLSA needs to trace & attest it came from a given branch; pinning doesn't expose that information - # https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md#referencing-the-slsa-generator - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 - with: - base64-subjects: ${{ needs.build.outputs.attestation_hashes }} - upload-assets: false # we upload its attestation in create_tag job, otherwise it creates a new release - - # This job uses release artifact to publish to PyPi - # it exchanges JWT tokens with GitHub to obtain PyPi credentials - # since it's already registered as a Trusted Publisher. - # It uses the sealed build artifact (.whl, .tar.gz) to release it - release: - needs: [build, seal, provenance] - environment: release - runs-on: ubuntu-latest - permissions: - id-token: write # OIDC for PyPi Trusted Publisher feature - env: - RELEASE_VERSION: ${{ needs.seal.outputs.RELEASE_VERSION }} - steps: - # NOTE: we need actions/checkout in order to use our local actions (e.g., ./.github/actions) - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ env.RELEASE_COMMIT }} - - - name: Restore sealed source code - uses: ./.github/actions/seal-restore - with: - integrity_hash: ${{ needs.build.outputs.integrity_hash }} - artifact_name: ${{ needs.build.outputs.artifact_name }} - - - name: Upload to PyPi prod - if: ${{ !inputs.skip_pypi }} - uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4 - - # PyPi test maintenance affected us numerous times, leaving for history purposes - # - name: Upload to PyPi test - # if: ${{ !inputs.skip_pypi }} - # uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4 - # with: - # repository-url: https://test.pypi.org/legacy/ - - # We create a Git Tag using our release version (e.g., v2.16.0) - # using our sealed source code we created earlier. - # Because we bumped version of our project as part of CI - # we need to add this into git before pushing the tag - # otherwise the release commit will be used as the basis for the tag. - # Later, we create a PR to update trunk with our newest release version (e.g., bump_version job) - create_tag: - needs: [release, seal, provenance] - runs-on: ubuntu-latest - permissions: - contents: write - steps: - # NOTE: we need actions/checkout to authenticate and configure git first - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ env.RELEASE_COMMIT }} - - - name: Restore sealed source code - uses: ./.github/actions/seal-restore - with: - integrity_hash: ${{ needs.seal.outputs.integrity_hash }} - artifact_name: ${{ needs.seal.outputs.artifact_name }} - - - id: setup-git - name: Git client setup and refresh tip - run: | - git config user.name "Powertools for AWS Lambda (Python) bot" - git config user.email "151832416+aws-powertools-bot@users.noreply.github.com" - git config remote.origin.url >&- - - - name: Create Git Tag - run: | - git add pyproject.toml aws_lambda_powertools/shared/version.py - git commit -m "chore: version bump" - git tag -a v"${RELEASE_VERSION}" -m "release_version: v${RELEASE_VERSION}" - git push origin v"${RELEASE_VERSION}" - env: - RELEASE_VERSION: ${{ needs.seal.outputs.RELEASE_VERSION }} - - - name: Upload provenance - id: upload-provenance - uses: ./.github/actions/upload-release-provenance - with: - release_version: ${{ needs.seal.outputs.RELEASE_VERSION }} - provenance_name: ${{needs.provenance.outputs.provenance-name}} - github_token: ${{ secrets.GITHUB_TOKEN }} - - # Creates a PR with the latest version we've just released - # since our trunk is protected against any direct pushes from automation - bump_version: - needs: [release, seal] - permissions: - contents: write # create-pr action creates a temporary branch - pull-requests: write # create-pr action creates a PR using the temporary branch - runs-on: ubuntu-latest - steps: - # NOTE: we need actions/checkout to authenticate and configure git first - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ env.RELEASE_COMMIT }} - - - name: Restore sealed source code - uses: ./.github/actions/seal-restore - with: - integrity_hash: ${{ needs.seal.outputs.integrity_hash }} - artifact_name: ${{ needs.seal.outputs.artifact_name }} - - - name: Create PR - id: create-pr - uses: ./.github/actions/create-pr - with: - files: "pyproject.toml aws_lambda_powertools/shared/version.py" - temp_branch_prefix: "ci-bump" - pull_request_title: "chore(ci): bump version to ${{ needs.seal.outputs.RELEASE_VERSION }}" - github_token: ${{ secrets.GITHUB_TOKEN }} - - # This job compiles a Lambda Layer optimized for space and speed (e.g., Cython) - # It then deploys to Layer's Beta and Prod account, including SAR Beta and Prod account. - # It uses canaries to attest Layers can be used and imported between stages. - # Lastly, it updates our documentation with the latest Layer ARN for all regions - # - # NOTE - # - # Watch out for the depth limit of 4 nested workflow_calls. - # publish_layer -> publish_v2_layer -> reusable_deploy_v2_layer_stack - publish_layer: - needs: [seal, release, create_tag] - secrets: inherit - permissions: - id-token: write - contents: write - pages: write - pull-requests: write - uses: ./.github/workflows/publish_v2_layer.yml - with: - latest_published_version: ${{ needs.seal.outputs.RELEASE_VERSION }} - pre_release: ${{ inputs.pre_release }} - source_code_artifact_name: ${{ needs.seal.outputs.artifact_name }} - source_code_integrity_hash: ${{ needs.seal.outputs.integrity_hash }} - - post_release: - needs: [seal, release, publish_layer] - permissions: - contents: read - issues: write - discussions: write - pull-requests: write - runs-on: ubuntu-latest - env: - RELEASE_VERSION: ${{ needs.seal.outputs.RELEASE_VERSION }} - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ env.RELEASE_COMMIT }} - - - name: Restore sealed source code - uses: ./.github/actions/seal-restore - with: - integrity_hash: ${{ needs.seal.outputs.integrity_hash }} - artifact_name: ${{ needs.seal.outputs.artifact_name }} - - - name: Close issues related to this release - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const post_release = require('.github/scripts/post_release.js') - await post_release({github, context, core}) diff --git a/.github/workflows/reusable_deploy_v2_layer_stack.yml b/.github/workflows/reusable_deploy_v2_layer_stack.yml deleted file mode 100644 index 6415e406489..00000000000 --- a/.github/workflows/reusable_deploy_v2_layer_stack.yml +++ /dev/null @@ -1,208 +0,0 @@ -name: Deploy CDK Layer v2 stack - -# PROCESS -# -# 1. Split what AWS regions support ARM vs regions that Lambda support ARM -# 2. Deploy previously built layer for each AWS commercial region -# 3. Export all published Layers as JSON -# 4. Deploy Canaries to every deployed region to test whether Powertools can be imported etc. - -# USAGE -# -# NOTE: meant to be used with ./.github/workflows/publish_v2_layer.yml -# -# beta: -# needs: build-layer -# # lower privilege propagated from parent workflow (release.yml) -# permissions: -# id-token: write -# contents: read -# pages: write # docs will be updated with latest Layer ARNs -# pull-requests: write # creation-action will create a PR with Layer ARN updates -# uses: ./.github/workflows/reusable_deploy_v2_layer_stack.yml -# secrets: inherit -# with: -# stage: "BETA" -# artefact-name: "cdk-layer-artefact" -# environment: "layer-beta" -# latest_published_version: ${{ inputs.latest_published_version }} - -on: - workflow_call: - inputs: - stage: - description: "Deployment stage (BETA, PROD)" - required: true - type: string - artefact-name: - description: "CDK Layer Artefact name to download" - required: true - type: string - environment: - description: "GitHub Environment to use for encrypted secrets" - required: true - type: string - latest_published_version: - description: "Latest version that is published" - required: true - type: string - source_code_artifact_name: - description: "Artifact name to restore sealed source code" - type: string - required: true - source_code_integrity_hash: - description: "Sealed source code integrity hash" - type: string - required: true - -permissions: - contents: read - -env: - RELEASE_COMMIT: ${{ github.sha }} # it gets propagated from the caller for security reasons - -jobs: - deploy-cdk-stack: - runs-on: ubuntu-latest - environment: ${{ inputs.environment }} - # lower privilege propagated from parent workflow (publish_v2_layer.yml) - permissions: - id-token: write - pull-requests: none - contents: read - pages: none - defaults: - run: - working-directory: ./layer - strategy: - fail-fast: false - matrix: - # To get a list of current regions, use: - # aws ec2 describe-regions --all-regions --query "Regions[].RegionName" --output text | tr "\t" "\n" | sort - include: - - region: "af-south-1" - has_arm64_support: "true" - - region: "ap-east-1" - has_arm64_support: "true" - - region: "ap-northeast-1" - has_arm64_support: "true" - - region: "ap-northeast-2" - has_arm64_support: "true" - - region: "ap-northeast-3" - has_arm64_support: "true" - - region: "ap-south-1" - has_arm64_support: "true" - - region: "ap-south-2" - has_arm64_support: "true" - - region: "ap-southeast-1" - has_arm64_support: "true" - - region: "ap-southeast-2" - has_arm64_support: "true" - - region: "ap-southeast-3" - has_arm64_support: "true" - - region: "ap-southeast-4" - has_arm64_support: "true" - - region: "ca-central-1" - has_arm64_support: "true" - - region: "ca-west-1" - has_arm64_support: "true" - - region: "eu-central-1" - has_arm64_support: "true" - - region: "eu-central-2" - has_arm64_support: "true" - - region: "eu-north-1" - has_arm64_support: "true" - - region: "eu-south-1" - has_arm64_support: "true" - - region: "eu-south-2" - has_arm64_support: "true" - - region: "eu-west-1" - has_arm64_support: "true" - - region: "eu-west-2" - has_arm64_support: "true" - - region: "eu-west-3" - has_arm64_support: "true" - - region: "il-central-1" - has_arm64_support: "true" - - region: "me-central-1" - has_arm64_support: "true" - - region: "me-south-1" - has_arm64_support: "true" - - region: "sa-east-1" - has_arm64_support: "true" - - region: "us-east-1" - has_arm64_support: "true" - - region: "us-east-2" - has_arm64_support: "true" - - region: "us-west-1" - has_arm64_support: "true" - - region: "us-west-2" - has_arm64_support: "true" - steps: - - name: checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ env.RELEASE_COMMIT }} - - - name: Restore sealed source code - uses: ./.github/actions/seal-restore - with: - integrity_hash: ${{ inputs.source_code_integrity_hash }} - artifact_name: ${{ inputs.source_code_artifact_name }} - - - name: Install poetry - run: pipx install git+https://github.com/python-poetry/poetry@bd500dd3bdfaec3de6894144c9cedb3a9358be84 # v2.0.1 - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1 - with: - aws-region: ${{ matrix.region }} - role-to-assume: ${{ secrets.AWS_LAYERS_ROLE_ARN }} - mask-aws-account-id: true - - name: Setup Node.js - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version: "16.12" - - name: Setup python - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 - with: - python-version: "3.12" - cache: "pip" - - name: Resolve and install project dependencies - # CDK spawns system python when compiling stack - # therefore it ignores both activated virtual env and cached interpreter by GH - run: | - poetry export --format requirements.txt --output requirements.txt - pip install --require-hashes -r requirements.txt - - name: install cdk and deps - working-directory: ./ - run: | - npm ci - npx cdk --version - - name: install deps - run: poetry install - - name: Download artifact - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: ${{ inputs.artefact-name }} - path: layer - - name: unzip artefact - run: unzip cdk.out.zip - - name: CDK Deploy Layer - run: npx cdk deploy --app cdk.out --context region=${{ matrix.region }} --parameters HasARM64Support=${{ matrix.has_arm64_support }} 'LayerV2Stack' --require-approval never --verbose --outputs-file cdk-outputs.json - - name: Store latest Layer ARN - if: ${{ inputs.stage == 'PROD' }} - run: | - mkdir cdk-layer-stack - jq -r -c '.LayerV2Stack.LatestLayerArn' cdk-outputs.json > cdk-layer-stack/${{ matrix.region }}-layer-version.txt - jq -r -c '.LayerV2Stack.LatestLayerArm64Arn' cdk-outputs.json >> cdk-layer-stack/${{ matrix.region }}-layer-version.txt - cat cdk-layer-stack/${{ matrix.region }}-layer-version.txt - - name: Save Layer ARN artifact - if: ${{ inputs.stage == 'PROD' }} - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: cdk-layer-stack-${{ matrix.region }} - path: ./layer/cdk-layer-stack/* # NOTE: upload-artifact does not inherit working-directory setting. - if-no-files-found: error - retention-days: 1 - - name: CDK Deploy Canary - run: npx cdk deploy --app cdk.out --context region=${{ matrix.region }} --parameters DeployStage="${{ inputs.stage }}" --parameters HasARM64Support=${{ matrix.has_arm64_support }} 'CanaryV2Stack' --require-approval never --verbose diff --git a/.github/workflows/reusable_deploy_v2_sar.yml b/.github/workflows/reusable_deploy_v2_sar.yml deleted file mode 100644 index e3ac2cc57ae..00000000000 --- a/.github/workflows/reusable_deploy_v2_sar.yml +++ /dev/null @@ -1,211 +0,0 @@ -name: Deploy V2 SAR - -# PROCESS -# -# 1. This workflow starts after the layer artifact is produced on `publish_v2_layer` -# 2. We use the same layer artifact to ensure the SAR app is consistent with the published Lambda Layer -# 3. We publish the SAR for both x86_64 and arm64 (see `matrix` section) -# 4. We use `sam package` and `sam publish` to publish the SAR app -# 5. We remove the previous Canary stack (if present) and deploy a new one to test the SAR App. We retain the Canary in the account for debugging purposes -# 6. Finally the published SAR app is made public on the PROD environment - -# USAGE -# -# NOTE: meant to be used with ./.github/workflows/publish_v2_layer.yml -# -# sar-beta: -# needs: build-layer -# permissions: -# # lower privilege propagated from parent workflow (release.yml) -# id-token: write -# contents: read -# pull-requests: none -# pages: none -# uses: ./.github/workflows/reusable_deploy_v2_sar.yml -# secrets: inherit -# with: -# stage: "BETA" -# artefact-name: "cdk-layer-artefact" -# environment: "layer-beta" -# package-version: ${{ inputs.latest_published_version }} -# source_code_artifact_name: ${{ inputs.source_code_artifact_name }} -# source_code_integrity_hash: ${{ inputs.source_code_integrity_hash }} - -permissions: - id-token: write - contents: read - -env: - NODE_VERSION: 16.12 - AWS_REGION: eu-west-1 - SAR_NAME: aws-lambda-powertools-python-layer - TEST_STACK_NAME: serverlessrepo-v2-powertools-layer-test-stack - RELEASE_COMMIT: ${{ github.sha }} # it gets propagated from the caller for security reasons - -on: - workflow_call: - inputs: - stage: - description: "Deployment stage (BETA, PROD)" - required: true - type: string - artefact-name: - description: "CDK Layer Artefact name to download" - required: true - type: string - package-version: - description: "The version of the package to deploy" - required: true - type: string - environment: - description: "GitHub Environment to use for encrypted secrets" - required: true - type: string - source_code_artifact_name: - description: "Artifact name to restore sealed source code" - type: string - required: true - source_code_integrity_hash: - description: "Sealed source code integrity hash" - type: string - required: true - -jobs: - deploy-sar-app: - runs-on: ubuntu-latest - environment: ${{ inputs.environment }} - strategy: - matrix: - architecture: ["x86_64", "arm64"] - steps: - - name: checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ env.RELEASE_COMMIT }} - - - name: Restore sealed source code - uses: ./.github/actions/seal-restore - with: - integrity_hash: ${{ inputs.source_code_integrity_hash }} - artifact_name: ${{ inputs.source_code_artifact_name }} - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1 - with: - aws-region: ${{ env.AWS_REGION }} - role-to-assume: ${{ secrets.AWS_LAYERS_ROLE_ARN }} - mask-aws-account-id: true - - # NOTE - # We connect to Layers account to log our intent to publish a SAR Layer - # we then jump to our specific SAR Account with the correctly scoped IAM Role - # this allows us to have a single trail when a release occurs for a given layer (beta+prod+SAR beta+SAR prod) - - name: AWS credentials SAR role - uses: aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1 - id: aws-credentials-sar-role - with: - aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY }} - aws-session-token: ${{ env.AWS_SESSION_TOKEN }} - role-duration-seconds: 1200 - aws-region: ${{ env.AWS_REGION }} - role-to-assume: ${{ secrets.AWS_SAR_V2_ROLE_ARN }} - mask-aws-account-id: true - - - name: Setup Node.js - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version: ${{ env.NODE_VERSION }} - - name: Download artifact - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: ${{ inputs.artefact-name }} - - name: Unzip artefact - run: unzip cdk.out.zip - - name: Configure SAR name - run: | - if [[ "${{ inputs.stage }}" == "BETA" ]]; then - SAR_NAME="test-${SAR_NAME}" - fi - echo SAR_NAME="${SAR_NAME}" >> "$GITHUB_ENV" - - name: Adds arm64 suffix to SAR name - if: ${{ matrix.architecture == 'arm64' }} - run: echo SAR_NAME="${SAR_NAME}-arm64" >> "$GITHUB_ENV" - - name: Normalize semantic version - id: semantic-version # v2.0.0a0 -> v2.0.0-a0 - env: - VERSION: ${{ inputs.package-version }} - run: | - VERSION="${VERSION/a/-a}" - echo "VERSION=${VERSION}" >> "$GITHUB_OUTPUT" - - name: Prepare SAR App - env: - VERSION: ${{ steps.semantic-version.outputs.VERSION }} - run: | - # From the generated LayerStack cdk.out artifact, find the layer asset path for the correct architecture. - # We'll use this as the source directory of our SAR. This way we are re-using the same layer asset for our SAR. - asset=$(jq -jc '.Resources[] | select(.Properties.CompatibleArchitectures == ["${{ matrix.architecture }}"]) | .Metadata."aws:asset:path"' cdk.out/LayerV2Stack.template.json) - - # fill in the SAR SAM template - sed \ - -e "s||${VERSION}|g" \ - -e "s//${{ env.SAR_NAME }}/g" \ - -e "s||./cdk.out/$asset|g" \ - layer/sar/template.txt > template.yml - - # SAR needs a README and a LICENSE, so just copy the ones from the repo - cp README.md LICENSE "./cdk.out/$asset/" - - # Debug purposes - cat template.yml - - name: Deploy SAR - run: | - # Package the SAR to our SAR S3 bucket, and publish it - sam package --template-file template.yml --output-template-file packaged.yml --s3-bucket ${{ secrets.AWS_SAR_S3_BUCKET }} - sam publish --template packaged.yml --region "$AWS_REGION" - - name: Deploy BETA canary - if: ${{ inputs.stage == 'BETA' }} - run: | - if [[ "${{ matrix.architecture }}" == "arm64" ]]; then - TEST_STACK_NAME="${TEST_STACK_NAME}-arm64" - fi - - echo "Check if stack does not exist" - stack_exists=$(aws cloudformation list-stacks --query "StackSummaries[?(StackName == '$TEST_STACK_NAME' && StackStatus == 'CREATE_COMPLETE')].{StackId:StackId, StackName:StackName, CreationTime:CreationTime, StackStatus:StackStatus}" --output text) - - if [[ -n "$stack_exists" ]] ; then - echo "Found test deployment stack, removing..." - aws cloudformation delete-stack --stack-name "$TEST_STACK_NAME" - aws cloudformation wait stack-delete-complete --stack-name "$TEST_STACK_NAME" - fi - - echo "Creating canary stack" - echo "Stack name: $TEST_STACK_NAME" - aws serverlessrepo create-cloud-formation-change-set \ - --application-id arn:aws:serverlessrepo:${{ env.AWS_REGION }}:${{ steps.aws-credentials-sar-role.outputs.aws-account-id }}:applications/${{ env.SAR_NAME }} \ - --stack-name "${TEST_STACK_NAME/serverlessrepo-/}" \ - --capabilities CAPABILITY_NAMED_IAM - - CHANGE_SET_ID=$(aws cloudformation list-change-sets --stack-name "$TEST_STACK_NAME" --query 'Summaries[*].ChangeSetId' --output text) - aws cloudformation wait change-set-create-complete --change-set-name "$CHANGE_SET_ID" - aws cloudformation execute-change-set --change-set-name "$CHANGE_SET_ID" - aws cloudformation wait stack-create-complete --stack-name "$TEST_STACK_NAME" - - echo "Waiting until stack deployment completes..." - - echo "Exit with error if stack is not in CREATE_COMPLETE" - stack_exists=$(aws cloudformation list-stacks --query "StackSummaries[?(StackName == '$TEST_STACK_NAME' && StackStatus == 'CREATE_COMPLETE')].{StackId:StackId, StackName:StackName, CreationTime:CreationTime, StackStatus:StackStatus}") - if [[ -z "$stack_exists" ]] ; then - echo "Could find successful deployment, exit error..." - exit 1 - fi - echo "Deployment successful" - - name: Publish SAR - if: ${{ inputs.stage == 'PROD' }} - run: | - # wait until SAR registers the app, otherwise it fails to make it public - sleep 15 - echo "Make SAR app public" - aws serverlessrepo put-application-policy \ - --application-id arn:aws:serverlessrepo:${{ env.AWS_REGION }}:${{ steps.aws-credentials-sar-role.outputs.aws-account-id }}:applications/${{ env.SAR_NAME }} \ - --statements Principals='*',Actions=Deploy