Skip to main content

BUILD SLACK PAYLOADS FROM GITHUB SECURITY ALERT RUNS

This guide shows you how to merge one run of the Dependabot, code scanning and secret scanning alert behaviors into one Slack Block Kit payload per repository with open alerts. It also shows how the build behaves when a scanner's results leave out a requested repository.

Prerequisites

Pull the extension

swamp extension pull @hivemq/github

The output looks like:

INF extension·pull: Pulling "@hivemq/github"@"2026.08.27.1787839782"
INF extension·pull: Identity verified: "@hivemq/github"@"2026.08.27.1787839782"
INF extension·pull: Pulled "@hivemq/github"@"2026.08.27.1787839782"
INF extension·pull: Extracted 21 files:

Create the security-alerts behavior

Create a behavior named slack-alerts of type @hivemq/github/security-alerts. Its only global argument is org, the organization that every scanner run must belong to:

globalArguments:
  org: example-org

Create and Run a Behavior shows the create command.

Know the build inputs

The build method takes four inputs:

  • repos, an array of the repository names that must be covered
  • dependabot, codeScanning and secretScanning, one object per scanner

Each scanner object has org, capturedAt and repos. Every entry in repos has org, repo, capturedAt, unavailable (a string or null), truncated and alerts. This is the shape of an alert behavior's run resource. Pass the objects as JSON with the :json= suffix.

Build the payloads

Run build with results from all three scanners covering api. In this example, Dependabot reports one open alert:

swamp behavior run slack-alerts build \
  --input 'repos:json=["api"]' \
  --input 'dependabot:json={"org":"example-org","capturedAt":"2026-10-15T09:00:00Z","repos":[{"org":"example-org","repo":"api","capturedAt":"2026-10-15T09:00:00Z","unavailable":null,"truncated":false,"alerts":[{"number":12,"htmlUrl":"https://github.com/example-org/api/security/dependabot/12","title":"Prototype pollution in lodash","severity":"high"}]}]}' \
  --input 'codeScanning:json={"org":"example-org","capturedAt":"2026-10-15T09:00:00Z","repos":[{"org":"example-org","repo":"api","capturedAt":"2026-10-15T09:00:00Z","unavailable":null,"truncated":false,"alerts":[]}]}' \
  --input 'secretScanning:json={"org":"example-org","capturedAt":"2026-10-15T09:00:00Z","repos":[{"org":"example-org","repo":"api","capturedAt":"2026-10-15T09:00:00Z","unavailable":null,"truncated":false,"alerts":[]}]}'

This checks that every scanner covers api in example-org. It then writes a payloads resource holding the Slack payload for api, with the blocks JSON-stringified so they can go straight to a Slack behavior's postBlocks method.

Check the coverage gate

If you request a repository that a scanner's results do not include, the build fails and writes nothing:

swamp behavior run slack-alerts build \
  --input 'repos:json=["api","web"]' \
  --input 'dependabot:json={"org":"example-org","capturedAt":"2026-10-15T09:00:00Z","repos":[{"org":"example-org","repo":"api","capturedAt":"2026-10-15T09:00:00Z","unavailable":null,"truncated":false,"alerts":[]}]}' \
  --input 'codeScanning:json={"org":"example-org","capturedAt":"2026-10-15T09:00:00Z","repos":[{"org":"example-org","repo":"api","capturedAt":"2026-10-15T09:00:00Z","unavailable":null,"truncated":false,"alerts":[]}]}' \
  --input 'secretScanning:json={"org":"example-org","capturedAt":"2026-10-15T09:00:00Z","repos":[{"org":"example-org","repo":"api","capturedAt":"2026-10-15T09:00:00Z","unavailable":null,"truncated":false,"alerts":[]}]}'

This requests api and web while every scanner covers only api, so the method stops at the coverage gap and writes no payloads resource.

If a real run fails this way, run the missing scanner again with the full repository list, then build again.

Wire the build into a workflow

In a workflow, do not pass JSON by hand. Run the three alert behaviors' list methods first, then pass their run resources to the dependabot, codeScanning and secretScanning inputs of build with CEL expressions. Refer to CEL Expressions and Workflows for the syntax. Read the stored payloads resource with Query and Manage Data.