functions/ directory. The following tools and conventions are used in the project.
Prerequisites
Install pipenv before running any of the commands below.Install dependencies
From within thefunctions/ directory, install all Python dependencies including development tools:
Pipfile, sync your local virtualenv:
Development dependencies (from Pipfile)
| Package | Version | Purpose |
|---|---|---|
boto3 | ~=1.34 | AWS SDK (mocked in tests) |
botocore | ~=1.34 | AWS SDK core |
pytest | latest | Test runner |
pytest-cov | latest | Coverage reports |
snapshottest | ~=0.6 | Snapshot testing |
black | latest | Code formatter |
isort | latest | Import sorter |
flake8 | latest | Linter |
radon | latest | Code complexity analysis |
mypy | latest | Type checker |
Running tests
ThePipfile defines named scripts for all common tasks. Run them from within the functions/ directory.
Unit tests
pytest with coverage reporting (--cov --cov-report=term). The test file is notify_slack_test.py.
All available scripts
| Script | Command | Description |
|---|---|---|
test | python3 -m pytest --cov --cov-report=term | Run tests with coverage |
test:updatesnapshots | python3 -m pytest --snapshot-update | Regenerate snapshot files |
cover | python3 -m coverage html | Generate HTML coverage report |
lint | python3 -m flake8 . --count --statistics ... | Show linting errors (non-blocking) |
lint:ci | python3 -m flake8 . --config=.flake8 | Lint with exit code (for CI) |
format | python3 -m black . | Auto-format all Python files |
imports | python3 -m isort . --profile black | Sort import statements |
typecheck | python3 -m mypy . --ignore-missing-imports | Run type checks |
complexity | python3 -m radon cc notify_slack.py -a | Show cyclomatic complexity |
halstead | python3 -m radon hal notify_slack.py | Show Halstead metrics |
Directory structure
events/
Contains raw event JSON files as they are emitted by AWS services (for example, guardduty_finding.json or cloudwatch_alarm.json). These match the event formats documented in the AWS documentation.
messages/
Contains SNS message payloads in the form delivered to the Lambda function. The Message attribute holds the payload that is parsed and sent to Slack — this can be an event from events/ or any plain string.
snapshots/
Contains snapshot files generated by snapshottest. Each snapshot records the expected Slack message payload for a given input. Tests fail if the output differs from the stored snapshot, making regressions visible immediately.
Snapshots should only change when the expected Slack output changes intentionally. When you update a snapshot, explain why in your pull request.
Snapshot testing workflow
When you change the output format of any formatter, update the snapshots:Auto-format the generated code
The snapshot files follow their own style; run the formatter to keep them consistent:
Using mylambda.py as a template
The mylambda.py file is a minimal custom Lambda function you can use as a starting point when you need behaviour different from the built-in notify_slack.py.
mylambda.py to your Terraform root module and set:
my_custom_function.py becomes my_custom_function.lambda_handler.
Integration tests
Integration tests send real notifications to a live Slack channel. They require a deployed module and an active webhook URL.Create a test Slack channel and webhook
Set up a dedicated Slack channel as a sandbox and create an incoming webhook for it. See the Slack incoming webhooks documentation for details.
Deploy the example module
From within
examples/notify-slack-simple/, set your Slack variables and apply:Run the integration tests
From within the One Slack message should arrive per file in
functions/ directory:functions/events/ and functions/messages/.Adding support for new event types
To add a new event type with custom formatting:Add a sample event payload
Create a JSON file in
functions/events/ named using snake case: <service>_<event_type>.json (for example, codepipeline_execution.json).Write a formatter function
In
notify_slack.py, add a function named format_<service>_<event_type>(). Follow the existing pattern: accept message and region arguments and return a Slack attachment dict.Add severity enum (optional)
If the event has severity levels that map to Slack colour bars, create an enum following the
CloudWatchAlarmState or GuardDutyFindingSeverity pattern.Register the event in `parse_notification()`
Add a detection condition to
parse_notification() that calls your new formatter.