Skip to content
Closed
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
55 changes: 55 additions & 0 deletions .github/workflows/pr-linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,58 @@ jobs:
PR_SHA: ${{ needs.download-if-workflow-run.outputs.pr_sha }}
LINTER_LOGIN: ${{ vars.LINTER_LOGIN }}
REPO_ROOT: ${{ github.workspace }}

- name: Get list of changed .template.json files
id: filter_files
run: |
echo "Getting changed CloudFormation templates..."
mkdir -p changed_templates

git fetch origin main --depth=1

base_sha="${{ github.event.pull_request.base.sha }}"
head_sha="${{ github.event.pull_request.head.sha }}"
if [[ -z "$base_sha" ]]; then base_sha=$(git merge-base origin/main HEAD); fi
if [[ -z "$head_sha" ]]; then head_sha=HEAD; fi

git diff --name-status "$base_sha" "$head_sha" \
| grep -E '^(A|M)\s+.*\.template\.json$' \
| awk '{print $2}' > changed_files.txt || true

while IFS= read -r file; do
if [ -f "$file" ]; then
safe_name=$(echo "$file" | sed 's|/|_|g')
cp "$file" "changed_templates/$safe_name"
else
echo "::warning::Changed file not found in workspace: $file"
fi
done < changed_files.txt

if [ -s changed_files.txt ]; then
echo "files_changed=true" >> $GITHUB_OUTPUT
else
echo "files_changed=false" >> $GITHUB_OUTPUT
fi

- name: Install cfn-guard
if: steps.filter_files.outputs.files_changed == 'true'
run: |
mkdir -p $HOME/.local/bin
curl -L -o cfn-guard.tar.gz https://github.com/aws-cloudformation/cloudformation-guard/releases/latest/download/cfn-guard-v3-x86_64-ubuntu-latest.tar.gz
tar -xzf cfn-guard.tar.gz
mv cfn-guard-v3-*/cfn-guard $HOME/.local/bin/cfn-guard
chmod +x $HOME/.local/bin/cfn-guard
echo "$HOME/.local/bin" >> $GITHUB_PATH

- name: Install & Build cfn-guard-custom-rules-tool
if: steps.filter_files.outputs.files_changed == 'true'
run: yarn install --frozen-lockfile && cd tools/@aws-cdk/cfn-guard-custom-rules-tool && yarn build

- name: Run cfn-guard if templates changed
if: steps.filter_files.outputs.files_changed == 'true'
uses: ./tools/@aws-cdk/cfn-guard-custom-rules-tool
with:
data_directory: './changed_templates'
rule_set_path: './tools/@aws-cdk/cfn-guard-custom-rules-tool/rules/trust_scope_rules.guard'
show_summary: 'fail'
output_format: 'single-line-summary'
5 changes: 5 additions & 0 deletions tools/@aws-cdk/cfn-guard-custom-rules-tool/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.js
*.js.map
*.d.ts
dist
node_modules
94 changes: 94 additions & 0 deletions tools/@aws-cdk/cfn-guard-custom-rules-tool/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# CFN Guard Custom Rules Validator

A GitHub Action tool designed to validate changed AWS CloudFormation templates against custom [cfn-guard](https://github.com/aws-cloudformation/cloudformation-guard) rules. Supports both local paths and remote URLs for rule sets.

---

## 🚀 Features

- Validates only changed `*.template.json` files in PRs
- Supports `cfn-guard v3`
- Accepts rules from a local file or remote URL
- Outputs validation results in summary format

---

## 📦 Inputs

| Name | Description | Required | Default |
|------------------|-------------------------------------------------------------------|----------|---------|
| `data_directory` | Directory containing templates to validate | ✅ Yes | |
| `rule_file_path` | Local path to the rules file | ❌ No | |
| `rule_set_url` | Remote URL pointing to rules file | ❌ No | |
| `show_summary` | Whether to show summary output (`fail`, `warn`, `none`) | ❌ No | `fail` |
| `output_format` | Output format (`single-line-summary`, `json`, etc.) | ❌ No | `single-line-summary` |

> Either `rule_file_path` or `rule_set_url` must be set.

---

## 🛠️ Usage

```yaml
- name: Run CFN Guard
uses: ./tools/@aws-cdk/cfn-guard-custom-rules-tool
with:
data_directory: './changed_templates'
rule_set_path: './tools/@aws-cdk/cfn-guard-custom-rules-tool/rules/trust_scope_rules.guard'
show_summary: 'fail'
output_format: 'single-line-summary'
```

---

## 🧪 Local Development

### 1. Build
```bash
npm install
npm run build
```

### 2. Run Locally
```bash
node dist/index.js \
--data_directory=./changed_templates \
--rule_file_path=./rules.guard \
--output_format=single-line-summary \
--show_summary=fail
```

---

## 📝 License

```text
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```

---

## 👏 Contributing

PRs are welcome! Please follow conventional commit messages and test your changes before opening a pull request.

---

## 📣 Acknowledgments

Built on top of [cfn-guard](https://github.com/aws-cloudformation/cloudformation-guard) and [GitHub Actions Toolkit](https://github.com/actions/toolkit).

---

Happy Guarding! 🛡️

30 changes: 30 additions & 0 deletions tools/@aws-cdk/cfn-guard-custom-rules-tool/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: 'cfn-guard-custom-rules-tool'
description: 'CFN Guard for custom or granular guard rules'
author: QuantumNeuralCoder

inputs:
data_directory:
description: "Path to CloudFormation templates"
required: true
rule_set_path:
description: "Path to a single .guard file locally"
required: false
rule_set_url:
description: "URL to a single .guard file on GitHub"
required: false
show_summary:
description: "cfn-guard summary output. Options are all, pass, fail, skip or none"
required: false
default: "fail"
output_format:
description: "cfn-guard output format. Options: json, yaml, single-line-summary"
required: false
default: "single-line-summary"

runs:
using: node20
main: dist/index.js

branding:
icon: shield
color: red
116 changes: 116 additions & 0 deletions tools/@aws-cdk/cfn-guard-custom-rules-tool/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions tools/@aws-cdk/cfn-guard-custom-rules-tool/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "cfn-guard-custom-rules-tool",
"version": "1.0.0",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"prepare": "npm run build"
},
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/exec": "^1.1.1"
},
"devDependencies": {
"@types/node": "^22.14.0",
"typescript": "^5.2.2"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Trust Scope Security Rules
# This rule file checks for overly broad trust scopes in IAM resources

# Rule to check for overly permissive IAM role trust policies
rule iam_role_trust_policy_not_overly_permissive {
AWS::IAM::Role {
Properties exists
Properties is_struct

Properties.AssumeRolePolicyDocument exists
Properties.AssumeRolePolicyDocument is_struct

Properties.AssumeRolePolicyDocument {
Statement exists
Statement is_list

# For each statement in the policy
Statement[*] {
# Check if Principal is overly permissive
when Principal exists {
# Check if Principal is a string (direct "*" case)
when Principal is_string {
Principal != "*"
}

# Check if AWS principal exists
when Principal.AWS exists {
# Check if AWS is a string
when Principal.AWS is_string {
Principal.AWS != "*"
Principal.AWS != /(?i):root/
}
}
}
}
}
}
}

Loading
Loading