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
22 changes: 22 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,25 @@ jobs:

- name: Test
run: make test

lint:
runs-on: ubuntu-latest
permissions:
contents: read
# only-new-issues reads the pull request diff
pull-requests: read
steps:
- uses: actions/checkout@v6

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: 1.25

- name: golangci-lint
uses: golangci/golangci-lint-action@v8
with:
version: v2.14
# The code predates most of the linters "default: all" now enables;
# fail on issues introduced by a change instead of the whole backlog.
only-new-issues: true
103 changes: 66 additions & 37 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,43 +1,72 @@
linters-settings:
gci:
sections:
- standard
- default
- prefix(github.com/rtbrick)
godot:
# list of regexps for excluding particular comment lines from check
exclude:
- '@.*'

issues:
exclude-rules:
- linters:
- funlen
- dupl
- bodyclose
- gocritic
- unparam
- lll
path: _test.go

version: "2"
linters:
enable-all: true
default: all
# "all" keeps growing with every golangci-lint release; the linters below
# are pure style preferences this codebase deliberately does not follow
# (or are deprecated, or need per-project config that adds nothing here,
# like depguard).
disable:
- scopelint
- golint
- interfacer
- maligned
- prealloc
- depguard
- err113
- errchkjson
- errorlint
- exhaustruct
- exhaustruct_v5
- funcorder
- gochecknoglobals
- wrapcheck
- testpackage
- godoclint
- gomodguard
- lll
- nestif
- nlreturn
- exhaustivestruct
- wsl
- noinlineerr
- paralleltest
- varnamelen
- goerr113
- prealloc
- tagliatelle
- errorlint
- errchkjson
- nestif
- testpackage
- varnamelen
- wrapcheck
- wsl
- wsl_v5
settings:
godot:
exclude:
- '@.*'
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- bodyclose
- dupl
- funlen
- gocritic
- lll
- unparam
path: _test.go
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gci
- gofmt
- gofumpt
- goimports
settings:
gci:
sections:
- standard
- default
- prefix(github.com/rtbrick)
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
15 changes: 15 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,29 @@ nfpms:
- deb
bindir: /usr/local/bin
section: utils
# bngblaster ships as a GitHub release .deb rather than from an apt
# repository, so a hard dependency would make a plain dpkg -i fail.
recommends:
- bngblaster
contents:
- src: debian/scripts/systemd/rtbrick-bngblasterctrl.service
dst: /lib/systemd/system/rtbrick-bngblasterctrl.service
file_info:
mode: 0644
- src: debian/scripts/default/rtbrick-bngblasterctrl
dst: /etc/default/rtbrick-bngblasterctrl
type: config|noreplace
file_info:
mode: 0644
- src: debian/scripts/logrotate/rtbrick-bngblasterctrl
dst: /etc/logrotate.d/rtbrick-bngblasterctrl
type: config|noreplace
file_info:
mode: 0644
scripts:
postinstall: debian/scripts/postinstall.sh
preremove: debian/scripts/preremove.sh
postremove: debian/scripts/postremove.sh
checksum:
name_template: 'checksums.txt'
snapshot:
Expand Down
83 changes: 83 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# CLAUDE.md

