---
title: Contributing
description: How to contribute to the opnsense2otel project, including build, test, and lint instructions
tags:
  - OPNsense
---

# Contributing

This guide covers the development workflow, tooling, and conventions for contributing to opnsense2otel.

This page is the canonical contribution guide. The repository root `CONTRIBUTING.md` is a short
pointer to this page — edit only this file; do not duplicate content into the root file.

## Prerequisites

- **Go** - Check `go.mod` for the required version (currently Go 1.27)
- **Make** - For build automation
- **golangci-lint** - Optional; runs in CI but can be used locally
- **Docker** - Optional; for container builds

## Getting started

Clone the repository:

```bash
git clone https://github.com/rknightion/opnsense2otel.git
cd opnsense2otel
```

## Build commands

| Command | Description |
|---------|-------------|
| `make` | Build the binary (static, version-embedded) |
| `make test` | Run all tests: `go test ./...` |
| `make lint` | Run `gofmt` and `golangci-lint --fix` |
| `make sync-vendor` | `go mod tidy && go mod vendor` |
| `make clean` | Format source and remove the binary |

### Building on macOS

The Makefile uses `-extldflags "-static"` which does not work on macOS. Use this instead:

```bash
CGO_ENABLED=0 go build -o opnsense2otel .
```

### Running a single test

```bash
go test ./internal/collector/ -run TestCollector
go test ./opnsense/ -run TestFetchGateways
```

## Project conventions

### Vendor directory

The vendor directory is committed to the repository. Always run `make sync-vendor` after modifying `go.mod`:

```bash
make sync-vendor
```

### Static binary

The build produces a fully static binary with:

- `CGO_ENABLED=0`
- `-ldflags "-s -w"` for stripped, optimized output
- `-trimpath` and `-mod=vendor` for reproducibility

### Version

The version is embedded at build time via `-ldflags -X main.version=...`. The `version.txt` file at the repository root is managed by release-please and tracks the current released version; GoReleaser embeds the git tag as the version in release builds, while local `make` builds embed `local-test`.

### Linters

The project uses `golangci-lint` with:

- `misspell` and `revive` enabled
- `unused` disabled

Linting runs in CI. Locally, `make lint` will run `gofmt` formatting (the `golangci-lint` step may fail if the tool is not installed, which is expected).

### Commit messages

This project uses [conventional commits](https://www.conventionalcommits.org/) for automated changelog generation via [release-please](https://github.com/googleapis/release-please):

```
feat(collector): add new subsystem collector
fix(kea): handle disabled DHCP service response
docs: update README with new collector descriptions
refactor: modernize Go syntax patterns
```

### Changelog

Release history lives entirely in `CHANGELOG.md`, generated by [release-please](https://github.com/googleapis/release-please)
from conventional commit messages. There is no separate "changes from upstream" section to maintain —
do not add one to `README.md`; it was deliberately removed and conventional commit messages are what
drive the changelog instead.

## Pull request checklist

Before submitting a PR, the local equivalent of everything `ci-success` requires:

- [ ] Code compiles: `make` or `CGO_ENABLED=0 go build`
- [ ] Tests pass: `go test ./...` (`make test`)
- [ ] Tests pass under the race detector: `go test -race ./...`
- [ ] Linters pass: `golangci-lint run ./...` (`make lint` runs `gofmt` plus `golangci-lint --fix`)
- [ ] Generated docs are current: `make docs-check` (run `make docs` first if it fails, then commit the
  regenerated files — never hand-edit content between `<!-- docgen:begin/end -->` markers)
- [ ] Grafana dashboard/alerts are current: `make grafana-check` (run `make dashboard` and, if alert
  rules changed, `make rules`, then commit the regenerated files — see `grafana/README.md`)
- [ ] Vendor is synced (if dependencies changed): `make sync-vendor`
- [ ] Conventional commit messages used
- [ ] New collectors follow the [adding a collector](../adding-collector.md) guide

CI additionally verifies the container image builds and embeds the correct version
(`docker-build-verify`); this can optionally be reproduced locally with `docker build .` but is not
required before opening a PR.

## Project structure

```text
.
+-- main.go                      # Entry point
+-- internal/
|   +-- collector/               # Prometheus collectors
|   |   +-- collector.go         # Top-level collector, interface
|   |   +-- arp_table.go         # Per-subsystem collector files
|   |   +-- gateways.go
|   |   +-- ...
|   +-- options/                 # CLI flags and configuration
|   |   +-- ops.go               # OPNsense connection config
|   |   +-- exporter.go          # Server config
|   |   +-- collectors.go        # Collector enable/disable switches
|   +-- logship/                 # Syslog + Zenarmor receivers, log enrichment, OTLP log sink
|   |   +-- syslog/              # Per-program syslog parsers
|   |   +-- zenarmor/            # Zenarmor HTTP receiver
|   |   +-- enrich/              # Device/service enrichment
|   |   +-- flowlog/             # Sink for internal/flow's correlated flow logs
|   |   +-- ...
|   +-- flow/                    # NetFlow receiver, rollup, correlator
|   |   +-- netflow/             # NetFlow wire decode + listener
|   |   +-- correlate.go         # NetFlow + Zenarmor conn merge
|   |   +-- ...
|   +-- webui/                   # Operator console served at /
|   |   +-- server.go            # Route registration, self-registering tabs
|   |   +-- status.go
|   |   +-- ...
|   +-- metricsnap/              # Passive metric capture, teed at both scrape sites
|       +-- recorder.go
+-- opnsense/                    # API client
|   +-- client.go                # HTTP client, TLS, retries
|   +-- gateways.go              # Per-subsystem Fetch methods
|   +-- ...
+-- deploy/                      # Deployment manifests
|   +-- k8s/                     # Kubernetes manifests
+-- grafana/                     # Grafana dashboard builder, panels, alert rules
+-- docs/                        # Documentation (this site)
+-- vendor/                      # Vendored dependencies
```
