#pr-reviews (2024-08)
Pull Request Reviews for Cloud Posse Projects
2024-08-01
Could https://github.com/cloudposse/terraform-aws-ecs-web-app/pull/189 please be reopened, the issue with the dependency should be fixed? (cc @kevcube as original author)
@Igor Rodionov @Andriy Knysh (Cloud Posse)
just another friendly ping on this
@Moritz comment by Andriy:
please add linux_parameters support in a separate PR.
This PR is very old and introduced many changes.
thank you
Re-do of #189
what
• set initProcessEnabled = true
in container definition if user has opted to enable ecs_exec (it is optional, but recommended by AWS)
why
• it will remove zombie processes in containers after exec is run • because AWS recommended it
2024-08-02
Would love to get a review on this PR which adds local file path support for Spacelift policies (in addition to the currently existing inline and http URL support): https://github.com/cloudposse/terraform-spacelift-cloud-infrastructure-automation/pull/183.
One thing to note though is that all the terratest
in the repo seem to be failing even for dependency updates (not even at the code level, terraform can’t be initalized). Tofu is suceeding. Can someone who’s familiar with how Terratest works take a look at that?
+ echo 'Unable to locate executable for terraform '
Unable to locate executable for terraform
I see that the Terratest command performs FULL_VERSION=$(vert -s "$(terraform-config-inspect --json examples/complete | jq -r '.required_core[]')" "$TF012" "$TF013" "$TF014" "$TF015" "$TF1" | head -1) || [[ -n "$VERSION" ]]
However, this repo is kind of a mono-module repo, so instead of examples/complete
it has examples/spacelift-policy
and examples/spacelift-stack
etc.
What are y’all thoughts on this test? Does that seem like the problem in this repo?
Potential options: adding a boilerplate examples/complete
or adding a fallback in the test script?
Got the tests fixed with the gracious help from @Veronika Gnilitska! Just pending a review now.
This should also address the other pending PR’s in this same repository where the test fails unrelated to the actual code
@Igor Rodionov @Dan Miller (Cloud Posse)
2024-08-05
2024-08-08
2024-08-09
Hello, could I get a PR review of https://github.com/cloudposse/terraform-aws-dms/pull/30?
…l_load_timestamp
what
Add feature missing s3_settings attribute use_task_start_time_for_full_load_timestamp
why
This attribute is available in the aws provider and we need it for an integration.
references
2024-08-20
Hi, just wanted to bring to your attention https://github.com/cloudposse/terraform-aws-lambda-function/pull/69 by @jpalomaki I just badly need to use that feature…
what
Allow lambda configuration author to optionally declare lambda:InvokeFunction
lambda permissions directly in this module.
More complex permissions configurations could still be done outside of this module.
why
This co-locates permissions related to the lambda in the module configuration (where we also declare lambda IAM role permissions), which can help a reader understand where the lambda is invoked from, e.g. in cases where the actual event sources are declared in a different root configuration.
In our specific use case, we use terragrunt to deploy the lambda function (straight from terraform registry module), so this feature would also help us avoid having to create a wrapper module just to add the necessary permission resources.
questions
- Because we support terraform 0.14+ (no default value support for optionals), we scope this to just the specific action
lambda:InvokeFunction
and keep the number of attributes a user has to fill in, small. Does this look like a sane approach (looks like it could cover a lot of ground already, judging by examples)? - Because we support terraform 0.14+, we can’t do replace_triggered_by. Not entirely sure if that is a problem though, since we just attach the permission to the function itself (and not an alias or version)
- The resource
for_each
is keyed by list index, which isn’t ideal, since it would force recreations if items are shuffled/inserted
references
Slack discussion, cc/ @osterman
@jpalomaki looks like there’s some updates on your PR
what
Allow lambda configuration author to optionally declare lambda:InvokeFunction
lambda permissions directly in this module.
More complex permissions configurations could still be done outside of this module.
why
This co-locates permissions related to the lambda in the module configuration (where we also declare lambda IAM role permissions), which can help a reader understand where the lambda is invoked from, e.g. in cases where the actual event sources are declared in a different root configuration.
In our specific use case, we use terragrunt to deploy the lambda function (straight from terraform registry module), so this feature would also help us avoid having to create a wrapper module just to add the necessary permission resources.
questions
- Because we support terraform 0.14+ (no default value support for optionals), we scope this to just the specific action
lambda:InvokeFunction
and keep the number of attributes a user has to fill in, small. Does this look like a sane approach (looks like it could cover a lot of ground already, judging by examples)? - Because we support terraform 0.14+, we can’t do replace_triggered_by. Not entirely sure if that is a problem though, since we just attach the permission to the function itself (and not an alias or version)
- The resource
for_each
is keyed by list index, which isn’t ideal, since it would force recreations if items are shuffled/inserted
references
Slack discussion, cc/ @osterman
Hey all! Would appreciate a review on adding support for Origin Access Control to the terraform-aws-cloudfront-s3-cdn component
what
• add Origin Access Control feature
• add var.origin_access_type
to enable Origin Access Identity or Origina Access Control policy
• add aws_cloudfront_origin_access_control.default
resource
• add origin_access_control_id
argument to origin config on aws_cloudfront_distribution.default
• update example code
• update README
why
• provide the ability to make use of an Origin Access Control
• retain default origin access identity behavior
• AWS recommends using origin access control
• Origin Access Identities are flagged in AWS Security Hub
references
• Closes #244 • https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html
@Ben Smith (Cloud Posse) @Jeremy White (Cloud Posse)
what
• add Origin Access Control feature
• add var.origin_access_type
to enable Origin Access Identity or Origina Access Control policy
• add aws_cloudfront_origin_access_control.default
resource
• add origin_access_control_id
argument to origin config on aws_cloudfront_distribution.default
• update example code
• update README
why
• provide the ability to make use of an Origin Access Control
• retain default origin access identity behavior
• AWS recommends using origin access control
• Origin Access Identities are flagged in AWS Security Hub
references
• Closes #244 • https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html
@Jeremy White (Cloud Posse) bumping this up
Please see comment. It looks like some of the depends_on changes could have caused it:
Returning due to fatal error: FatalError{Underlying: error while running command: exit status 1; ╷
│ Error: reading S3 Bucket CORS Configuration (eg-test-cf-s3-cdn-lambda-18717-origin): couldn't find resource
│
│ with module.cloudfront_s3_cdn.aws_s3_bucket_cors_configuration.origin[0],
│ on ../../main.tf line 352, in resource "aws_s3_bucket_cors_configuration" "origin":
│ 352: resource "aws_s3_bucket_cors_configuration" "origin" {
│
╵}
It’s interesting, I run both terraform
and opentofu
tests using docker and they always pass - I suppose the opentofu CI job was unlucky? :thinking_face:
I’ve added a depends_on to the aws_s3_bucket_cors_configuration.origin
resource in hopes that corrects it. I’ll admit it seems a bit odd of an error, cannot find a resource that it is in the middle of creating.
Looks like latest terratest
passed. I believe I corrected the lint formatting with my latest commit and hoping that clears up the bats failure on the next ci run
oof, sorry that I got busy yesterday. Re-running now
sorry looks like i hadn’t saved all the changes before my previous commit just pushed up what i think should handle the failures
not sure what’s up with the chatops action. I’ll look into it on monday if no one else does this weekend
awesome. hope you enjoy the weekend!
2024-08-21
2024-08-22
Hi there, a very very quick change to the cloudwatch submodule into the lamdba one, to allow the context to be passed to the submodule instead of just vars. Thanks
https://github.com/cloudposse/terraform-aws-lambda-function/pull/74
what
A patch to pass the context
instead of just vars
to the CloudWatch submodule.
why
This module is only setting the context vars
instead of the whole context
, leaving up to the submodule to set its own context.
By settings the context
(as advised by cloudposse) the root deployment are passed to the submodule, and an upper/camel/pascal case function_name
will be consistent with the Cloudwatch group name.
references
• Closes #73
@Dan Miller (Cloud Posse)
what
A patch to pass the context
instead of just vars
to the CloudWatch submodule.
why
This module is only setting the context vars
instead of the whole context
, leaving up to the submodule to set its own context.
By settings the context
(as advised by cloudposse) the root deployment are passed to the submodule, and an upper/camel/pascal case function_name
will be consistent with the Cloudwatch group name.
references
• Closes #73
Thanks for submitting the PR! Looks good to me, but I left 1 minor comment
Updated, thanks for checking
@Dan Miller (Cloud Posse)
@nnsense we accidentally introduce a breaking change! I’m fixing it now, but we have to revert this PR https://github.com/cloudposse/terraform-aws-lambda-function/issues/78
Describe the Bug
#74 actually breaks aws_cloudwatch_log_group
names
module.lambda_cloudtrail_lookup[0].module.cloudwatch_log_group.aws_cloudwatch_log_group.default[0] must be replaced
-/+ resource “aws_cloudwatch_log_group” “default” { ~ arn = “arn:aws:logs:us-east-1:012345678910:log-group:/aws/lambda/compromised-keys-cloudtrail-lookup” -> (known after apply) ~ id = “/aws/lambda/compromised-keys-cloudtrail-lookup” -> (known after apply) ~ log_group_class = “STANDARD” -> (known after apply) ~ name = “/aws/lambda/compromised-keys-cloudtrail-lookup” -> “namespace-environment-stage-/aws/lambda/compromised-keys-cloudtrail-lookup” # forces replacement + name_prefix = (known after apply) ~ tags = { ~ “Name” = “namespace-environment-stage-compromised-keys” -> “namespace-environment-stage-/aws/lambda/compromised-keys-cloudtrail-lookup” } ~ tags_all = { ~ “Name” = “namespace-environment-stage-compromised-keys” -> “namespace-environment-stage-/aws/lambda/compromised-keys-cloudtrail-lookup” # (15 unchanged elements hidden) } # (2 unchanged attributes hidden) }
# module.lambda_delete_key[0].module.cloudwatch_log_group.aws_cloudwatch_log_group.default[0] must be replaced -/+ resource “aws_cloudwatch_log_group” “default” { ~ arn = “arn:aws:logs:us-east-1:012345678910:log-group:/aws/lambda/compromised-keys-delete-key” -> (known after apply) ~ id = “/aws/lambda/compromised-keys-delete-key” -> (known after apply) ~ log_group_class = “STANDARD” -> (known after apply) ~ name = “/aws/lambda/compromised-keys-delete-key” -> “namespace-environment-stage-/aws/lambda/compromised-keys-delete-key” # forces replacement + name_prefix = (known after apply) ~ tags = { ~ “Name” = “namespace-environment-stage-compromised-keys” -> “namespace-environment-stage-/aws/lambda/compromised-keys-delete-key” } ~ tags_all = { ~ “Name” = “namespace-environment-stage-compromised-keys” -> “namespace-environment-stage-/aws/lambda/compromised-keys-delete-key” # (15 unchanged elements hidden) } # (2 unchanged attributes hidden) }
# module.lambda_notify_security[0].module.cloudwatch_log_group.aws_cloudwatch_log_group.default[0] must be replaced -/+ resource “aws_cloudwatch_log_group” “default” { ~ arn = “arn:aws:logs:us-east-1:012345678910:log-group:/aws/lambda/compromised-keys-notify-security” -> (known after apply) ~ id = “/aws/lambda/compromised-keys-notify-security” -> (known after apply) ~ log_group_class = “STANDARD” -> (known after apply) ~ name = “/aws/lambda/compromised-keys-notify-security” -> “namespace-environment-stage-/aws/lambda/compromised-keys-notify-security” # forces replacement + name_prefix = (known after apply) ~ tags = { ~ “Name” = “namespace-environment-stage-compromised-keys” -> “namespace-environment-stage-/aws/lambda/compromised-keys-notify-security” } ~ tags_all = { ~ “Name” = “namespace-environment-stage-compromised-keys” -> “namespace-environment-stage-/aws/lambda/compromised-keys-notify-security” # (15 unchanged elements hidden) } # (2 unchanged attributes hidden) }
Plan: 3 to add, 0 to change, 3 to destroy.
Expected Behavior
name
should be not changed
https://github.com/cloudposse/terraform-aws-lambda-function/pull/74/files#diff-dc46acf24afd63ef8c556b77c126ccc6e578bc87e3aa09a931f33d9bf2532fbbR15
Possible solution: Provide all context
variables except name
Steps to Reproduce
- Create https://github.com/cloudposse/terraform-aws-lambda-function/blob/main/examples/complete/main.tf on v0.5.5
- Update to v0.6.0
Screenshots
No response
Environment
No response
Additional Context
No response
OOPS! :smile: Right.. but then.. why name is lowercase? name
is basically my reason behind that PR, if I set that to something uppercase, there’s something that set it back to lowercase, which creates a bug for the module, if you set the lambda name to something different from lowercase it will then target a cloudwatch group that doesn’t exist (being all lowercase)
I will try to dig more, this is not the end of it!!
Something that let me think, but I didn’t pay too much attention to it, is hardcoding /aws/lambda/
at the beginning of the cloudwatch group name. That is what I think is actually creating the issue.. Will try to propose a solution
the name is lowercase because the log group name is run through our null-label module, which converts everything to lowercase as a convention https://github.com/cloudposse/terraform-aws-cloudwatch-logs/blob/main/main.tf#L5-L13
module "log_group_label" {
source = "cloudposse/label/null"
version = "0.25.0"
# Allow forward slashes
regex_replace_chars = "/[^a-zA-Z0-9-\\/]/"
context = module.this.context
}
I was assuming that but when I check the [variables.tf](http://variables.tf)
inside null label it says “default is lower” but then default = null
.. I didn’t find where that “lower” is then being set TBH
https://github.com/cloudposse/terraform-null-label/blob/e88c5a8e4b8a621d4b96603bfe5c0738b96aec5b/variables.tf#L193
variable "label_value_case" {
sorry wrong link. looking, one second
so yes it is label_value_case
, which if unset will choose “lower”
https://github.com/cloudposse/terraform-null-label/blob/main/main.tf#L14
label_value_case = "lower"
Got it, thanks :slightly_smiling_face: So.. the problem lies down to the name
attribute which is set to be "/aws/lambda/${var.function_name}"
Trying to automate avoiding to add an additional variable for whoever wants it camelCase, PascalCase or Title but still trying to avoid breaking who is already relying on this being lower
by deefault.. what do you think of…
module "cloudwatch_log_group" {
source = "cloudposse/cloudwatch-logs/aws"
version = "0.6.6"
enabled = module.this.enabled
iam_role_enabled = false
kms_key_arn = var.cloudwatch_logs_kms_key_arn
retention_in_days = var.cloudwatch_logs_retention_in_days
name = "/aws/lambda/${var.function_name}"
label_value_case = can(regex("[A-Z]", var.function_name)) ? "none" : "lower" <-------------------- this ?
tags = module.this.tags
}
Or even better null
instead of lower
since that’s the default
@Dan Miller (Cloud Posse) hi there, any thoughts on the above? I have a number of lambdas all named pascalcase and all have the link with cloud watch broken, would love to fix it :)
so that I follow correctly, is your intention with that label_value_case
line to use “none” if there are any upper case characters in the function name and use lower if no?
Yes, it’s weird I know.. But now I’m terrorised do introduce something that’ll break the others work :)
what about other users that have upper case function names?
this will replace their log group, no?
all have the link with cloud watch broken
Which is the part that’s broken? Maybe we can fix that instead
That’s my case, and it would be awesome to get it fixed. Like I said in the issue I opened, if my lambda has a name with uppercase letters, the module will create a cloud watch group all lowercase but it will then refer to it as it was originally, with upper case. Easy to test, just deploy a lambda with SomeName
, it will reference a group with SomeName
but the model will create it somename
Cloudposse powerful null label is usually taking care of this, which is why I originally added the context, but this cloud watch module inside lambda is peculiar because it specifically set name
prefixing it with /aws/lambda
which I think is the real issue
but it will then refer to it as it was originally, with upper case
Forgive me if you already said, but where does your lambda refer to the cloudwatch group? Is that part of the module?
Into the module main.tf
module "cloudwatch_log_group" {
source = "cloudposse/cloudwatch-logs/aws"
version = "0.6.6"
enabled = module.this.enabled
iam_role_enabled = false
kms_key_arn = var.cloudwatch_logs_kms_key_arn
retention_in_days = var.cloudwatch_logs_retention_in_days
name = "/aws/lambda/${var.function_name}"
tags = module.this.tags
}
name
is the cloudposse null-label name
into the cloudwatch module which, as you pointed out, is lower
by default.
This is obviously true for both lambda and cloudwatch module but the lambda module is set by the user context
while the cloudwatch module is not. So the cloudwatch group will create the name in lowercase because the context
isn’t set by my config and, likely, since no log_group
is set into the lambda module to force the name, Lambda will assume its name is the same as the the function itself, prefixed by /aws/lambda
. This will set lambda to search for /aws/lambda/MyLogGroup
even if the module has created it as /aws/lambda/myloggroup
.
The example/complete provided is setting the lambda name with module.label.id
which also forces that all lowercase, if I set that to var.function_name
, this is the plan
:
# module.lambda.aws_lambda_function.this[0] will be created
+ resource "aws_lambda_function" "this" {
+ architectures = (known after apply)
+ arn = (known after apply)
+ code_sha256 = (known after apply)
+ filename = "function.zip"
+ function_name = "ThisIsMyFunction" <---------------- PascalCase
+ handler = "handler.handler"
+ id = (known after apply)
+ invoke_arn = (known after apply)
+ last_modified = (known after apply)
+ layers = []
+ memory_size = 128
+ package_type = "Zip"
+ publish = false
+ qualified_arn = (known after apply)
+ qualified_invoke_arn = (known after apply)
+ reserved_concurrent_executions = -1
+ role = (known after apply)
+ runtime = "nodejs20.x"
+ signing_job_arn = (known after apply)
+ signing_profile_version_arn = (known after apply)
+ skip_destroy = false
+ source_code_hash = (known after apply)
+ source_code_size = (known after apply)
+ tags_all = (known after apply)
+ timeout = 3
+ version = (known after apply)
}
# module.lambda.module.cloudwatch_log_group.aws_cloudwatch_log_group.default[0] will be created
+ resource "aws_cloudwatch_log_group" "default" {
+ arn = (known after apply)
+ id = (known after apply)
+ log_group_class = (known after apply)
+ name = "/aws/lambda/thisismyfunction" <---------------- lowercase
+ name_prefix = (known after apply)
+ retention_in_days = 0
+ skip_destroy = false
+ tags = {
+ "Name" = "/aws/lambda/thisismyfunction"
}
+ tags_all = {
+ "Name" = "/aws/lambda/thisismyfunction"
}
}
To sort this out, the best would be to pass context
and leave the name up to the user (without /aws/lambda
) but I tried and we had to roll the change back because then name
ends up getting the context
name applied (so, the id
). Another solution would be, without my weird “regex” workaround, to set the label_value_case
as well into the lambda module’s cloudwatch group, allowing us to set it the same way we set lambda. Unfortunately, this is just my case, if someone else is setting anything else from the root module, it will sill get lost, exactly like label_value_case
, but apparently no one else complained so far, so I might be one of the few changing the variables of the root context
Ah well, of course we also have the option to force the log group name into lambda, but I don’t think is fair to enforce a naming convention to the user by unilaterally decide to set everything to lowercase.
I just tested, this works if you think it would be ok, passing the root module setting to cloudwatch, what do you think?
module "cloudwatch_log_group" {
source = "cloudposse/cloudwatch-logs/aws"
version = "0.6.6"
enabled = module.this.enabled
iam_role_enabled = false
kms_key_arn = var.cloudwatch_logs_kms_key_arn
retention_in_days = var.cloudwatch_logs_retention_in_days
name = "/aws/lambda/${var.function_name}"
label_value_case = var.label_value_case
tags = module.this.tags
}
to be honest I’m a little swamped this week with other work, so I may not have much time to look into this at more than a high level. Although I do think adding var.label_value_case
as an option is a good compromise
I completely understand and obviously not a problem at all, I will add a PR with the proposed change so that you can review once you have time, thanks :)
2024-08-23
2024-08-24
Hey all,
Ive opened a PR to the CP subnets module to allow routing to a Transit gateway. Left more details in the pr description, looking forward to getting feedback on this change.
https://github.com/cloudposse/terraform-aws-named-subnets/pull/60
what
• The existing module only allows a user to associate the route table of a private subnet with a network interface or a nat gateway. • By adding the tgw_id argument, users of the subnet module can automatically create a route table with routing between a private subnet and a transit gateway.
why
• As a best practice, a user may create an AWS account for centralized networking.
• To allow traffic to route from account B to account A (centralized networking account), a Transit Gateway is needed.
• If a user creates a subnet using this module, the tgw_id feature will allow the user to directly associate the route table in the private subnet to an existing transit gateway.
• Example architecture:
ec2 -> private subnet rtb -> tgw -> private subnet rtb-> natgw -> public internet
|——–AWS Account B——|——-AWS Account A———-|
References
do you see the note in description that this module is deprecated? I would recommend you use cloudposse/terraform-aws-dynamic-subnets instead
what
• The existing module only allows a user to associate the route table of a private subnet with a network interface or a nat gateway. • By adding the tgw_id argument, users of the subnet module can automatically create a route table with routing between a private subnet and a transit gateway.
why
• As a best practice, a user may create an AWS account for centralized networking.
• To allow traffic to route from account B to account A (centralized networking account), a Transit Gateway is needed.
• If a user creates a subnet using this module, the tgw_id feature will allow the user to directly associate the route table in the private subnet to an existing transit gateway.
• Example architecture:
ec2 -> private subnet rtb -> tgw -> private subnet rtb-> natgw -> public internet
|——–AWS Account B——|——-AWS Account A———-|
References
Ah didnt notice that, thanks.
Wow, I didn’t notice too, and I’m actively using that module. It’s a bit hard to see for me because I usually jump to the readme and read that (and I skip the header, if any :D)
2024-08-26
Hi cloudposse crew! Just a minor addition to the lambda module, allowing to set a Kinesis stream, DynamoDB stream, or SQS queue as a trigger for lambda. https://github.com/cloudposse/terraform-aws-lambda-function/pull/75 Thanks :)
what
Implementation of the aws_lambda_event_source_mapping
resource, allowing to set a Kinesis stream, DynamoDB stream, or SQS queue as a trigger for lambda. I’ve porpousely kept things simple allowing only a few variables:
• source_mapping_arn
pointing to the arn
of the triggering resource (eg, the lambda execution role)
• source_mapping_batch_size
allowing to tune the number of events we pass to the function.
• source_mapping_starting_position
, because it’s usually required and terraform complains if it’s unset
• source_mapping_starting_position_timestamp
, if someone wants to use AT_TIMESTAMP
in Kinesis.
why
It’s useful to get lambda triggered by other resources without having to set just one resource in another module.
@Dan Miller (Cloud Posse)
what
Implementation of the aws_lambda_event_source_mapping
resource, allowing to set a Kinesis stream, DynamoDB stream, or SQS queue as a trigger for lambda. I’ve porpousely kept things simple allowing only a few variables:
• source_mapping_arn
pointing to the arn
of the triggering resource (eg, the lambda execution role)
• source_mapping_batch_size
allowing to tune the number of events we pass to the function.
• source_mapping_starting_position
, because it’s usually required and terraform complains if it’s unset
• source_mapping_starting_position_timestamp
, if someone wants to use AT_TIMESTAMP
in Kinesis.
why
It’s useful to get lambda triggered by other resources without having to set just one resource in another module.
Left a comment. We should try to make sure any resource is covered by terratest
Fixed.. well, maybe, not sure if that’s everything needed
@nnsense looks like terraform failed once we enabled these new resources. Can you please review the error? Let me know if you have any questions about it
That’s what I was expecting to happen by adding source_mapping_enabled = true
, but I don’t know what to set for source_mapping_arn
because that doesn’t exist (should I add a dynamodb example to sort that out?)
I think I’ve sorted that out passing fake parameters, hope that works…
aww right It doesnt
You might need to create an example dynamodb table so that you can properly validate the resource by passing a valid ARN
Let’s do it
Done ( )
2024-08-27
For your kind attention Another minor addition to allow a user to set a resource policy to the dynamodb module (well.. which is why I asked this ) https://github.com/cloudposse/terraform-aws-dynamodb/pull/135
@Dan Miller (Cloud Posse)
@Ben Smith (Cloud Posse)
@nnsense left a comment. Same idea as yesterday where we added test coverage for any new resource
2024-08-28
2024-08-29
Hey all, what is the status of https://github.com/cloudposse/terraform-aws-dms/pull/30? Changes were requested and they have been implemented
@Andriy Knysh (Cloud Posse) @Igor Rodionov
@Ray Finch thank you for the PR, it’s merged