Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions compute/lambda/rvn-lambda-definition.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ definition:
name: Lambda Function
description: AWS Lambda function with zip or container image deployments, alias-based releases, IAM, logs, and optional function URLs.
release:
version: 0.3.3
description: Document cross-account ECR support for image registry deploys.
version: 0.4.0
description: >-
Stop creating a module-owned ECR repository when pulling from an image
registry. Add a required initial image tag or digest used to create the
function before its first deployment.
module:
inputs:
- $include: ../../partials/inputs/aws-account.yml
Expand Down Expand Up @@ -209,6 +212,15 @@ module:
show_when:
package_type: Image
build_source: image_registry
- id: initial_image_ref
label: Initial image tag or digest
type: string
description: Tag or digest used only to create the function before its first deployment. It must already exist in the image repository above. Deployments promote the tag or digest you pass at deploy time; changing this value afterward has no effect. Do not include the repository URI.
placeholder: sha256:... or latest
required: true
show_when:
package_type: Image
build_source: image_registry
Comment on lines +215 to +223

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Initial image refs lack validation

The new required initial_image_ref accepts empty, whitespace-containing, full-URI, and malformed digest values even though it is interpolated directly into image_uri; these inputs reach AWS as malformed references and defer the error until Lambda creation. Add input validation for the supported tag and sha256 digest forms.

Context Used: AGENTS.md (source)

Knowledge Base Used: Autoscaling and Lambda Compute Modules

Prompt To Fix With AI
This is a comment left during a code review.
Path: compute/lambda/rvn-lambda-definition.yml
Line: 215-223

Comment:
**Initial image refs lack validation**

The new required `initial_image_ref` accepts empty, whitespace-containing, full-URI, and malformed digest values even though it is interpolated directly into `image_uri`; these inputs reach AWS as malformed references and defer the error until Lambda creation. Add input validation for the supported tag and `sha256` digest forms.

**Context Used:** AGENTS.md ([source](https://github.com/flightcontrolhq/modules/blob/main/AGENTS.md))

**Knowledge Base Used:** [Autoscaling and Lambda Compute Modules](https://app.greptile.com/flightcontrol/-/custom-context/knowledge-base/flightcontrolhq/modules/-/docs/compute-other.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

- id: image_start_command
label: Start command
type: string_array
Expand Down Expand Up @@ -895,6 +907,9 @@ module:
show_when:
lambda_type: regional
package_type: Image
build_source:
- dockerfile
- nixpacks
- id: ecr_scan_on_push_enabled
label: Scan images on push
type: boolean
Expand All @@ -904,6 +919,9 @@ module:
show_when:
lambda_type: regional
package_type: Image
build_source:
- dockerfile
- nixpacks
- id: ecr_force_deletion_enabled
label: Force delete image repository
type: boolean
Expand All @@ -913,6 +931,9 @@ module:
show_when:
lambda_type: regional
package_type: Image
build_source:
- dockerfile
- nixpacks
- $include: ../../partials/inputs/misc-section.yml
- $include: ../../partials/inputs/tags.yml
- $include: ../../partials/inputs/terraform-settings.yml
Expand Down Expand Up @@ -943,7 +964,7 @@ module:
ecr_default_lifecycle_policy_enabled: true
ecr_force_deletion_enabled: << module.input.ecr_force_deletion_enabled >>
ecr_repository_creation_enabled: >-
<< module.input.lambda_type != "edge" && module.input.package_type == "Image" >>
<< module.input.lambda_type != "edge" && module.input.package_type == "Image" && module.input.build_source != "image_registry" >>
ecr_repository_name: << module.input.name >>
ecr_scan_on_push_enabled: << module.input.ecr_scan_on_push_enabled >>
environment_variables: >-
Expand Down Expand Up @@ -974,6 +995,10 @@ module:
(len(module.input.image_start_command || []) > 0 ? module.input.image_start_command : nil), entry_point:
(len(module.input.image_entry_point || []) > 0 ? module.input.image_entry_point : nil),
working_directory: module.input.image_working_directory} : nil) >>
image_uri: >-
<< module.input.lambda_type != "edge" && module.input.package_type == "Image" && module.input.build_source == "image_registry" ?
(module.input.initial_image_ref contains "sha256:" ? module.input.image_repository + "@" + module.input.initial_image_ref :
module.input.image_repository + ":" + module.input.initial_image_ref) : nil >>
kms_key_arn: >-
<< module.input.lambda_type == "edge" ? nil : (module.input.kms_key_arn || nil) >>
lambda_at_edge_enabled: << module.input.lambda_type == "edge" >>
Expand Down
34 changes: 34 additions & 0 deletions compute/lambda/tests/basic.tftest.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,40 @@ run "permissions_and_event_source_mappings" {
}
}

run "image_registry_no_module_ecr" {
command = plan

variables {
package_type = "Image"
runtime = null
handler = null
s3_bucket = null
s3_key = null
ecr_repository_creation_enabled = false
image_uri = "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-function:v1"
}

assert {
condition = aws_lambda_function.this.package_type == "Image"
error_message = "Package type should be Image."
}

assert {
condition = aws_lambda_function.this.image_uri == "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-function:v1"
error_message = "Function should be created from the external image URI."
}

assert {
condition = length(module.ecr) == 0
error_message = "No module-owned ECR repository should be created for external image registries."
}

assert {
condition = length(terraform_data.bootstrap_image) == 0
error_message = "No bootstrap image should be seeded when the image comes from an external registry."
}
}

run "aliases_created" {
command = plan

Expand Down
25 changes: 25 additions & 0 deletions tools/ravion-modules/test/compiler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,31 @@ describe("compiler", () => {
);
});

it("gates the Lambda ECR repository on build source and seeds image-registry creates from an initial ref", async () => {
const compiled = await compileDefinitionFile(join(repoRoot, "compute", "lambda", "rvn-lambda-definition.yml"));
const inputs = getModuleInputs(compiled.module);

const initialImageRef = findInput(inputs, "initial_image_ref");
assert.equal(initialImageRef.label, "Initial image tag or digest");
assert.equal(initialImageRef.required, true);
assert.equal(getBuildSourceShowWhen(initialImageRef), "image_registry");

assert.deepEqual(getBuildSourceShowWhen(findInput(inputs, "section_ecr")), ["dockerfile", "nixpacks"]);
assert.deepEqual(getBuildSourceShowWhen(findInput(inputs, "ecr_scan_on_push_enabled")), ["dockerfile", "nixpacks"]);
assert.deepEqual(getBuildSourceShowWhen(findInput(inputs, "ecr_force_deletion_enabled")), ["dockerfile", "nixpacks"]);

assert.equal(
getTerraformVariable(compiled.module, "ecr_repository_creation_enabled"),
'<< module.input.lambda_type != "edge" && module.input.package_type == "Image" && module.input.build_source != "image_registry" >>',
);

const imageUri = assertString(getTerraformVariable(compiled.module, "image_uri"));
assert.match(imageUri, /module\.input\.build_source == "image_registry"/);
assert.match(imageUri, /module\.input\.initial_image_ref contains "sha256:"/);
assert.match(imageUri, /module\.input\.image_repository \+ "@" \+ module\.input\.initial_image_ref/);
assert.match(imageUri, /module\.input\.image_repository \+ ":" \+ module\.input\.initial_image_ref/);
});

it("compiles Railpack inputs and builder object for static builds", async () => {
const compiled = await compileDefinitionFile(join(repoRoot, "hosting", "static_site", "rvn-aws-static-definition.yml"));
const inputs = getModuleInputs(compiled.module);
Expand Down
Loading