diff --git a/docs/environment/variables.mdx b/docs/environment/variables.mdx
index e76c469b2..4c634bd53 100644
--- a/docs/environment/variables.mdx
+++ b/docs/environment/variables.mdx
@@ -60,6 +60,8 @@ aws ssm put-parameter --region us-east-1 --name '//my-app\my-parameter' --type S
It is recommended to prefix the parameter name with your application name, for example: `/my-app/my-parameter`.
+SSM also allows to store a SecureString parameter, which is encrypted with AWS KMS. To use a SecureString, simply change the `--type` argument to `--type SecureString`. Bref takes care of decrypting the value.
+
### Retrieving secrets
You can inject a secret in an environment variable:
diff --git a/layers.json b/layers.json
index 14f14e2bf..b14462807 100644
--- a/layers.json
+++ b/layers.json
@@ -1,410 +1,410 @@
{
"php-83": {
- "ca-central-1": "6",
- "eu-central-1": "6",
- "eu-north-1": "6",
- "eu-west-1": "6",
- "eu-west-2": "6",
- "eu-west-3": "6",
- "sa-east-1": "6",
- "us-east-1": "6",
- "us-east-2": "6",
- "us-west-1": "6",
- "us-west-2": "6",
- "ap-east-1": "6",
- "ap-south-1": "6",
- "ap-northeast-1": "6",
- "ap-northeast-2": "6",
- "ap-northeast-3": "6",
- "ap-southeast-1": "6",
- "ap-southeast-2": "6",
- "eu-south-1": "6",
- "eu-south-2": "6",
- "af-south-1": "6",
- "me-south-1": "6"
+ "ca-central-1": "13",
+ "eu-central-1": "13",
+ "eu-north-1": "13",
+ "eu-west-1": "13",
+ "eu-west-2": "13",
+ "eu-west-3": "13",
+ "sa-east-1": "13",
+ "us-east-1": "13",
+ "us-east-2": "13",
+ "us-west-1": "13",
+ "us-west-2": "13",
+ "ap-east-1": "13",
+ "ap-south-1": "13",
+ "ap-northeast-1": "13",
+ "ap-northeast-2": "13",
+ "ap-northeast-3": "13",
+ "ap-southeast-1": "13",
+ "ap-southeast-2": "13",
+ "eu-south-1": "13",
+ "eu-south-2": "13",
+ "af-south-1": "13",
+ "me-south-1": "13"
},
"php-83-fpm": {
- "ca-central-1": "6",
- "eu-central-1": "6",
- "eu-north-1": "6",
- "eu-west-1": "6",
- "eu-west-2": "6",
- "eu-west-3": "6",
- "sa-east-1": "6",
- "us-east-1": "6",
- "us-east-2": "6",
- "us-west-1": "6",
- "us-west-2": "6",
- "ap-east-1": "6",
- "ap-south-1": "6",
- "ap-northeast-1": "6",
- "ap-northeast-2": "6",
- "ap-northeast-3": "6",
- "ap-southeast-1": "6",
- "ap-southeast-2": "6",
- "eu-south-1": "6",
- "eu-south-2": "6",
- "af-south-1": "6",
- "me-south-1": "6"
+ "ca-central-1": "13",
+ "eu-central-1": "13",
+ "eu-north-1": "13",
+ "eu-west-1": "13",
+ "eu-west-2": "13",
+ "eu-west-3": "13",
+ "sa-east-1": "13",
+ "us-east-1": "13",
+ "us-east-2": "13",
+ "us-west-1": "13",
+ "us-west-2": "13",
+ "ap-east-1": "13",
+ "ap-south-1": "13",
+ "ap-northeast-1": "13",
+ "ap-northeast-2": "13",
+ "ap-northeast-3": "13",
+ "ap-southeast-1": "13",
+ "ap-southeast-2": "13",
+ "eu-south-1": "13",
+ "eu-south-2": "13",
+ "af-south-1": "13",
+ "me-south-1": "13"
},
"php-82": {
- "ca-central-1": "50",
- "eu-central-1": "50",
- "eu-north-1": "50",
- "eu-west-1": "50",
- "eu-west-2": "50",
- "eu-west-3": "50",
- "sa-east-1": "50",
- "us-east-1": "50",
- "us-east-2": "50",
- "us-west-1": "50",
- "us-west-2": "50",
- "ap-east-1": "50",
- "ap-south-1": "50",
- "ap-northeast-1": "50",
- "ap-northeast-2": "50",
- "ap-northeast-3": "50",
- "ap-southeast-1": "50",
- "ap-southeast-2": "50",
- "eu-south-1": "50",
- "eu-south-2": "49",
- "af-south-1": "50",
- "me-south-1": "50"
+ "ca-central-1": "57",
+ "eu-central-1": "57",
+ "eu-north-1": "57",
+ "eu-west-1": "57",
+ "eu-west-2": "57",
+ "eu-west-3": "57",
+ "sa-east-1": "57",
+ "us-east-1": "57",
+ "us-east-2": "57",
+ "us-west-1": "57",
+ "us-west-2": "57",
+ "ap-east-1": "57",
+ "ap-south-1": "57",
+ "ap-northeast-1": "57",
+ "ap-northeast-2": "57",
+ "ap-northeast-3": "57",
+ "ap-southeast-1": "57",
+ "ap-southeast-2": "57",
+ "eu-south-1": "57",
+ "eu-south-2": "56",
+ "af-south-1": "57",
+ "me-south-1": "57"
},
"php-82-fpm": {
- "ca-central-1": "50",
- "eu-central-1": "50",
- "eu-north-1": "50",
- "eu-west-1": "50",
- "eu-west-2": "50",
- "eu-west-3": "50",
- "sa-east-1": "50",
- "us-east-1": "50",
- "us-east-2": "50",
- "us-west-1": "50",
- "us-west-2": "50",
- "ap-east-1": "50",
- "ap-south-1": "50",
- "ap-northeast-1": "50",
- "ap-northeast-2": "50",
- "ap-northeast-3": "50",
- "ap-southeast-1": "50",
- "ap-southeast-2": "50",
- "eu-south-1": "50",
- "eu-south-2": "49",
- "af-south-1": "50",
- "me-south-1": "50"
+ "ca-central-1": "57",
+ "eu-central-1": "57",
+ "eu-north-1": "57",
+ "eu-west-1": "57",
+ "eu-west-2": "57",
+ "eu-west-3": "57",
+ "sa-east-1": "57",
+ "us-east-1": "57",
+ "us-east-2": "57",
+ "us-west-1": "57",
+ "us-west-2": "57",
+ "ap-east-1": "57",
+ "ap-south-1": "57",
+ "ap-northeast-1": "57",
+ "ap-northeast-2": "57",
+ "ap-northeast-3": "57",
+ "ap-southeast-1": "57",
+ "ap-southeast-2": "57",
+ "eu-south-1": "57",
+ "eu-south-2": "56",
+ "af-south-1": "57",
+ "me-south-1": "57"
},
"php-81": {
- "ca-central-1": "61",
- "eu-central-1": "61",
- "eu-north-1": "61",
- "eu-west-1": "61",
- "eu-west-2": "61",
- "eu-west-3": "61",
- "sa-east-1": "61",
- "us-east-1": "61",
- "us-east-2": "61",
- "us-west-1": "61",
- "us-west-2": "61",
- "ap-east-1": "53",
- "ap-south-1": "60",
- "ap-northeast-1": "60",
- "ap-northeast-2": "60",
- "ap-northeast-3": "60",
- "ap-southeast-1": "60",
- "ap-southeast-2": "60",
- "eu-south-1": "53",
- "eu-south-2": "50",
- "af-south-1": "53",
- "me-south-1": "53"
+ "ca-central-1": "68",
+ "eu-central-1": "68",
+ "eu-north-1": "68",
+ "eu-west-1": "68",
+ "eu-west-2": "68",
+ "eu-west-3": "68",
+ "sa-east-1": "68",
+ "us-east-1": "68",
+ "us-east-2": "68",
+ "us-west-1": "68",
+ "us-west-2": "68",
+ "ap-east-1": "60",
+ "ap-south-1": "67",
+ "ap-northeast-1": "67",
+ "ap-northeast-2": "67",
+ "ap-northeast-3": "67",
+ "ap-southeast-1": "67",
+ "ap-southeast-2": "67",
+ "eu-south-1": "60",
+ "eu-south-2": "57",
+ "af-south-1": "60",
+ "me-south-1": "60"
},
"php-81-fpm": {
- "ca-central-1": "60",
- "eu-central-1": "60",
- "eu-north-1": "61",
- "eu-west-1": "61",
- "eu-west-2": "60",
- "eu-west-3": "60",
- "sa-east-1": "60",
- "us-east-1": "61",
- "us-east-2": "60",
- "us-west-1": "60",
- "us-west-2": "61",
- "ap-east-1": "53",
- "ap-south-1": "59",
- "ap-northeast-1": "60",
- "ap-northeast-2": "59",
- "ap-northeast-3": "59",
- "ap-southeast-1": "59",
- "ap-southeast-2": "59",
- "eu-south-1": "52",
- "eu-south-2": "49",
- "af-south-1": "52",
- "me-south-1": "52"
+ "ca-central-1": "67",
+ "eu-central-1": "67",
+ "eu-north-1": "68",
+ "eu-west-1": "68",
+ "eu-west-2": "67",
+ "eu-west-3": "67",
+ "sa-east-1": "67",
+ "us-east-1": "68",
+ "us-east-2": "67",
+ "us-west-1": "67",
+ "us-west-2": "68",
+ "ap-east-1": "60",
+ "ap-south-1": "66",
+ "ap-northeast-1": "67",
+ "ap-northeast-2": "66",
+ "ap-northeast-3": "66",
+ "ap-southeast-1": "66",
+ "ap-southeast-2": "66",
+ "eu-south-1": "59",
+ "eu-south-2": "56",
+ "af-south-1": "59",
+ "me-south-1": "59"
},
"php-80": {
- "ca-central-1": "64",
- "eu-central-1": "63",
- "eu-north-1": "64",
- "eu-west-1": "64",
- "eu-west-2": "64",
- "eu-west-3": "64",
- "sa-east-1": "64",
- "us-east-1": "64",
- "us-east-2": "64",
- "us-west-1": "64",
- "us-west-2": "64",
- "ap-east-1": "54",
- "ap-south-1": "63",
- "ap-northeast-1": "61",
- "ap-northeast-2": "60",
- "ap-northeast-3": "61",
- "ap-southeast-1": "60",
- "ap-southeast-2": "62",
- "eu-south-1": "54",
- "eu-south-2": "50",
- "af-south-1": "54",
- "me-south-1": "54"
+ "ca-central-1": "71",
+ "eu-central-1": "70",
+ "eu-north-1": "71",
+ "eu-west-1": "71",
+ "eu-west-2": "71",
+ "eu-west-3": "71",
+ "sa-east-1": "71",
+ "us-east-1": "71",
+ "us-east-2": "71",
+ "us-west-1": "71",
+ "us-west-2": "71",
+ "ap-east-1": "61",
+ "ap-south-1": "70",
+ "ap-northeast-1": "68",
+ "ap-northeast-2": "67",
+ "ap-northeast-3": "68",
+ "ap-southeast-1": "67",
+ "ap-southeast-2": "69",
+ "eu-south-1": "61",
+ "eu-south-2": "57",
+ "af-south-1": "61",
+ "me-south-1": "61"
},
"php-80-fpm": {
- "ca-central-1": "61",
- "eu-central-1": "61",
- "eu-north-1": "61",
- "eu-west-1": "61",
- "eu-west-2": "61",
- "eu-west-3": "61",
- "sa-east-1": "61",
- "us-east-1": "61",
- "us-east-2": "61",
- "us-west-1": "61",
- "us-west-2": "61",
- "ap-east-1": "53",
- "ap-south-1": "60",
- "ap-northeast-1": "60",
- "ap-northeast-2": "60",
- "ap-northeast-3": "60",
- "ap-southeast-1": "60",
- "ap-southeast-2": "60",
- "eu-south-1": "53",
- "eu-south-2": "50",
- "af-south-1": "53",
- "me-south-1": "53"
+ "ca-central-1": "68",
+ "eu-central-1": "68",
+ "eu-north-1": "68",
+ "eu-west-1": "68",
+ "eu-west-2": "68",
+ "eu-west-3": "68",
+ "sa-east-1": "68",
+ "us-east-1": "68",
+ "us-east-2": "68",
+ "us-west-1": "68",
+ "us-west-2": "68",
+ "ap-east-1": "60",
+ "ap-south-1": "67",
+ "ap-northeast-1": "67",
+ "ap-northeast-2": "67",
+ "ap-northeast-3": "67",
+ "ap-southeast-1": "67",
+ "ap-southeast-2": "67",
+ "eu-south-1": "60",
+ "eu-south-2": "57",
+ "af-south-1": "60",
+ "me-south-1": "60"
},
"arm-php-83": {
- "ca-central-1": "6",
- "eu-central-1": "6",
- "eu-north-1": "6",
- "eu-west-1": "6",
- "eu-west-2": "6",
- "eu-west-3": "6",
- "sa-east-1": "6",
- "us-east-1": "6",
- "us-east-2": "6",
- "us-west-1": "6",
- "us-west-2": "6",
- "ap-east-1": "6",
- "ap-south-1": "6",
- "ap-northeast-1": "6",
- "ap-northeast-2": "6",
- "ap-northeast-3": "6",
- "ap-southeast-1": "6",
- "ap-southeast-2": "6",
- "eu-south-1": "6",
- "eu-south-2": "6",
- "af-south-1": "6",
- "me-south-1": "6"
+ "ca-central-1": "13",
+ "eu-central-1": "13",
+ "eu-north-1": "13",
+ "eu-west-1": "13",
+ "eu-west-2": "13",
+ "eu-west-3": "13",
+ "sa-east-1": "13",
+ "us-east-1": "13",
+ "us-east-2": "13",
+ "us-west-1": "13",
+ "us-west-2": "13",
+ "ap-east-1": "13",
+ "ap-south-1": "13",
+ "ap-northeast-1": "13",
+ "ap-northeast-2": "13",
+ "ap-northeast-3": "13",
+ "ap-southeast-1": "13",
+ "ap-southeast-2": "13",
+ "eu-south-1": "13",
+ "eu-south-2": "13",
+ "af-south-1": "13",
+ "me-south-1": "13"
},
"arm-php-83-fpm": {
- "ca-central-1": "6",
- "eu-central-1": "6",
- "eu-north-1": "6",
- "eu-west-1": "6",
- "eu-west-2": "6",
- "eu-west-3": "6",
- "sa-east-1": "6",
- "us-east-1": "6",
- "us-east-2": "6",
- "us-west-1": "6",
- "us-west-2": "6",
- "ap-east-1": "6",
- "ap-south-1": "6",
- "ap-northeast-1": "6",
- "ap-northeast-2": "6",
- "ap-northeast-3": "6",
- "ap-southeast-1": "6",
- "ap-southeast-2": "6",
- "eu-south-1": "6",
- "eu-south-2": "6",
- "af-south-1": "6",
- "me-south-1": "6"
+ "ca-central-1": "13",
+ "eu-central-1": "13",
+ "eu-north-1": "13",
+ "eu-west-1": "13",
+ "eu-west-2": "13",
+ "eu-west-3": "13",
+ "sa-east-1": "13",
+ "us-east-1": "13",
+ "us-east-2": "13",
+ "us-west-1": "13",
+ "us-west-2": "13",
+ "ap-east-1": "13",
+ "ap-south-1": "13",
+ "ap-northeast-1": "13",
+ "ap-northeast-2": "13",
+ "ap-northeast-3": "13",
+ "ap-southeast-1": "13",
+ "ap-southeast-2": "13",
+ "eu-south-1": "13",
+ "eu-south-2": "13",
+ "af-south-1": "13",
+ "me-south-1": "13"
},
"arm-php-82": {
- "ca-central-1": "38",
- "eu-central-1": "38",
- "eu-north-1": "38",
- "eu-west-1": "38",
- "eu-west-2": "38",
- "eu-west-3": "38",
- "sa-east-1": "38",
- "us-east-1": "38",
- "us-east-2": "38",
- "us-west-1": "38",
- "us-west-2": "38",
- "ap-east-1": "38",
- "ap-south-1": "38",
- "ap-northeast-1": "38",
- "ap-northeast-2": "38",
- "ap-northeast-3": "38",
- "ap-southeast-1": "38",
- "ap-southeast-2": "38",
- "eu-south-1": "38",
- "eu-south-2": "38",
- "af-south-1": "38",
- "me-south-1": "38"
+ "ca-central-1": "45",
+ "eu-central-1": "45",
+ "eu-north-1": "45",
+ "eu-west-1": "45",
+ "eu-west-2": "45",
+ "eu-west-3": "45",
+ "sa-east-1": "45",
+ "us-east-1": "45",
+ "us-east-2": "45",
+ "us-west-1": "45",
+ "us-west-2": "45",
+ "ap-east-1": "45",
+ "ap-south-1": "45",
+ "ap-northeast-1": "45",
+ "ap-northeast-2": "45",
+ "ap-northeast-3": "45",
+ "ap-southeast-1": "45",
+ "ap-southeast-2": "45",
+ "eu-south-1": "45",
+ "eu-south-2": "45",
+ "af-south-1": "45",
+ "me-south-1": "45"
},
"arm-php-82-fpm": {
- "ca-central-1": "38",
- "eu-central-1": "38",
- "eu-north-1": "38",
- "eu-west-1": "38",
- "eu-west-2": "38",
- "eu-west-3": "38",
- "sa-east-1": "38",
- "us-east-1": "38",
- "us-east-2": "38",
- "us-west-1": "38",
- "us-west-2": "38",
- "ap-east-1": "38",
- "ap-south-1": "38",
- "ap-northeast-1": "38",
- "ap-northeast-2": "38",
- "ap-northeast-3": "38",
- "ap-southeast-1": "38",
- "ap-southeast-2": "38",
- "eu-south-1": "38",
- "eu-south-2": "38",
- "af-south-1": "38",
- "me-south-1": "38"
+ "ca-central-1": "45",
+ "eu-central-1": "45",
+ "eu-north-1": "45",
+ "eu-west-1": "45",
+ "eu-west-2": "45",
+ "eu-west-3": "45",
+ "sa-east-1": "45",
+ "us-east-1": "45",
+ "us-east-2": "45",
+ "us-west-1": "45",
+ "us-west-2": "45",
+ "ap-east-1": "45",
+ "ap-south-1": "45",
+ "ap-northeast-1": "45",
+ "ap-northeast-2": "45",
+ "ap-northeast-3": "45",
+ "ap-southeast-1": "45",
+ "ap-southeast-2": "45",
+ "eu-south-1": "45",
+ "eu-south-2": "45",
+ "af-south-1": "45",
+ "me-south-1": "45"
},
"arm-php-81": {
- "ca-central-1": "41",
- "eu-central-1": "41",
- "eu-north-1": "41",
- "eu-west-1": "41",
- "eu-west-2": "41",
- "eu-west-3": "41",
- "sa-east-1": "41",
- "us-east-1": "41",
- "us-east-2": "41",
- "us-west-1": "41",
- "us-west-2": "41",
- "ap-east-1": "41",
- "ap-south-1": "41",
- "ap-northeast-1": "41",
- "ap-northeast-2": "41",
- "ap-northeast-3": "41",
- "ap-southeast-1": "41",
- "ap-southeast-2": "41",
- "eu-south-1": "41",
- "eu-south-2": "41",
- "af-south-1": "41",
- "me-south-1": "41"
+ "ca-central-1": "48",
+ "eu-central-1": "48",
+ "eu-north-1": "48",
+ "eu-west-1": "48",
+ "eu-west-2": "48",
+ "eu-west-3": "48",
+ "sa-east-1": "48",
+ "us-east-1": "48",
+ "us-east-2": "48",
+ "us-west-1": "48",
+ "us-west-2": "48",
+ "ap-east-1": "48",
+ "ap-south-1": "48",
+ "ap-northeast-1": "48",
+ "ap-northeast-2": "48",
+ "ap-northeast-3": "48",
+ "ap-southeast-1": "48",
+ "ap-southeast-2": "48",
+ "eu-south-1": "48",
+ "eu-south-2": "48",
+ "af-south-1": "48",
+ "me-south-1": "48"
},
"arm-php-81-fpm": {
- "ca-central-1": "41",
- "eu-central-1": "41",
- "eu-north-1": "41",
- "eu-west-1": "41",
- "eu-west-2": "41",
- "eu-west-3": "41",
- "sa-east-1": "41",
- "us-east-1": "41",
- "us-east-2": "41",
- "us-west-1": "41",
- "us-west-2": "41",
- "ap-east-1": "41",
- "ap-south-1": "41",
- "ap-northeast-1": "41",
- "ap-northeast-2": "41",
- "ap-northeast-3": "41",
- "ap-southeast-1": "41",
- "ap-southeast-2": "41",
- "eu-south-1": "41",
- "eu-south-2": "41",
- "af-south-1": "41",
- "me-south-1": "41"
+ "ca-central-1": "48",
+ "eu-central-1": "48",
+ "eu-north-1": "48",
+ "eu-west-1": "48",
+ "eu-west-2": "48",
+ "eu-west-3": "48",
+ "sa-east-1": "48",
+ "us-east-1": "48",
+ "us-east-2": "48",
+ "us-west-1": "48",
+ "us-west-2": "48",
+ "ap-east-1": "48",
+ "ap-south-1": "48",
+ "ap-northeast-1": "48",
+ "ap-northeast-2": "48",
+ "ap-northeast-3": "48",
+ "ap-southeast-1": "48",
+ "ap-southeast-2": "48",
+ "eu-south-1": "48",
+ "eu-south-2": "48",
+ "af-south-1": "48",
+ "me-south-1": "48"
},
"arm-php-80": {
- "ca-central-1": "63",
- "eu-central-1": "62",
- "eu-north-1": "63",
- "eu-west-1": "63",
- "eu-west-2": "63",
- "eu-west-3": "63",
- "sa-east-1": "63",
- "us-east-1": "63",
- "us-east-2": "63",
- "us-west-1": "63",
- "us-west-2": "63",
- "ap-east-1": "55",
- "ap-south-1": "62",
- "ap-northeast-1": "62",
- "ap-northeast-2": "62",
- "ap-northeast-3": "62",
- "ap-southeast-1": "62",
- "ap-southeast-2": "62",
- "eu-south-1": "55",
- "eu-south-2": "51",
- "af-south-1": "55",
- "me-south-1": "55"
+ "ca-central-1": "70",
+ "eu-central-1": "69",
+ "eu-north-1": "70",
+ "eu-west-1": "70",
+ "eu-west-2": "70",
+ "eu-west-3": "70",
+ "sa-east-1": "70",
+ "us-east-1": "70",
+ "us-east-2": "70",
+ "us-west-1": "70",
+ "us-west-2": "70",
+ "ap-east-1": "62",
+ "ap-south-1": "69",
+ "ap-northeast-1": "69",
+ "ap-northeast-2": "69",
+ "ap-northeast-3": "69",
+ "ap-southeast-1": "69",
+ "ap-southeast-2": "69",
+ "eu-south-1": "62",
+ "eu-south-2": "58",
+ "af-south-1": "62",
+ "me-south-1": "62"
},
"arm-php-80-fpm": {
- "ca-central-1": "62",
- "eu-central-1": "61",
- "eu-north-1": "62",
- "eu-west-1": "62",
- "eu-west-2": "61",
- "eu-west-3": "61",
- "sa-east-1": "61",
- "us-east-1": "62",
- "us-east-2": "62",
- "us-west-1": "61",
- "us-west-2": "62",
- "ap-east-1": "54",
- "ap-south-1": "60",
- "ap-northeast-1": "61",
- "ap-northeast-2": "60",
- "ap-northeast-3": "60",
- "ap-southeast-1": "60",
- "ap-southeast-2": "60",
- "eu-south-1": "53",
- "eu-south-2": "50",
- "af-south-1": "54",
- "me-south-1": "53"
+ "ca-central-1": "69",
+ "eu-central-1": "68",
+ "eu-north-1": "69",
+ "eu-west-1": "69",
+ "eu-west-2": "68",
+ "eu-west-3": "68",
+ "sa-east-1": "68",
+ "us-east-1": "69",
+ "us-east-2": "69",
+ "us-west-1": "68",
+ "us-west-2": "69",
+ "ap-east-1": "61",
+ "ap-south-1": "67",
+ "ap-northeast-1": "68",
+ "ap-northeast-2": "67",
+ "ap-northeast-3": "67",
+ "ap-southeast-1": "67",
+ "ap-southeast-2": "67",
+ "eu-south-1": "60",
+ "eu-south-2": "57",
+ "af-south-1": "61",
+ "me-south-1": "60"
},
"console": {
- "ca-central-1": "60",
- "eu-central-1": "60",
- "eu-north-1": "60",
- "eu-west-1": "60",
- "eu-west-2": "60",
- "eu-west-3": "60",
- "sa-east-1": "60",
- "us-east-1": "60",
- "us-east-2": "60",
- "us-west-1": "60",
- "us-west-2": "60",
- "ap-east-1": "52",
- "ap-south-1": "59",
- "ap-northeast-1": "59",
- "ap-northeast-2": "59",
- "ap-northeast-3": "59",
- "ap-southeast-1": "59",
- "ap-southeast-2": "59",
- "eu-south-1": "52",
- "eu-south-2": "49",
- "af-south-1": "52",
- "me-south-1": "52"
+ "ca-central-1": "67",
+ "eu-central-1": "67",
+ "eu-north-1": "67",
+ "eu-west-1": "67",
+ "eu-west-2": "67",
+ "eu-west-3": "67",
+ "sa-east-1": "67",
+ "us-east-1": "67",
+ "us-east-2": "67",
+ "us-west-1": "67",
+ "us-west-2": "67",
+ "ap-east-1": "59",
+ "ap-south-1": "66",
+ "ap-northeast-1": "66",
+ "ap-northeast-2": "66",
+ "ap-northeast-3": "66",
+ "ap-southeast-1": "66",
+ "ap-southeast-2": "66",
+ "eu-south-1": "59",
+ "eu-south-2": "56",
+ "af-south-1": "59",
+ "me-south-1": "59"
}
}
\ No newline at end of file
diff --git a/serverless.yml b/serverless.yml
index 43244fa3d..3dc3d8a6d 100644
--- a/serverless.yml
+++ b/serverless.yml
@@ -38,25 +38,19 @@ functions:
timeout: 5 # in seconds (API Gateway has a timeout of 29 seconds)
events:
- http: 'ANY /'
+ - httpApi: '*'
psr7:
handler: demo/psr7.php
runtime: php-83
description: 'Bref HTTP demo with a PSR-7 handler'
timeout: 5 # in seconds (API Gateway has a timeout of 29 seconds)
+ url: true
events:
- http: 'ANY /psr7'
- httpApi: 'GET /psr7'
environment:
- BREF_LOOP_MAX: 100
-
- http-api:
- handler: demo/http.php
- runtime: php-83-fpm
- description: 'Bref HTTP demo'
- timeout: 5 # in seconds (API Gateway has a timeout of 29 seconds)
- events:
- - httpApi: '*'
+ #BREF_LOOP_MAX: 100
console:
handler: demo/console.php
diff --git a/src/Bref.php b/src/Bref.php
index 180cdbac6..06d93a52c 100644
--- a/src/Bref.php
+++ b/src/Bref.php
@@ -2,6 +2,7 @@
namespace Bref;
+use Bref\Listener\EventDispatcher;
use Bref\Runtime\FileHandlerLocator;
use Closure;
use Psr\Container\ContainerInterface;
@@ -11,10 +12,14 @@ class Bref
{
private static ?Closure $containerProvider = null;
private static ?ContainerInterface $container = null;
+ /**
+ * TODO deprecate hooks when the event dispatcher is stable.
+ */
private static array $hooks = [
'beforeStartup' => [],
'beforeInvoke' => [],
];
+ private static EventDispatcher $eventDispatcher;
/**
* Configure the container that provides Lambda handlers.
@@ -26,6 +31,17 @@ public static function setContainer(Closure $containerProvider): void
self::$containerProvider = $containerProvider;
}
+ /**
+ * @internal This API is experimental and may change at any time.
+ */
+ public static function events(): EventDispatcher
+ {
+ if (! isset(self::$eventDispatcher)) {
+ self::$eventDispatcher = new EventDispatcher;
+ }
+ return self::$eventDispatcher;
+ }
+
/**
* Register a hook to be executed before the runtime starts.
*
diff --git a/src/ConsoleRuntime/Main.php b/src/ConsoleRuntime/Main.php
index 7b7b0f16d..422817a02 100755
--- a/src/ConsoleRuntime/Main.php
+++ b/src/ConsoleRuntime/Main.php
@@ -19,6 +19,7 @@ public static function run(): void
LazySecretsLoader::loadSecretEnvironmentVariables();
Bref::triggerHooks('beforeStartup');
+ Bref::events()->beforeStartup();
$lambdaRuntime = LambdaRuntime::fromEnvironmentVariable('console');
@@ -28,6 +29,8 @@ public static function run(): void
$lambdaRuntime->failInitialization("Handler `$handlerFile` doesn't exist", 'Runtime.NoSuchHandler');
}
+ Bref::events()->afterStartup();
+
/** @phpstan-ignore-next-line */
while (true) {
$lambdaRuntime->processNextEvent(function ($event, Context $context) use ($handlerFile): array {
diff --git a/src/Event/Http/HttpRequestEvent.php b/src/Event/Http/HttpRequestEvent.php
index c4cbff55a..736b23728 100644
--- a/src/Event/Http/HttpRequestEvent.php
+++ b/src/Event/Http/HttpRequestEvent.php
@@ -190,7 +190,11 @@ public function getCookies(): array
$cookies = [];
foreach ($cookieParts as $cookiePart) {
- [$cookieName, $cookieValue] = explode('=', $cookiePart, 2);
+ $explode = explode('=', $cookiePart, 2);
+ if (count($explode) !== 2) {
+ continue;
+ }
+ [$cookieName, $cookieValue] = $explode;
$cookies[$cookieName] = urldecode($cookieValue);
}
return $cookies;
diff --git a/src/Event/Sqs/SqsRecord.php b/src/Event/Sqs/SqsRecord.php
index 4c9db8058..300b27ebc 100644
--- a/src/Event/Sqs/SqsRecord.php
+++ b/src/Event/Sqs/SqsRecord.php
@@ -57,6 +57,17 @@ public function getReceiptHandle(): string
return $this->record['receiptHandle'];
}
+ /**
+ * Returns the name of the SQS queue that contains the message.
+ * Queue naming constraints: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/quotas-queues.html
+ */
+ public function getQueueName(): string
+ {
+ $parts = explode(':', $this->record['eventSourceARN']);
+
+ return $parts[count($parts) - 1];
+ }
+
/**
* Returns the record original data as an array.
*
diff --git a/src/FpmRuntime/FpmHandler.php b/src/FpmRuntime/FpmHandler.php
index 2205966f8..6f7136184 100644
--- a/src/FpmRuntime/FpmHandler.php
+++ b/src/FpmRuntime/FpmHandler.php
@@ -136,7 +136,8 @@ public function handleRequest(HttpRequestEvent $event, Context $context): HttpRe
$response = $this->client->readResponse($socketId, $timeoutDelayInMs);
} catch (TimedoutException) {
- echo "The PHP script timed out. Bref will now restart PHP-FPM to start from a clean slate and flush the PHP logs.\nTimeouts can happen for example when trying to connect to a remote API or database, if this happens continuously check for those.\nIf you are using a RDS database, read this: https://bref.sh/docs/environment/database.html#accessing-the-internet\n";
+ $invocationId = $context->getAwsRequestId();
+ echo "$invocationId The PHP script timed out. Bref will now restart PHP-FPM to start from a clean slate and flush the PHP logs.\nTimeouts can happen for example when trying to connect to a remote API or database, if this happens continuously check for those.\nIf you are using a RDS database, read this: https://bref.sh/docs/environment/database.html#accessing-the-internet\n";
/**
* Restart FPM so that the blocked script is 100% terminated and that its logs are flushed to stderr.
diff --git a/src/FpmRuntime/Main.php b/src/FpmRuntime/Main.php
index d3241b5d1..fa462c113 100755
--- a/src/FpmRuntime/Main.php
+++ b/src/FpmRuntime/Main.php
@@ -22,6 +22,7 @@ public static function run(): void
LazySecretsLoader::loadSecretEnvironmentVariables();
Bref::triggerHooks('beforeStartup');
+ Bref::events()->beforeStartup();
$lambdaRuntime = LambdaRuntime::fromEnvironmentVariable('fpm');
@@ -38,6 +39,8 @@ public static function run(): void
$lambdaRuntime->failInitialization(new RuntimeException('Error while starting PHP-FPM: ' . $e->getMessage(), 0, $e));
}
+ Bref::events()->afterStartup();
+
/** @phpstan-ignore-next-line */
while (true) {
$lambdaRuntime->processNextEvent($phpFpm);
diff --git a/src/FunctionRuntime/Main.php b/src/FunctionRuntime/Main.php
index f6925ca06..8d335ce8b 100644
--- a/src/FunctionRuntime/Main.php
+++ b/src/FunctionRuntime/Main.php
@@ -17,6 +17,7 @@ public static function run(): void
LazySecretsLoader::loadSecretEnvironmentVariables();
Bref::triggerHooks('beforeStartup');
+ Bref::events()->beforeStartup();
$lambdaRuntime = LambdaRuntime::fromEnvironmentVariable('function');
@@ -28,6 +29,8 @@ public static function run(): void
$lambdaRuntime->failInitialization($e, 'Runtime.NoSuchHandler');
}
+ Bref::events()->afterStartup();
+
$loopMax = getenv('BREF_LOOP_MAX') ?: 1;
$loops = 0;
while (true) {
diff --git a/src/Listener/BrefEventSubscriber.php b/src/Listener/BrefEventSubscriber.php
new file mode 100644
index 000000000..489c3cfbe
--- /dev/null
+++ b/src/Listener/BrefEventSubscriber.php
@@ -0,0 +1,59 @@
+subscribers[] = $subscriber;
+ }
+
+ /**
+ * Trigger the `beforeStartup` event.
+ *
+ * @internal This method is called by Bref and should not be called by user code.
+ */
+ public function beforeStartup(): void
+ {
+ foreach ($this->subscribers as $listener) {
+ $listener->beforeStartup();
+ }
+ }
+
+ /**
+ * Trigger the `afterStartup` event.
+ *
+ * @internal This method is called by Bref and should not be called by user code.
+ */
+ public function afterStartup(): void
+ {
+ foreach ($this->subscribers as $listener) {
+ $listener->afterStartup();
+ }
+ }
+
+ /**
+ * Trigger the `beforeInvoke` event.
+ *
+ * @internal This method is called by Bref and should not be called by user code.
+ */
+ public function beforeInvoke(
+ callable | Handler | RequestHandlerInterface $handler,
+ mixed $event,
+ Context $context,
+ ): void {
+ foreach ($this->subscribers as $listener) {
+ $listener->beforeInvoke($handler, $event, $context);
+ }
+ }
+
+ /**
+ * Trigger the `afterInvoke` event.
+ *
+ * @internal This method is called by Bref and should not be called by user code.
+ */
+ public function afterInvoke(
+ callable | Handler | RequestHandlerInterface $handler,
+ mixed $event,
+ Context $context,
+ mixed $result,
+ \Throwable | null $error = null,
+ ): void {
+ foreach ($this->subscribers as $listener) {
+ $listener->afterInvoke($handler, $event, $context, $result, $error);
+ }
+ }
+}
diff --git a/src/Runtime/LambdaRuntime.php b/src/Runtime/LambdaRuntime.php
index d1cd50e0b..f0b70f1ac 100755
--- a/src/Runtime/LambdaRuntime.php
+++ b/src/Runtime/LambdaRuntime.php
@@ -86,6 +86,7 @@ public function processNextEvent(Handler | RequestHandlerInterface | callable $h
$this->setEnv('LAMBDA_INVOCATION_CONTEXT', json_encode($context, JSON_THROW_ON_ERROR));
Bref::triggerHooks('beforeInvoke');
+ Bref::events()->beforeInvoke($handler, $event, $context);
$this->ping();
@@ -93,9 +94,13 @@ public function processNextEvent(Handler | RequestHandlerInterface | callable $h
$result = $this->invoker->invoke($handler, $event, $context);
$this->sendResponse($context->getAwsRequestId(), $result);
+
+ Bref::events()->afterInvoke($handler, $event, $context, $result);
} catch (Throwable $e) {
$this->signalFailure($context->getAwsRequestId(), $e);
+ Bref::events()->afterInvoke($handler, $event, $context, null, $e);
+
return false;
}
diff --git a/tests/Event/Http/CommonHttpTest.php b/tests/Event/Http/CommonHttpTest.php
index 3e931a97b..b6cc0e34e 100644
--- a/tests/Event/Http/CommonHttpTest.php
+++ b/tests/Event/Http/CommonHttpTest.php
@@ -416,6 +416,17 @@ public function test request with cookies(int $version)
]);
}
+ /**
+ * @dataProvider provide API Gateway versions
+ */
+ public function test request with invalid cookies(int $version)
+ {
+ $this->fromFixture(__DIR__ . "/Fixture/ag-v$version-cookies-invalid.json");
+
+ // See https://stackoverflow.com/a/61695783/245552
+ $this->assertCookies([], 'foo');
+ }
+
/**
* @dataProvider provide API Gateway versions
*/
@@ -497,7 +508,7 @@ abstract protected function assertBody(string $expected): void;
abstract protected function assertContentType(?string $expected): void;
- abstract protected function assertCookies(array $expected): void;
+ abstract protected function assertCookies(array $expected, string |null $expectedHeader = null): void;
abstract protected function assertHeaders(array $expected): void;
diff --git a/tests/Event/Http/Fixture/ag-v1-cookies-invalid.json b/tests/Event/Http/Fixture/ag-v1-cookies-invalid.json
new file mode 100644
index 000000000..5bcfcde0d
--- /dev/null
+++ b/tests/Event/Http/Fixture/ag-v1-cookies-invalid.json
@@ -0,0 +1,53 @@
+{
+ "version": "1.0",
+ "resource": "/path",
+ "path": "/path",
+ "httpMethod": "GET",
+ "headers": {
+ "Accept": "*/*",
+ "Accept-Encoding": "gzip, deflate",
+ "Cache-Control": "no-cache",
+ "Host": "example.org",
+ "User-Agent": "PostmanRuntime/7.20.1",
+ "X-Amzn-Trace-Id": "Root=1-ffffffff-ffffffffffffffffffffffff",
+ "X-Forwarded-For": "1.1.1.1",
+ "X-Forwarded-Port": "443",
+ "X-Forwarded-Proto": "https",
+ "Cookie": "foo"
+ },
+ "queryStringParameters": null,
+ "pathParameters": null,
+ "stageVariables": null,
+ "requestContext": {
+ "resourceId": "xxxxxx",
+ "resourcePath": "/path",
+ "httpMethod": "PUT",
+ "extendedRequestId": "XXXXXX-xxxxxxxx=",
+ "requestTime": "24/Nov/2019:18:55:08 +0000",
+ "path": "/path",
+ "accountId": "123400000000",
+ "protocol": "HTTP/1.1",
+ "stage": "dev",
+ "domainPrefix": "dev",
+ "requestTimeEpoch": 1574621708700,
+ "requestId": "ffffffff-ffff-4fff-ffff-ffffffffffff",
+ "identity": {
+ "cognitoIdentityPoolId": null,
+ "accountId": null,
+ "cognitoIdentityId": null,
+ "caller": null,
+ "sourceIp": "1.1.1.1",
+ "principalOrgId": null,
+ "accessKey": null,
+ "cognitoAuthenticationType": null,
+ "cognitoAuthenticationProvider": null,
+ "userArn": null,
+ "userAgent": "PostmanRuntime/7.20.1",
+ "user": null
+ },
+ "domainName": "example.org",
+ "apiId": "xxxxxxxxxx"
+ },
+ "body": "",
+ "isBase64Encoded": false
+}
diff --git a/tests/Event/Http/Fixture/ag-v2-cookies-invalid.json b/tests/Event/Http/Fixture/ag-v2-cookies-invalid.json
new file mode 100644
index 000000000..1e4908fe2
--- /dev/null
+++ b/tests/Event/Http/Fixture/ag-v2-cookies-invalid.json
@@ -0,0 +1,41 @@
+{
+ "version": "2.0",
+ "routeKey": "ANY /path",
+ "rawPath": "/path",
+ "rawQueryString": "",
+ "cookies": ["foo"],
+ "headers": {
+ "Accept": "*/*",
+ "Accept-Encoding": "gzip, deflate",
+ "Cache-Control": "no-cache",
+ "Host": "example.org",
+ "User-Agent": "PostmanRuntime/7.20.1",
+ "X-Amzn-Trace-Id": "Root=1-ffffffff-ffffffffffffffffffffffff",
+ "X-Forwarded-For": "1.1.1.1",
+ "X-Forwarded-Port": "443",
+ "X-Forwarded-Proto": "https"
+ },
+ "queryStringParameters": null,
+ "stageVariables": null,
+ "requestContext": {
+ "accountId": "123400000000",
+ "apiId": "xxxxxxxxxx",
+ "domainName": "example.org",
+ "domainPrefix": "0000000000",
+ "http": {
+ "method": "GET",
+ "path": "/path",
+ "protocol": "HTTP/1.1",
+ "sourceIp": "1.1.1.1",
+ "userAgent": "PostmanRuntime/7.20.1"
+ },
+ "requestId": "JTHoQgr2oAMEPMg=",
+ "routeId": "47matwk",
+ "routeKey": "ANY /path",
+ "stage": "$default",
+ "time": "24/Nov/2019:18:55:08 +0000",
+ "timeEpoch": 1574621708700
+ },
+ "body": "",
+ "isBase64Encoded": false
+}
diff --git a/tests/Event/Http/HttpRequestEventTest.php b/tests/Event/Http/HttpRequestEventTest.php
index 20d7ec9c5..d1f2f516d 100644
--- a/tests/Event/Http/HttpRequestEventTest.php
+++ b/tests/Event/Http/HttpRequestEventTest.php
@@ -27,15 +27,18 @@ protected function assertContentType(?string $expected): void
}
}
- protected function assertCookies(array $expected): void
+ protected function assertCookies(array $expected, string |null $expectedHeader = null): void
{
$this->assertEquals($expected, $this->event->getCookies());
// Also check that the cookies are available in the HTTP headers (they should be)
- $expectedHeader = array_map(function (string $value, string $key): string {
- return $key . '=' . urlencode($value);
- }, $expected, array_keys($expected));
- $this->assertEquals(implode('; ', $expectedHeader), $this->event->getHeaders()['cookie'][0] ?? '');
+ if ($expectedHeader === null) {
+ $expectedHeader = array_map(function (string $value, string $key): string {
+ return $key . '=' . urlencode($value);
+ }, $expected, array_keys($expected));
+ $expectedHeader = implode('; ', $expectedHeader);
+ }
+ $this->assertEquals($expectedHeader, $this->event->getHeaders()['cookie'][0] ?? '');
}
protected function assertHeaders(array $expected): void
diff --git a/tests/Event/Http/Psr7BridgeTest.php b/tests/Event/Http/Psr7BridgeTest.php
index 869a7e347..e2ab8de1a 100644
--- a/tests/Event/Http/Psr7BridgeTest.php
+++ b/tests/Event/Http/Psr7BridgeTest.php
@@ -48,7 +48,7 @@ protected function assertContentType(?string $expected): void
$this->assertEquals($expected, $this->request->getHeaderLine('Content-Type'));
}
- protected function assertCookies(array $expected): void
+ protected function assertCookies(array $expected, string |null $expectedHeader = null): void
{
$this->assertEquals($expected, $this->request->getCookieParams());
}
diff --git a/tests/Event/Sqs/SqsRecordTest.php b/tests/Event/Sqs/SqsRecordTest.php
new file mode 100644
index 000000000..b83f190ff
--- /dev/null
+++ b/tests/Event/Sqs/SqsRecordTest.php
@@ -0,0 +1,18 @@
+assertSame($sqsRecord->getQueueName(), 'my-queue');
+ }
+}
diff --git a/tests/FpmRuntime/FpmHandlerTest.php b/tests/FpmRuntime/FpmHandlerTest.php
index 388803894..1515150f6 100644
--- a/tests/FpmRuntime/FpmHandlerTest.php
+++ b/tests/FpmRuntime/FpmHandlerTest.php
@@ -777,6 +777,42 @@ public function test request with cookies(int $version)
]);
}
+ /**
+ * @dataProvider provide API Gateway versions
+ */
+ public function test request with invalid cookies(int $version)
+ {
+ $event = [
+ 'version' => '1.0',
+ 'httpMethod' => 'GET',
+ 'headers' => [
+ 'Cookie' => 'foo',
+ ],
+ ];
+ $this->assertGlobalVariables($event, [
+ '$_GET' => [],
+ '$_POST' => [],
+ '$_FILES' => [],
+ '$_COOKIE' => [
+ 'foo' => '',
+ ],
+ '$_REQUEST' => [],
+ '$_SERVER' => [
+ 'REQUEST_URI' => '/',
+ 'PHP_SELF' => '/',
+ 'PATH_INFO' => '/',
+ 'REQUEST_METHOD' => 'GET',
+ 'QUERY_STRING' => '',
+ 'HTTP_COOKIE' => 'foo',
+ 'CONTENT_LENGTH' => '0',
+ 'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
+ 'LAMBDA_INVOCATION_CONTEXT' => json_encode($this->fakeContext),
+ 'LAMBDA_REQUEST_CONTEXT' => '[]',
+ ],
+ 'HTTP_RAW_BODY' => '',
+ ]);
+ }
+
/**
* @dataProvider provide API Gateway versions
*/
diff --git a/tests/HttpRequestProxyTest.php b/tests/HttpRequestProxyTest.php
index 4164546ad..725f1c1e2 100644
--- a/tests/HttpRequestProxyTest.php
+++ b/tests/HttpRequestProxyTest.php
@@ -47,6 +47,8 @@ public function test POST request with multipart file uploads(int $version
public function test request with cookies(int $version);
+ public function test request with invalid cookies(int $version);
+
public function test POST request with base64 encoded body(int $version);
public function test PUT request(int $version);
diff --git a/tests/Listener/EventDispatcherTest.php b/tests/Listener/EventDispatcherTest.php
new file mode 100644
index 000000000..701753bfb
--- /dev/null
+++ b/tests/Listener/EventDispatcherTest.php
@@ -0,0 +1,31 @@
+subscribe($subscriber);
+
+ $eventDispatcher->beforeStartup();
+ $this->assertTrue($subscriber->invokedBeforeStartup);
+
+ $handler = fn () => null;
+ $event = new stdClass;
+ $context = Context::fake();
+ $eventDispatcher->beforeInvoke($handler, $event, $context);
+ $this->assertEquals([$handler, $event, $context], $subscriber->invokedBeforeInvoke);
+
+ $result = new stdClass;
+ $eventDispatcher->afterInvoke($handler, $event, $context, $result);
+ $this->assertEquals([$handler, $event, $context, $result, null], $subscriber->invokedAfterInvoke);
+ }
+}
diff --git a/tests/Listener/FakeSubscriber.php b/tests/Listener/FakeSubscriber.php
new file mode 100644
index 000000000..446db1126
--- /dev/null
+++ b/tests/Listener/FakeSubscriber.php
@@ -0,0 +1,33 @@
+invokedBeforeStartup = true;
+ }
+
+ /**
+ * @param mixed ...$params
+ */
+ public function beforeInvoke(...$params): void
+ {
+ $this->invokedBeforeInvoke = $params;
+ }
+
+ /**
+ * @param mixed ...$params
+ */
+ public function afterInvoke(...$params): void
+ {
+ $this->invokedAfterInvoke = $params;
+ }
+}
diff --git a/website/src/components/home/sponsors.jsx b/website/src/components/home/sponsors.jsx
index 4ce56a581..a02c64cf4 100644
--- a/website/src/components/home/sponsors.jsx
+++ b/website/src/components/home/sponsors.jsx
@@ -2,7 +2,6 @@ import GoldSponsor from './sponsors/gold-sponsor';
import craftLogo from './sponsors/logo-craft-cms.png';
import tidewaysLogo from './sponsors/logo-tideways.svg';
import myBuilderLogo from './sponsors/logo-mybuilder.svg';
-import shippyProLogo from './sponsors/logo-shippypro.png';
import nullLogo from './sponsors/logo-null.png';
import awsLogo from './sponsors/logo-aws.svg';
import jetbrainsLogo from './sponsors/logo-jetbrains.svg';
@@ -10,6 +9,7 @@ import laravelLogo from './sponsors/logo-laravel.svg';
import depotLogo from './sponsors/logo-depot.svg';
import secumailerLogo from './sponsors/logo-secumailer.svg';
import ecomailLogo from './sponsors/logo-ecomail.png';
+import spreakerLogo from './sponsors/logo-spreaker.svg';
import PremiumSponsor from './sponsors/premium-sponsor';
export default function Sponsors() {
@@ -26,9 +26,9 @@ export default function Sponsors() {