REST controller daemon (`bngblasterctrl`) for the [BNG Blaster](https://github.com/rtbrick/bngblaster).
It creates, starts, stops and inspects multiple `bngblaster` test instances on one host and
wraps each instance's JSON-RPC control socket as a REST API.
It also ships an embedded web UI (served on `/`, on by default, disable with `-ui=false`) that runs
on top of that REST API to manage instances from a browser.

## Commands

```sh
make build # -> bin/<os>_<arch>/bngblasterctrl (version from latest git tag)
make test # go test -v -cover ./... (what CI runs, with make build)
go test ./pkg/server -run TestServer_create # single test
make lint # golangci-lint v2 (default: all, see .golangci.yml); CI only fails on new issues
make fumpt # gofumpt formatting
make gci # import order: standard, default, github.com/rtbrick
go generate ./pkg/controller # regenerate repositorymock.go (needs matryer/moq)
```

Run locally without root by pointing at a writable folder:

```sh
./bin/linux_amd64/bngblasterctrl -d /tmp/bngblaster -debug
```

## Layout

- `cmd/bngblasterctrl/` – flag parsing, zerolog setup (warn+ goes to stderr, rest to stdout), HTTP server.
- `pkg/controller/` – instance lifecycle on disk and process management.
- `Repository` interface (`model.go`) is the seam between HTTP and the file system/processes;
`DefaultRepository` (`repository.go`) is the real implementation.
- Each instance is a folder `<config-dir>/<name>/` holding `config.json`, `run.json`, `run.pid`,
`run.sock`, `run.log`, `run_report.json`, `run.pcap`, `run.stdout`, `run.stderr`
(filename constants in `repository.go`). "Running" is derived from these files, not from in-memory state.
- `prom.go` – Prometheus metrics collected from running instances via the control socket.
- `pkg/server/` – gorilla/mux router (`server.go` `routes()`), one file per feature
(streams, sessions, overview, logs, files, ui, apidocs). `cache.go` is a short-TTL,
per-instance summary cache with in-flight dedup; invalidate it on any lifecycle change.
`hardening.go` holds the auth-independent protections (cross-origin check for
state-changing requests, `-allowed-hosts`, security headers/CSP, body size limits); bound every
new request body with `http.MaxBytesReader` and log lifecycle changes via `auditLog`.
- `pkg/server/webui/` – experimental embedded SPA. Vanilla HTML/CSS/JS, **no build step,
no framework, no npm** – files are `go:embed`ed and served as-is. `index.html` is a Go
template (`{{.AssetVersion}}` cache-busting).
- `docs/` – `swagger.yaml` + Swagger UI, embedded into the binary and also published via GitHub Pages.
- `debian/` – systemd unit, `/etc/default` env file, logrotate, install scripts (packaged by goreleaser).

## Conventions

- Every Go file starts with:
```go
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (C) 2020-2026, RtBrick, Inc.
```
- Constructors use functional options (`NewServer(repo, WithUI(...))`, `NewDefaultRepository(WithConfigFolder(...))`).
Optional surface sits behind a flag + option. `-ui`, `-upload` and `-interfaces-api` default to on in the
binary (disable with `-flag=false`); the server/repository options themselves still default to off.
- Handlers are methods returning `http.HandlerFunc`. Always sanitize the instance path variable with
`cleanPathVariable`, and file names with `filepath.Base` + `isUnsafeFileName`. There is no auth yet
(`authMiddleware` is a no-op hook), so path-traversal safety matters.
- Use `JSONError` / `JSONNotFound` for error responses; map `controller.ErrBlaster*` errors to HTTP status
(running → 412, not exists → 404).
- Logging via `github.com/rs/zerolog/log` with structured fields.
- Comments explain *why*; the codebase uses fairly thorough doc comments – match that density.

## Testing

- Server tests use `controller.RepositoryMock` (moq) plus `httpexpect`/`httptest`; table-driven with `testify/require`.
- Process tests fake `bngblaster` via `controller.ExecCommand` and the `TestHelperProcess` /
`GO_WANT_HELPER_PROCESS` pattern (`process_test.go`).
- Fixtures live in `pkg/controller/td/`.
- After changing the `Repository` interface, regenerate the mock or the build breaks.

## When changing the API

Update in the same change: the route in `server.go`, `docs/swagger.yaml`, the web UI (`app.js`) if it
consumes the endpoint, and the README if flags or defaults change.

## Release

Tag-driven via goreleaser (`.goreleaser.yaml`, `.github/workflows/release.yml`): linux/amd64 static
binary (`CGO_ENABLED=0`) + `.deb`. `main.Version` is injected through ldflags.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BSD 3-Clause License

Copyright (C) 2020-2025, RtBrick, Inc.
Copyright (C) 2020-2026, RtBrick, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
Loading
Loading