Skip to content

Commit

Permalink
Stream Cirrus CI webhook events to DataDog (#2)
Browse files Browse the repository at this point in the history
* Stream Cirrus CI webhook events to DataDog

* Run golangci-lint

* Release binaries and container image

* Enrich DataDog events with tags

* Webhook event type is also a tag

* README.md: document DataDog processor

* Dockerfile: proper --from=builder path

* .cirrus.yml: remove dependency on "Test (macOS)" task

* README.md: add usage section

* Support sending events via the Datadog API
  • Loading branch information
edigaryev authored Jul 13, 2023
1 parent 180317e commit 1617ce1
Show file tree
Hide file tree
Showing 17 changed files with 817 additions and 2 deletions.
4 changes: 4 additions & 0 deletions .cirrus.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
load("github.com/cirrus-modules/golang@main", "lint_task")

def main(ctx):
return [lint_task()]
32 changes: 32 additions & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
task:
name: Release Binaries
only_if: $CIRRUS_TAG != ''
depends_on:
- Lint
env:
GITHUB_TOKEN: ENCRYPTED[!98ace8259c6024da912c14d5a3c5c6aac186890a8d4819fad78f3e0c41a4e0cd3a2537dd6e91493952fb056fa434be7c!]
container:
image: goreleaser/goreleaser:latest
cpu: 4
memory: 12G
release_script: goreleaser


docker_builder:
name: Release Docker Image
only_if: $CIRRUS_TAG != ''
depends_on:
- Lint
env:
GITHUB_TOKEN: ENCRYPTED[!82ed873afdf627284305afef4958c85a8f73127b09978a9786ac521559630ea6c9a5ab6e7f8315abf9ead09b6eff6eae!]
login_script:
- echo $GITHUB_TOKEN | docker login ghcr.io -u fkorotkov --password-stdin
setup_script:
- docker buildx create --name multibuilder
- docker buildx use multibuilder
- docker buildx inspect --bootstrap
deploy_script: |
docker buildx build --push --platform linux/amd64,linux/arm64 \
--tag ghcr.io/cirruslabs/cirrus-webhooks-server:$CIRRUS_TAG \
--tag ghcr.io/cirruslabs/cirrus-webhooks-server:latest \
.
122 changes: 122 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
run:
timeout: 5m

linters-settings:
# Even in Rust you can get away with partial matching,
# so make sure that the linter respects the programmer's
# intent expressed in the form of "default" case.
exhaustive:
default-signifies-exhaustive: true

linters:
enable:
- asciicheck
- bodyclose
- dupl
- errcheck
- exhaustive
- exportloopref
- exportloopref
- gochecknoinits
- gocognit
- goconst
- gocritic
- gocyclo
- godot
- godox
- goerr113
- gofmt
- goheader
- gomodguard
- goprintffuncname
- gosec
- gosimple
- govet
- ineffassign
- lll
- makezero
- misspell
- nakedret
- nestif
- noctx
- nolintlint
- predeclared
- rowserrcheck
- sqlclosecheck
- staticcheck
- stylecheck
- testpackage
- tparallel
- typecheck
- unconvert
- unparam
- unused
- unused
- whitespace

disable:
# Messages like "struct of size 104 bytes could be of size 96 bytes" from a package
# that was last updated 2 years ago[1] are barely helpful.
#
# After all, we're writing the code for other people, so let's trust the compiler here (that's
# constantly evolving compared to this linter) and revisit this if memory usage becomes a problem.
#
# [1]: https://github.com/mdempsky/maligned/commit/6e39bd26a8c8b58c5a22129593044655a9e25959
- maligned

# We don't have high-performance requirements at this moment, so sacrificing
# the code readability for marginal performance gains is not worth it.
- prealloc

# New linters that require a lot of codebase churn and noise, but perhaps we can enable them in the future.
- nlreturn
- wrapcheck
- errorlint

# Unfortunately, we use globals due to how spf13/cobra works.
- gochecknoglobals

# That's fine that some Proto objects don't have all fields initialized
- exhaustivestruct

# Style linters that are total nuts.
- wsl
- gofumpt
- goimports
- funlen

# This conflicts with the Protocol Buffers Version 3 design,
# which is largely based on default values for struct fields.
- exhaustivestruct

# Enough parallelism for now.
- paralleltest

# Ill-based assumptions about identifiers like fmt.Println without taking context into account.
- forbidigo

# Advantages of using t.Helper() are too small to waste developer's cognitive stamina on it.
- thelper

# Too restrictive defaults, plus there's already a gocyclo linter in place.
- cyclop

# Gives false positives for textbook examples[1][2]
# [1]: https://github.com/charithe/durationcheck/issues/7
# [2]: https://golang.org/pkg/time/ (see "To convert an integer number of units to a Duration, multiply:")
- durationcheck

# No way to disable the "exported" check for the whole project[1]
# [1]: https://github.com/mgechev/revive/issues/244#issuecomment-560512162
- revive

# Unfortunately too much false-positives, e.g. for a 0700 umask or number 10 when using strconv.FormatInt()
- gomnd

# Needs package whitelists
- depguard

issues:
# Don't hide multiple issues that belong to one class since GitHub annotations can handle them all nicely.
max-issues-per-linter: 0
max-same-issues: 0
26 changes: 26 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
project_name: cws

before:
hooks:
- go mod download

builds:
- main: cmd/cws.go
env:
- CGO_ENABLED=0
goos:
- linux
- darwin
goarch:
- amd64
- arm64

archives:
- id: binary
format: binary
name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}"
- id: regular
name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}"

