Contributing¶
port49 is a TACACS+ server in Go (Apache-2.0). This page is what a contributor needs before the first change: how to build and test, the one-time hook setup, and the rule that decides what the docs may say about a device.
Build and test¶
You need Go 1.26 or later. The module is github.com/blanketfish/port49, and the build is static, with no cgo.
make build
make test && make vet
make testruns the lab harness's unit tests (no device), the Python client and Ansible collection tests (Python 3.10 or later), and the whole Go suite (go test ./... -count=1). A full run takes about 20 minutes.make vetfails on any filegofmtwould change, then runsgo vet. A change is not ready until both commands pass, and you should report their real output in the pull request.- Anything that needs a device image, a container runtime or the lab is a separate
make lab-*target and is never part ofmake test. A pull request does not need the lab. Leave those targets to a maintainer with the lab; see Qualification.
Once per clone: the hooks¶
make hooks
make hooks points this clone's core.hooksPath at .githooks. That enables two checks on every commit:
a secret scan of the staged changes (gitleaks), and a check that the commit message carries no session
link or trailer. The setting lives in the clone's git configuration, which its worktrees share, so run it
once per clone. Never bypass a finding with --no-verify; fix it.
Conventions¶
- Branches and commits. Branch from
mainasfeature/<slug>orfix/<slug>and open a pull request. Commit with Conventional Commits (feat:,fix:,docs:,chore:,refactor:,test:). Keep commits small and atomic. - snake_case wherever it is data. YAML keys, JSON log keys, configuration keys and metric names.
- Reason codes are a closed list. A decision's
reasoncomes from the table in spec §5.7 andinternal/decision/reasons.go. To add one, add it to the spec table first. - The log never holds a secret. No token, password, challenge or response, ever. A credential appears
only as
credential_sha256, and a body that has not been validated is never logged. - No device identity in a metric label.
The lab register¶
Every claim about how a device behaves has an entry, L<N>, in the lab register: the table in
spec §15.
The register, not memory or a vendor manual, is the source of truth for device behavior. Four rules:
- A claim cited to an open entry is unmeasured. Do not "fix" a doc to assert it.
- A decision marked provisional on
L<N>stays provisional until that row closes. -
Closing an entry means all of these:
- the lab test passed;
tests/lab/results/L<N>-<platform>.mdexists, with the platform, the image version, the observation and a capture pointer;- the row's Status in spec §15 is edited to
closed — measured <date>; tests/lab/results/L<N>-<platform>.md; - the change is committed as
docs: close lab register entries ....
A row with one platform measured and others open stays open. 4. If a lab result contradicts a doc, the doc is wrong. Fix the doc, cite the results note, and say so in the commit message. A results note wins over a doc.
On this site, a device claim links its results note, or it sits in an "Unmeasured" box worded as unknown.
Where the design lives¶
- The architecture and the policy engine spec (§13 records decisions, §15 is the register).
docs/superpowers/plans/: one implementation plan per build step, and itsREADME.mdis the roadmap.tests/lab/: the lab harness, andtests/lab/results/for the notes the register cites.
More¶
- Qualification: vetting a firmware, adding a platform, and the lab regression run.
- Releasing: how a release is cut and published.