Skip to content

Commit 13ca1e0

Browse files
authored
Merge pull request #1 from cruxstack/dev
feat: create initial bot implementation
2 parents 783605a + 2994487 commit 13ca1e0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+5576
-1
lines changed

.editorconfig

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[*]
2+
indent_style = space
3+
indent_size = 2
4+
end_of_line = lf
5+
insert_final_newline = true
6+
trim_trailing_whitespace = true
7+
charset = utf-8
8+
9+
[{Dockerfile,Dockerfile.*}]
10+
indent_size = 4
11+
tab_width = 4
12+
13+
[{Makefile,makefile,GNUmakefile}]
14+
indent_style = tab
15+
indent_size = 4
16+
17+
[Makefile.*]
18+
indent_style = tab
19+
indent_size = 4
20+
21+
[**/*.{go,mod,sum}]
22+
indent_style = tab
23+
indent_size = unset
24+
25+
[**/*.py]
26+
indent_size = 4

.env.example

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
APP_DEBUG_ENABLED=true
2+
APP_AWS_CONSOLE_URL=https://console.aws.amazon.com
3+
APP_AWS_ACCESS_PORTAL_URL=
4+
APP_AWS_ACCESS_ROLE_NAME=
5+
APP_AWS_SECURITYHUBV2_REGION=
6+
7+
# Auto-close rules (JSON array) - optional
8+
# APP_AUTO_CLOSE_RULES='[{"name":"auto-close-runs-on-container-mounts","enabled":true,"filters":{"finding_types":["PrivilegeEscalation:Runtime/ContainerMountsHostDirectory"],"resource_tags":[{"name":"provider","value":"runs-on.com"}]},"action":{"status_id":5,"comment":"Auto-closed: Expected behavior for runs-on.com ephemeral runners"},"skip_notification":true}]'
9+
10+
# Auto-close rules from S3 (recommended for large rule sets) - optional
11+
# APP_AUTO_CLOSE_RULES_S3_BUCKET=my-securityhub-rules-bucket
12+
# APP_AUTO_CLOSE_RULES_S3_PREFIX=rules/
13+
14+
# Slack integration (optional - both required to enable Slack notifications)
15+
APP_SLACK_TOKEN=
16+
APP_SLACK_CHANNEL=

.github/.dependabot.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "github-actions"
4+
directory: "/"
5+
schedule:
6+
interval: "daily"

.github/workflows/ci.yaml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: ci
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
lint:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout Code
19+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
20+
21+
- name: Setup Go
22+
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
23+
with:
24+
go-version: '1.24'
25+
26+
- name: Run go vet
27+
run: go vet ./...
28+
29+
- name: Check formatting
30+
run: |
31+
unformatted=$(gofmt -l .)
32+
if [ -n "$unformatted" ]; then
33+
echo "following files are not formatted:"
34+
echo "$unformatted"
35+
exit 1
36+
fi
37+
38+
test:
39+
runs-on: ubuntu-latest
40+
steps:
41+
- name: Checkout Code
42+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
43+
44+
- name: Setup Go
45+
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
46+
with:
47+
go-version: '1.24'
48+
49+
- name: Run Tests
50+
run: make test
51+
52+
- name: Run Verify Tests
53+
run: make test-verify-verbose
54+
55+
build:
56+
runs-on: ubuntu-latest
57+
steps:
58+
- name: Checkout Code
59+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
60+
61+
- name: Setup Go
62+
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
63+
with:
64+
go-version: '1.24'
65+
66+
- name: Build Lambda
67+
run: GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -C cmd/lambda -o ../../dist/bootstrap

.github/workflows/release.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: release
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout Code
16+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
17+
- name: Bump Version
18+
id: tag_version
19+
uses: mathieudutour/github-tag-action@a22cf08638b34d5badda920f9daf6e72c477b07b # v6.2
20+
with:
21+
github_token: ${{ secrets.GITHUB_TOKEN }}
22+
default_bump: minor
23+
custom_release_rules: bug:patch:Fixes,chore:patch:Chores,docs:patch:Documentation,feat:minor:Features,refactor:minor:Refactors,test:patch:Tests,ci:patch:Development,dev:patch:Development
24+
- name: Create Release
25+
uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0
26+
with:
27+
tag: ${{ steps.tag_version.outputs.new_tag }}
28+
name: ${{ steps.tag_version.outputs.new_tag }}
29+
body: ${{ steps.tag_version.outputs.changelog }}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: semantic-check
2+
on:
3+
pull_request_target:
4+
types:
5+
- opened
6+
- edited
7+
- synchronize
8+
9+
permissions:
10+
contents: read
11+
pull-requests: read
12+
13+
jobs:
14+
main:
15+
name: Semantic Commit Message Check
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout Code
19+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
20+
- uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
21+
name: Check PR for Semantic Commit Message
22+
env:
23+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24+
with:
25+
requireScope: false
26+
validateSingleCommit: true

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
!**/.gitkeep
2+
3+
tmp/
4+
dist/
5+
.DS_Store
6+
7+
.local/
8+
.env

