App Integrations
Pull request bot
What the LevelFour bot posts on GitHub pull requests and GitLab merge requests that change Terraform or CloudFormation, and the commands you can reply to it with.
Once GitHub or GitLab is connected, the LevelFour bot reads every pull request or merge request that changes Terraform or CloudFormation. It posts the cost impact of the change back on the request, and it proposes cheaper settings where it finds them. It behaves the same on both providers.
What it reads
| Language | What the bot prices |
|---|---|
| Terraform | The resources in your .tf files |
| CloudFormation | YAML and JSON templates, SAM templates, nested stacks whose TemplateURL or Location names a file in the repository, and AWS::Include snippets from the repository |
A request that changes both gets one cost comment covering both. How it prices a CloudFormation template covers parameters, regions and what the bot cannot read.
What it posts
| Item | Where | What it shows |
|---|---|---|
| Cost comment | The conversation | The cost of the changed resources before and after, and the monthly spend. The bot edits this one comment on each push instead of adding new ones |
| LevelFour status | The checks panel on GitHub, the pipeline status on GitLab | That the analysis ran, and its summary |
| Inline suggestions | On lines in the changed hunks of the diff | A concrete change to a resource, ready to apply |
The LevelFour status reports the analysis, not a budget. On GitHub it passes, or reads neutral when the bot has suggestions for you. On GitLab it passes. It fails only when the analysis itself could not run, so it is not a gate on cost.
The bot posts a suggestion inline on any line of the diff it can comment on, context lines inside a changed hunk included. In a CloudFormation template the value must be written in the resource's own properties: a value that comes from a Parameter default or a Mapping gets no inline suggestion.
A change that touches no Terraform or CloudFormation resources gets no cost comment, and the status says why.
How it prices a CloudFormation template
The bot resolves parameters, conditions, mappings and intrinsic functions before it prices a template. It prices a nested stack inside the template that creates it, with the parameters that template passes down.
Parameter values and the region come from .levelfour/config.yml, then from samconfig, then from the template's own defaults, with us-east-1 as the last resort for the region. PR bot configuration has the order and the parameters file formats.
When the estimate rests on something the bot had to assume, the cost comment lists it under Assumptions:
- a parameter priced at its default
- a condition the bot could not decide, and assumed to hold
- a value CloudFormation reads at deploy time:
Fn::ImportValue, a parameter stored in Systems Manager, a dynamic reference such as{{resolve:ssm:...}}
Read the list before you trust the total. If a stack deploys with values other than its defaults, map its parameters file under cloudformation.parameter_files.
The bot does not price:
- AWS CDK apps. Pricing one needs
cdk synth, which the bot does not run. Run it yourself and pointl4 estimateat the synthesized templates. - Serverless Framework projects (
serverless.yml). - Registry modules, the
::MODULEresource types.
Reply with a command
Mention the bot in a comment on the pull request or merge request, followed by a command. The bot reacts to your comment when it picks it up, then replies or updates the cost comment.
Anyone who can comment can run help. The commands that change something (dismiss, snooze, ignore and apply) need write access to the repository on GitHub, or the Developer role or above on GitLab. The bot answers anyone else with a note saying so.
| Command | What it does |
|---|---|
@levelfourai help | Posts the list of commands |
@levelfourai dismiss <reason> | Dismisses the bot's suggestions on this request. A reason is required |
@levelfourai snooze <reason> | Hides the suggestions until the next push. A reason is required |
@levelfourai ignore <type>.<name> | Leaves one resource out of future analyses |
@levelfourai apply all | Commits every inline suggestion to the request's branch |
@levelfourai apply <type>.<name> | Commits only the suggestions for that resource |
<type>.<name> names the resource in its own language. For Terraform it is the resource address from your .tf files. For CloudFormation it is the resource type, a dot, and the logical ID:
@levelfourai ignore aws_ebs_volume.logs
@levelfourai ignore AWS::EC2::Volume.LogsTwo stacks can declare the same logical ID. Add @ and the stack's scope to name the resource in one stack only. A root stack's scope is its template path. A nested stack's scope is the root template path followed by / and the logical ID of each nested stack resource on the way down, never the nested template's own path:
@levelfourai ignore AWS::EC2::Volume.Logs@stacks/app.yaml
@levelfourai ignore AWS::RDS::DBInstance.Primary@stacks/app.yaml/Database
@levelfourai ignore AWS::RDS::DBInstance.Replica@stacks/app.yaml/Database/ReadReplicasThe second line names Primary in the stack that stacks/app.yaml creates through its Database resource. The third goes one level deeper, through ReadReplicas inside that stack.
Dismissing, snoozing and ignoring add a line to the top of the cost comment naming who did it, and the reason for a dismiss or snooze, so the next reviewer sees the decision.
Applying suggestions
apply writes the suggestions into one commit on the branch and replies with its short SHA. On GitLab it also resolves the suggestion threads it applied. It does not run on a pull request or merge request from a fork, because the fork's branch belongs to its author.
On GitHub, if the branch moved after the bot's last analysis, the bot refuses rather than overwrite newer work. Push, let the cost comment update, and run apply again. apply also needs the LevelFour app to hold write access to repository contents. If it does not, the bot says so, and an organization owner approves the permission in GitHub.
Tune it per repository
A .levelfour/config.yml at the root of the default branch turns the bot off for a repository, drops the inline suggestions, caps how many it posts, skips paths and resource types, or tells the bot which parameters file a template deploys with. PR bot configuration has every field.
Next
- PR bot configuration is the
.levelfour/config.ymlreference - GitHub and GitLab cover connecting each provider
l4 estimateprices the same templates from a terminal or a CI job