Skip to content
Open
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
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.git
bin
dist
8 changes: 8 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,11 @@ updates:
- dependency-name: github.com/gorilla/handlers
versions:
- 1.5.1
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
- package-ecosystem: docker
directory: "/"
schedule:
interval: weekly
24 changes: 2 additions & 22 deletions .github/workflows/ci-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,5 @@ permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
go: [ '1.27' ]
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: ${{ matrix.go }}
- name: Run unit tests
run: go test -race ./...
- name: Run static checks
run: go vet ./...
- name: Run acceptance tests
run: make acceptance
- name: Check for vulnerabilities
run: |
go run golang.org/x/vuln/cmd/govulncheck@v1.9.0 ./...
go run golang.org/x/vuln/cmd/govulncheck@v1.9.0 -tags=acceptance ./...
validate:
uses: ./.github/workflows/validate.yml
26 changes: 18 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,17 @@ on:
tags:
- 'v*.*.*'

permissions:
contents: read

jobs:
validate:
uses: ./.github/workflows/validate.yml

release:
needs: validate
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand All @@ -18,47 +27,48 @@ jobs:
with:
go-version: '1.27'
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v4
uses: goreleaser/goreleaser-action@a4f02ab5355a589de60d917a659ce617ed19b3de # v7.3.0
if: startsWith(github.ref, 'refs/tags/')
with:
distribution: goreleaser
version: latest
version: v2.19.0
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_RELEASER: ${{ secrets.GH_RELEASER }}
docker-hub:
needs: release
needs: [validate, release]
name: Deploy to DockerHub
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

- name: Login to DockerHub
uses: docker/login-action@v3
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}

- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ${{ github.repository }}
tags: |
type=ref,event=tag

- name: Build and push to docker registry
if: success()
uses: docker/build-push-action@v5
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: .
platforms: linux/amd64,linux/arm64
build-args: VERSION=${{ github.ref_name }}
push: true
tags: ${{ steps.meta.outputs.tags }}
98 changes: 98 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: Validate

on:
workflow_call:

permissions:
contents: read

env:
GO_VERSION: '1.27'

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Run unit tests
run: go test -race ./...
- name: Run static checks
run: |
go vet ./...
go vet -tags=acceptance ./acceptance/...
- name: Run acceptance tests
run: make acceptance
- name: Check for vulnerabilities
run: |
go run golang.org/x/vuln/cmd/govulncheck@v1.9.0 ./...
go run golang.org/x/vuln/cmd/govulncheck@v1.9.0 -tags=acceptance ./...

package:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Install GoReleaser
uses: goreleaser/goreleaser-action@a4f02ab5355a589de60d917a659ce617ed19b3de # v7.3.0
with:
version: v2.19.0
install-only: true
- name: Validate release configuration and build snapshot
run: |
goreleaser check
goreleaser release --snapshot --clean
python3 scripts/check-release-artifacts.py
- name: Run acceptance tests against packaged Linux binary
run: |
mkdir -p bin
tar -xzf dist/*_linux_x86_64.tar.gz -C bin killgrave
./bin/killgrave --version
cd acceptance
go test -count=1 -tags=acceptance ./...

docker:
strategy:
matrix:
arch: [amd64, arm64]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up QEMU
uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0
- name: Set up Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- name: Build image without publishing
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: .
platforms: linux/${{ matrix.arch }}
build-args: VERSION=validation
push: false
load: true
tags: killgrave:validation
- name: Check image version and fixture response
run: |
docker run --rm --platform linux/${{ matrix.arch }} killgrave:validation --version | grep -Fx 'Killgrave version: docker-validation'
mkdir -p "$RUNNER_TEMP/imposters"
cat > "$RUNNER_TEMP/imposters/smoke.imp.json" <<'JSON'
[{"request":{"method":"GET","endpoint":"/release-check"},"response":{"status":200,"body":"release-ok"}}]
JSON
container=$(docker run -d --platform linux/${{ matrix.arch }} -p 127.0.0.1:3000:3000 -v "$RUNNER_TEMP/imposters:/imposters:ro" killgrave:validation --host 0.0.0.0 --imposters /imposters)
trap 'docker logs "$container"; docker rm -f "$container"' EXIT
for attempt in $(seq 1 30); do
if curl --fail --silent http://127.0.0.1:3000/release-check > "$RUNNER_TEMP/response"; then break; fi
sleep 1
done
test "$(cat "$RUNNER_TEMP/response")" = release-ok
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ coverage.txt

imposters

!internal/server/http/test/testdata/imposters/
!internal/server/http/test/testdata/imposters/
# GoReleaser snapshot artifacts
/dist/
27 changes: 20 additions & 7 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
version: 2

builds:
-
-
binary: killgrave
main: ./cmd/killgrave/main.go
ldflags:
ldflags:
- -s -w -X github.com/friendsofgo/killgrave/internal/app/cmd._version={{.Version}}
env:
- CGO_ENABLED=0
Expand Down Expand Up @@ -31,24 +34,34 @@ archives:
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
formats: [tar.gz]
format_overrides:
- goos: windows
format: zip
formats: [zip]
files:
- LICENSE
- README.md
- CHANGELOG.md
brews:
homebrew_casks:
-
name: killgrave
tap:
homepage: https://github.com/friendsofgo/killgrave
repository:
owner: friendsofgo
name: homebrew-tap
token: "{{ .Env.GH_RELEASER }}"
folder: Formula
directory: Casks
binaries:
- killgrave
hooks:
post:
install_steps: |
on_macos do
run "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "{{ .StagedPath }}/killgrave"]
end
description: |
Simple way to generate fake servers
checksum:
name_template: 'checksums.txt'
changelog:
skip: true
disable: true
23 changes: 12 additions & 11 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
FROM golang:1.27-alpine AS build
FROM --platform=$BUILDPLATFORM golang:1.27-alpine AS build

LABEL MAINTAINER = 'Friends of Go (it@friendsofgo.tech)'
LABEL maintainer="Friends of Go (it@friendsofgo.tech)"

ARG TARGETOS=linux
ARG TARGETARCH=amd64

RUN apk add --update git
RUN apk add ca-certificates
RUN apk add --no-cache ca-certificates
WORKDIR /go/src/github.com/friendsofgo/killgrave
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go mod tidy && TAG=$(git describe --tags --abbrev=0) \
&& LDFLAGS=$(echo "-s -w -X github.com/friendsofgo/killgrave/internal/app/cmd._version="docker-$TAG) \
&& CGO_ENABLED=0 GOOS="${TARGETOS}" GOARCH="${TARGETARCH}" go build -a -installsuffix cgo -o /go/bin/killgrave -ldflags "$LDFLAGS" cmd/killgrave/main.go
ARG TARGETOS=linux
ARG TARGETARCH=amd64
ARG VERSION=dev
RUN CGO_ENABLED=0 GOOS="${TARGETOS}" GOARCH="${TARGETARCH}" go build \
-buildvcs=false -trimpath \
-ldflags "-s -w -X github.com/friendsofgo/killgrave/internal/app/cmd._version=docker-${VERSION}" \
-o /go/bin/killgrave ./cmd/killgrave

# Building image with the binary
FROM scratch
COPY --from=build /go/bin/killgrave /go/bin/killgrave
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ You can install Killgrave in different ways, but all of them are very simple:
If you are a Mac user, you can install Killgrave using [Homebrew](https://brew.sh/):

```sh
$ brew install friendsofgo/tap/killgrave
$ brew install --cask friendsofgo/tap/killgrave
```

:warning: If you are installing via Homebrew, you always get the [latest Killgrave version](https://github.com/friendsofgo/killgrave/releases), we hope to fix this soon.
Expand Down Expand Up @@ -561,6 +561,9 @@ In the following example, we have defined multiple imposters for the `POST /goph
````

## Contributing

Release tooling, nonpublishing checks, credentials, and retry steps are documented in [Release maintenance](docs/releases.md).

[Contributions](CONTRIBUTING.md) are more than welcome, if you are interested please follow our guidelines to help you get started.

## License
Expand Down
44 changes: 44 additions & 0 deletions scripts/check-release-artifacts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""Verify the release's supported archives, contents, and SHA-256 checksums."""

import hashlib
from pathlib import Path
import tarfile
import zipfile


def main():
dist = Path("dist")
targets = {
"darwin_arm64", "darwin_x86_64", "freebsd_i386", "freebsd_x86_64",
"linux_arm64", "linux_armv6", "linux_armv7", "linux_i386", "linux_x86_64",
"windows_arm64", "windows_i386", "windows_x86_64",
}
seen = set()
checksums = (dist / "checksums.txt").read_text().splitlines()
for line in checksums:
digest, name = line.split()
path = dist / name
if hashlib.sha256(path.read_bytes()).hexdigest() != digest:
raise ValueError(f"Checksum mismatch: {name}")
target = next((t for t in targets if name.endswith(
"_" + t + (".zip" if t.startswith("windows_") else ".tar.gz")
)), None)
if target is None or target in seen or not name.startswith("killgrave_"):
raise ValueError(f"Unexpected archive: {name}")
seen.add(target)
binary = "killgrave.exe" if target.startswith("windows_") else "killgrave"
if path.suffix == ".zip":
with zipfile.ZipFile(path) as archive:
entries = set(archive.namelist())
else:
with tarfile.open(path) as archive:
entries = set(archive.getnames())
if entries != {binary, "LICENSE", "README.md", "CHANGELOG.md"}:
raise ValueError(f"Unexpected contents in {name}: {entries}")
if seen != targets:
raise ValueError(f"Missing targets: {targets - seen}")
print(f"Verified {len(seen)} release archives and checksums")


if __name__ == "__main__":
main()
Loading