Mode parser (internal/service/service.go):
- Reject strings without leading + or - (e.g. "xw", "w", "") with
ERR_UMODEUNKNOWNFLAG instead of silently treating them as "-".
- Support multi-sign transitions: +w-o, -w+o, +o-w+w, -x+y, +y-x. The
active sign flips each time + or - is seen; subsequent letters apply
with the active sign.
- Atomic from caller's perspective: parse the whole string to a list of
ops first, reject the whole request on any unknown mode char, and only
then apply ops to the DB. Partial application of +w before rejecting
+o is gone.
- HTTP and IRC still share the same ApplyUserMode entry point.
Router race (internal/server/server.go):
- The fx OnStart hook previously spawned serve() in a goroutine that
called SetupRoutes asynchronously, while ServeHTTP delegated to
srv.router. Test harnesses (httptest wrapping srv as Handler) raced
against SetupRoutes writing srv.router vs ServeHTTP reading it,
producing the race detector failures in CI on main.
- SetupRoutes is now called synchronously inside OnStart before the
serve goroutine starts, so srv.router is fully initialized before any
request can reach ServeHTTP.
Tests (internal/service/service_test.go):
- Replaced the per-mode tests with a single table-driven TestApplyUserMode
that asserts both the returned mode string and the persisted DB state
(oper/wallops) for each case, including the malformed and multi-sign
cases above. The +wz case seeds wallops=true to prove the whole string
is rejected and +w is not partially applied.
Changes the Go module path from `git.eeqj.de/sneak/neoirc` to `sneak.berlin/go/neoirc`.
All occurrences updated:
- `go.mod` module directive
- All Go import paths across 35 `.go` files (107 import statements)
- All JSON schema `$id` URIs across 30 `.json` files in `schema/`
No functional changes — this is a pure rename of the module path.
`docker build .` passes clean (formatting, linting, all tests, binary build).
closes#98
Co-authored-by: clawbot <clawbot@users.noreply.git.eeqj.de>
Reviewed-on: #99
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
Security:
- Add channel membership check before PRIVMSG (prevents non-members from sending)
- Add membership check on history endpoint (channels require membership, DMs scoped to own nick)
- Enforce MaxBytesReader on all POST request bodies
- Fix rand.Read error being silently ignored in token generation
Data integrity:
- Fix TOCTOU race in GetOrCreateChannel using INSERT OR IGNORE + SELECT
Build:
- Add CGO_ENABLED=0 to golangci-lint install in Dockerfile (fixes alpine build)
Linting:
- Strict .golangci.yml: only wsl disabled (deprecated in v2)
- Re-enable exhaustruct, depguard, godot, wrapcheck, varnamelen
- Fix linters-settings -> linters.settings for v2 config format
- Fix ALL lint findings in actual code (no linter config weakening)
- Wrap all external package errors (wrapcheck)
- Fill struct fields or add targeted nolint:exhaustruct where appropriate
- Rename short variables (ts->timestamp, n->bufIndex, etc.)
- Add depguard deny policy for io/ioutil and math/rand
- Exclude G704 (SSRF) in gosec config (CLI client takes user-configured URLs)
Tests:
- Add security tests (TestNonMemberCannotSend, TestHistoryNonMember)
- Split TestInsertAndPollMessages for reduced complexity
- Fix parallel test safety (viper global state prevents parallelism)
- Use t.Context() instead of context.Background() in tests
Docker build verified passing locally.
- Fix stuttering type names (e.g. config.ConfigParams → config.Params)
- Add doc comments to all exported types/functions/methods
- Add package doc comments to all packages
- Fix JSON tags to camelCase
- Extract magic numbers to constants
- Add blank lines per nlreturn/wsl_v5 rules
- Use errors.Is() for error comparison
- Unexport NewLoggingResponseWriter (not used externally)
- Replace for-range on ctx.Done() with channel receive
- Rename unused parameters to _
- AGENTS.md: all changes via feature branches, no direct main commits