AGENTS.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Agent Guidelines
2+
3+
## Build & Test
4+
- **Build Lambda**: `GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -C cmd/lambda -o ../../dist/bootstrap`
5+
- **Test all**: `make test` (runs with `-race -count=1`)
6+
- **Test single package**: `go test -race -count=1 ./internal/filters`
7+
- **Test single function**: `go test -race -count=1 ./internal/filters -run TestFilterEngine_FindMatchingRule_RunsOnExample`
8+
- **Run sample locally**: `go run -C cmd/sample .` (requires `.env` file and AWS credentials for auto-close testing)
9+
- **Lint**: `go vet ./...` and `gofmt -l .`
10+
11+
## Code Style
12+
- **Imports**: stdlib, then blank line, then third-party, then local (e.g., `internal/`)
13+
- **Naming**: Go standard - `PascalCase` exports, `camelCase` private, `ALL_CAPS` for env vars prefixed with `APP_`
14+
- **Error handling**: return errors up the stack; use `fmt.Errorf` for wrapping
15+
- **Structs**: define types in package, constructors as `New()` or `NewTypeName()`; all methods must be public (PascalCase)
16+
- **Interfaces**: keep minimal (e.g., `SecurityHubEvent` has 2 methods)
17+
- **Formatting**: use `gofmt` (tabs for indentation)
18+
- **Comments**: rare, lowercase, short, concise; code should be self-documenting
19+
- **Code smells**: keep to minimum; prefer clear naming over comments
20+
21+
## Architecture
22+
- `cmd/lambda/main.go` - Lambda handler entry point
23+
- `cmd/sample/main.go` - Local development runner using fixtures
24+
- `internal/app/` - Core application logic and configuration
25+
- `internal/events/` - OCSF event parsing and Slack message formatting
26+
- `internal/filters/` - Auto-close rule engine and filter matching logic
27+
- `internal/actions/` - Finding update actions (auto-close via BatchUpdateFindingsV2)
28+
- `internal/notifiers/` - Optional notification integrations (Slack)
29+
- `fixtures/samples.json` - Sample Security Hub v2 OCSF findings for testing
30+
31+
## Important Notes
32+
- This project is specifically for **AWS Security Hub v2** which uses OCSF (Open Cybersecurity Schema Framework) format
33+
- It is NOT compatible with the original AWS Security Hub (now called Security Hub CSPM) ASFF format
34+
- Security Hub v2 centralizes findings from GuardDuty, Inspector, Macie, IAM Access Analyzer, and Security Hub CSPM
35+
- Events use OCSF fields like `finding_info`, `metadata`, `severity`, `class_name`, etc.
36+
- Auto-close rules use **BatchUpdateFindingsV2** API (not BatchUpdateFindings)
37+
- Slack integration is **optional** - bot works without Slack if only auto-close is needed
38+
- Rules are evaluated in order; first match wins
39+
- Filter matching uses AND logic - all specified filters must match

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Crux Stack
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# set mac-only linker flags only for go test (not global)
2+
UNAME_S := $(shell uname -s)
3+
TEST_ENV :=
4+
ifeq ($(UNAME_S),Darwin)
5+
TEST_ENV = CGO_LDFLAGS=-w
6+
endif
7+
8+
TEST_FLAGS := -race -count=1
9+
.PHONY: build-debug
10+
build-debug:
11+
GOOS=$(GOOS) GOARCH=$(GOARCH) go build -trimpath -ldflags "-s -w" -o dist/sample ./cmd/sample
12+
13+
.PHONY: debug
14+
debug:
15+
go run ./cmd/sample
16+
17+
.PHONY: test
18+
test:
19+
$(TEST_ENV) go test $(TEST_FLAGS) $$(go list ./... | grep -v tmp/)
20+
21+
.PHONY: test-unit
22+
test-unit:
23+
$(TEST_ENV) go test $(TEST_FLAGS) ./internal/...
24+
25+
.PHONY: test-verify
26+
test-verify:
27+
go run ./cmd/verify
28+
29+
.PHONY: test-verify-verbose
30+
test-verify-verbose:
31+
go run ./cmd/verify -verbose
32+

0 commit comments

Comments
 (0)