Skip to content
Merged
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
16 changes: 16 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Code owners for goceleris/loadgen.
#
# GitHub requests a review from the matching owners on every pull request
# that touches these paths; with "Require review from Code Owners" enabled on
# the main branch protection, their approval is mandatory before merging.
# Later rules take precedence over earlier ones — keep the catch-all first.
#
# Syntax: https://docs.github.com/articles/about-code-owners

# Default owner for everything in the repository.
* @FumingPower3925

# Area delegation example — uncomment and adjust when a second maintainer
# takes ownership of a subsystem (the more specific rule wins):
# /cmd/loadgen/ @FumingPower3925 @WdnLiu
# /.github/ @FumingPower3925
16 changes: 16 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
## Summary

Brief description of the change and why it is needed.

## Changes

-

## Test Plan

- [ ] Unit tests added/updated (`go test -race -count=1 ./...`)
- [ ] `golangci-lint run` and `go vet ./...` pass
- [ ] Integration matrix passes if the H1/H2/WS/SSE client paths changed (`go test -tags integration -run TestIntegrationH2CMatrix .`)
- [ ] README cluster-bench contract updated if the JSON result schema or CLI flags changed

Closes #
31 changes: 31 additions & 0 deletions .github/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Automatically generated release notes (GitHub "Generate release notes").
# Same categories as goceleris/celeris so the org's release pages read alike.
# Labels are applied on the pull request; dependabot / actions bumps are
# excluded because they are noise for consumers of the binaries.
changelog:
exclude:
labels:
- dependencies
- github_actions
categories:
- title: Breaking Changes
labels:
- breaking
- title: Security
labels:
- security
- title: Fixes
labels:
- bug
- fix
- title: Performance
labels:
- performance
- perf
- title: Features
labels:
- enhancement
- feature
- title: Other Changes
labels:
- "*"
20 changes: 13 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ jobs:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.27.0"
- uses: golangci/golangci-lint-action@v9
- uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0
with:
version: v2.13
- name: actionlint
Expand All @@ -33,8 +35,10 @@ jobs:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.27.0"
- name: Run tests
Expand All @@ -45,8 +49,10 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.27.0"
# The testserver helper imports github.com/goceleris/celeris (pinned in
Expand Down
22 changes: 17 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ jobs:
name: Publish to Go Package Registry
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.27.0"
- name: Verify module
Expand All @@ -33,6 +35,10 @@ jobs:
# orchestrators can fetch them without re-cloning + rebuilding.
name: Build cmd/loadgen binaries (${{ matrix.goos }}/${{ matrix.goarch }})
runs-on: ubuntu-latest
permissions:
contents: write # action-gh-release uploads the tarball to the release
id-token: write # OIDC token that signs the SLSA provenance (Sigstore)
attestations: write # store the attestation in the repository's attestation store
strategy:
matrix:
include:
Expand All @@ -45,8 +51,8 @@ jobs:
- goos: darwin
goarch: arm64
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.27.0"
- name: Build
Expand All @@ -67,7 +73,13 @@ jobs:
run: |
cd dist
tar czf "loadgen_${GOOS}_${GOARCH}.tar.gz" "loadgen-${GOOS}-${GOARCH}"
# SLSA build provenance for the exact archive that ships. Consumers
# verify with: gh attestation verify <asset> -R goceleris/loadgen
- name: Attest build provenance
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-path: dist/loadgen_${{ matrix.goos }}_${{ matrix.goarch }}.tar.gz
- name: Attach to release
uses: softprops/action-gh-release@v3
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
with:
files: dist/loadgen_${{ matrix.goos }}_${{ matrix.goarch }}.tar.gz
66 changes: 66 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Contributing to loadgen