release:
prerelease: auto
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM goreleaser/goreleaser:latest as builder

WORKDIR /build/
ADD . /build/

RUN goreleaser build --single-target --snapshot

FROM gcr.io/distroless/base

LABEL org.opencontainers.image.source=https://github.com/cirruslabs/cirrus-webhooks-server

COPY --from=builder /build/dist/cws_linux_*/cws /bin/cws

ENTRYPOINT ["/bin/cws"]
55 changes: 53 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,53 @@
# cirrus-webhooks-server-example
Example of a simple server that processes webhook events from Cirrus CI
# Cirrus Webhooks Server

Examples of the webhook event processors from the Cirrus CI.

## Datadog processor

This processor receives, enriches and streams Cirrus CI webhook events to Datadog.

### Usage

```
docker run -it --rm ghcr.io/cirruslabs/cirrus-webhooks-server:latest datadog
```

The following command-line arguments are supported:

* `--api-key` (`string`) — enables sending events via the Datadog API using the specified API key
* `--api-site` (`string`) — specifies the [Datadog site](https://docs.datadoghq.com/getting_started/site/) to use when sending events via the Datadog API (defaults to `datadoghq.com`)
* `--dogstatsd-addr` — enables sending events via the DogStatsD protocol to the specified address (for example, `--dogstatsd-addr=127.0.0.1:8125`)
* `--event-type` (`string`) — event type to process (for example `build`, `task` or `audit_event`) (defaults to `audit_event`)
* `--http-addr` (`string`) — address on which the HTTP server will listen on (defaults to `:8080`)
* `--http-path` (`string`) — HTTP path on which the webhook events will be expected (defaults to `/`)
* `--secret-token` (`string`) — if specified, this value will be used as a HMAC SHA-256 secret to verify the webhook events

### Example

The simplest way to try this processor is to use Docker and [ngrok](https://ngrok.com/).

First, obtain the API key from the Datadog's `Organization Settings``API Keys`.

Then, run the Datadog processor:

```sh
docker run -it --rm -p 8080:8080 ghcr.io/cirruslabs/cirrus-webhooks-server:latest datadog --api-key=$DD_API_KEY
```

Finally, [install](https://ngrok.com/download) and run `ngrok` to expose our Datadog processor's HTTP server to the internet:

```sh
ngrok http 8080
```

This will open the following TUI window:

![](docs/ngrok-http-8080.png)

You'll need to copy the forwarding address and set it in your organization's settings in the Cirrus CI app:

![](docs/cirrus-ci-webhook-settings.png)

Now you can run some tasks, and the corresponding audit events will appear shortly in your "Events Explorer":

![](docs/datadog-webhook-event.png)
22 changes: 22 additions & 0 deletions cmd/cws.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package main

import (
"context"
"github.com/cirruslabs/cirrus-webhooks-server/internal/command"
"log"
"os"
"os/signal"
)

func main() {
// Set up a signal-interruptible context
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)

// Run the command
if err := command.NewRootCmd().ExecuteContext(ctx); err != nil {
cancel()
log.Fatal(err)
}

cancel()
}
Binary file added docs/cirrus-ci-webhook-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/datadog-webhook-event.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/ngrok-http-8080.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module github.com/cirruslabs/cirrus-webhooks-server

go 1.20

require (
github.com/DataDog/datadog-api-client-go/v2 v2.14.0
github.com/DataDog/datadog-go/v5 v5.3.0
github.com/brpaz/echozap v1.1.3
github.com/labstack/echo/v4 v4.10.2
github.com/spf13/cobra v1.7.0
go.uber.org/zap v1.24.0
)

require (
github.com/DataDog/zstd v1.5.2 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/labstack/gommon v0.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.11.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/oauth2 v0.5.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/tools v0.11.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
)
Loading

0 comments on commit 1617ce1

Please sign in to comment.