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
118 changes: 118 additions & 0 deletions .github/workflows/security-guardian.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
name: Security Guardian
on:
pull_request: {}

# Triggered from a separate job when a review is added
workflow_run:
workflows: [PR Linter Trigger]
types:
- completed

# Trigger when a status is updated (CodeBuild leads to statuses)
status: {}

# Trigger when a check suite is completed (GitHub actions and CodeCov create checks)
check_suite:
types: [completed]

jobs:
download-if-workflow-run:
runs-on: ubuntu-latest
outputs:
pr_number: ${{ steps.pr_output.outputs.pr_number }}
pr_sha: ${{ steps.pr_output.outputs.pr_sha }}
# if conditions on all individual steps because subsequent jobs depend on this job
# and we cannot skip it entirely
steps:
- name: 'Download workflow_run artifact'
if: github.event_name == 'workflow_run'
uses: dawidd6/action-download-artifact@v9
with:
run_id: ${{ github.event.workflow_run.id }}
name: pr_info
path: pr/
search_artifacts: true

- name: 'Determine PR info'
# PR info comes from the artifact if downloaded, or GitHub context if not.
if: github.event_name == 'workflow_run'
id: 'pr_output'
run: |
if [[ ! -f pr/pr_number ]]; then
echo "${{ github.event.pull_request.number }}" > pr/pr_number
fi
if [[ ! -f pr/pr_sha ]]; then
echo "${{ github.event.pull_request.head.sha }}" > pr/pr_sha
fi
cat pr/*
echo "pr_number=$(cat pr/pr_number)" >> "$GITHUB_OUTPUT"
echo "pr_sha=$(cat pr/pr_sha)" >> "$GITHUB_OUTPUT"

run-security-guardian:
# Necessary to have sufficient permissions to write to the PR
permissions:
contents: read
pull-requests: write
statuses: read
issues: read
checks: read
runs-on: ubuntu-latest
needs: download-if-workflow-run
steps:
- name: Checkout
uses: actions/checkout@v4

- 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 security-guardian
if: steps.filter_files.outputs.files_changed == 'true'
run: yarn install --frozen-lockfile && cd tools/@aws-cdk/security-guardian && yarn build

- name: Run cfn-guard if templates changed
if: steps.filter_files.outputs.files_changed == 'true'
uses: ./tools/@aws-cdk/security-guardian
with:
data_directory: './changed_templates'
rule_set_path: './tools/@aws-cdk/security-guardian/rules/trust_scope_rules.guard'
show_summary: 'fail'
output_format: 'single-line-summary'
Binary file not shown.
Binary file not shown.
5 changes: 5 additions & 0 deletions tools/@aws-cdk/security-guardian/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.js
*.js.map
*.d.ts
dist
node_modules
93 changes: 93 additions & 0 deletions tools/@aws-cdk/security-guardian/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Security Guardian

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 | ✅ Yes | |
| `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` |

> `data_directory` and `rule_file_path` must be set.

---

## 🛠️ Usage

```yaml
- name: Run CFN Guard
uses: ./tools/@aws-cdk/security-guardian
with:
data_directory: './changed_templates'
rule_set_path: './tools/@aws-cdk/security-guardian/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! 🛡️

26 changes: 26 additions & 0 deletions tools/@aws-cdk/security-guardian/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: 'Security Guardian'
description: 'Security Guardian for custom or granular guard rules'

inputs:
data_directory:
description: "Path to CloudFormation templates"
required: true
rule_set_path:
description: "Path to a single .guard file locally"
required: true
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/security-guardian/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/security-guardian/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "security-guardian",
"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"
}
}
Loading
Loading