Thanks for helping improve loadgen, the load generator behind the celeris
benchmark suite. loadgen is deliberately dependency-light (two direct Go
dependencies) and is exercised on real hardware by
[goceleris/probatorium](https://github.com/goceleris/probatorium), so
changes are held to the same standard as the engine they measure.

## Prerequisites

- Go **1.27.0** (the version pinned in `go.mod` and in CI)
- [golangci-lint](https://golangci-lint.run/) v2.13+ (the CI pin)
- Linux or macOS. The client itself is portable; the process-CPU sampler
and recv-queue probe have Linux implementations and `_other.go`
fallbacks.

## Build and test

```bash
go build ./... # compile everything, including cmd/loadgen
go vet ./...
golangci-lint run # same config CI uses (.golangci.yml)
go test -race -count=1 -timeout 120s ./... # unit tests, exactly as CI runs them

# Integration matrix against a live celeris server. The testserver helper is
# a nested module that imports celeris; the tests spawn it as a subprocess.
go test -tags integration -race -count=1 -timeout 180s -v -run TestIntegrationH2CMatrix .
```

`gofmt` and `goimports` (with `github.com/goceleris/loadgen` as the local
prefix) are enforced by golangci-lint, so run it before pushing.

## Pull request flow

1. Fork the repository and create a topic branch from `main`
(`feat/…`, `fix/…`, `perf/…`, `chore/…`).
2. Keep each PR focused on a single change and include tests — a
correctness fix without a regression test is not complete.
3. Write commit messages in the `type: description` format
(`feat:`, `fix:`, `perf:`, `security:`, `test:`, `ci:`, `docs:`, `chore:`)
and explain *why* in the body when it is not obvious from the diff.
4. Fill in the pull request template (Summary, Changes, Test Plan,
`Closes #…`). Changes to the JSON result schema or the CLI flags must
also update the README's cluster-bench contract section, because
probatorium parses that output.
5. Make sure the CI workflow (lint, actionlint, unit tests, integration
matrix) is green.

## Merge rule

loadgen follows the same governance as celeris — see
[celeris/GOVERNANCE.md](https://github.com/goceleris/celeris/blob/main/GOVERNANCE.md).
In short: `main` is protected, every change lands through a pull request
that passes CI and is approved by a code owner (see `.github/CODEOWNERS`),
and pull requests are merged by a maintainer — never force-pushed. Releases
are tagged from `main` and the release workflow builds, attests and
publishes the binaries.

## Reporting security issues

Do not open a public issue. Follow [SECURITY.md](SECURITY.md).

## License

By contributing you agree that your contributions are licensed under the
[Apache License 2.0](LICENSE) that covers the project.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,16 @@ chmod +x /tmp/loadgen-${OS}-${ARCH}

GitHub displays the SHA-256 of each release asset on the release page — `gh release download <tag>` and the web UI verify checksums automatically, so no separate `.sha256` sidecar ships.

### Verify a release

Every release tarball is built by the [release workflow](.github/workflows/release.yml) and carries a signed [SLSA build provenance](https://slsa.dev/provenance/) attestation, generated with `actions/attest-build-provenance` and recorded in GitHub's attestation store. Before running a downloaded binary on a bench host, check that the asset really came from this repository's release pipeline:

```bash
gh attestation verify loadgen_linux_amd64.tar.gz -R goceleris/loadgen
```

The command fails if the archive was tampered with after the build or was not produced by a `goceleris/loadgen` workflow. Add `--format json` to inspect the attested source commit, workflow path and builder. Releases published before the attestation step was added (v1.4.13 and earlier) have no attestation and will fail verification.

### Reference orchestrator

The probatorium cluster bench drives this contract: it cross-compiles loadgen (or fetches a release tarball), pushes it to the load host, executes it, and parses the stdout JSON — decoding `histogram` for cross-cell re-aggregation. See [goceleris/probatorium](https://github.com/goceleris/probatorium).
Expand Down
60 changes: 60 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Security Policy

loadgen is a load-generation *client*: it opens outbound connections to a
target you name on the command line and never listens on a socket in
production use. Its security surface is therefore small — a malicious
server could still try to exploit the HTTP/1.1, HTTP/2, WebSocket and SSE
response parsers, and the JSON result written to stdout is consumed by
orchestrators — so we treat parser and output-handling bugs as security
issues.

## Reporting a Vulnerability

**Please do not open a public issue for security problems.**

Report privately, in order of preference:

1. **GitHub private vulnerability reporting (preferred)** — open the
repository's **Security** tab and click **"Report a vulnerability"**.
Private vulnerability reporting is enabled on this repository; the report
is visible only to the maintainers and becomes the draft advisory that
ships with the fix.
2. **Email** — [security@goceleris.dev](mailto:security@goceleris.dev).

Include a description of the issue, the loadgen version (the release tag, or
the `loadgen_version` field of a result), reproduction steps or a
proof-of-concept, and the impact you believe it has.

You will receive an **acknowledgement within 72 hours**. We will keep you
informed as we triage, fix and disclose, and we credit reporters in the
release notes unless they prefer otherwise.

## Supported Versions

Only the latest release of loadgen receives security fixes. Pre-built
binaries and the Go module are cut from the same tag, so upgrade to the most
recent `v1.x` tag to remain covered.

## Scope

In scope:

- The HTTP/1.1, HTTP/2 (prior-knowledge and h2c upgrade), WebSocket and SSE
client implementations and their response parsers
- TLS configuration handling (`-insecure`, custom `tls.Config`)
- The federation peer protocol
- The JSON result output consumed by orchestrators
- The release pipeline (workflows, published binaries and their provenance)

Out of scope:

- Vulnerabilities in the server under test
- Denial of service of a target caused by *intended* use of a load generator

## The celeris engine

Vulnerabilities in the HTTP server framework that loadgen is built to test
belong to the [goceleris/celeris](https://github.com/goceleris/celeris)
repository — see
[celeris/SECURITY.md](https://github.com/goceleris/celeris/blob/main/SECURITY.md)
for its supported-versions table and reporting channels.