Commit Graph
8 Commits
Author SHA1 Message Date
clawbot c20ad88dfe fix: KILL actually disconnects the victim; unify HTTP/IRC divergences
check / check (push) Successful in 1m12s
Addresses the 2026-08-10 FAIL review (findings 1-7, 9, 10).

KILL never terminated the victim's connection on either transport: both
paths called BroadcastQuit, which deletes the session row and tells the
victim's peers it quit, but leaves the victim holding a socket that looks
alive and silently delivers nothing while its nick is freed for reuse.
Service now owns a session-ID keyed registry of live wire connections that
ircserver populates at registration, and both KILL paths go through the new
Service.KillSession, which broadcasts the QUIT and then sends the victim a
KILL and ERROR :Closing Link before closing its socket. The victim's relay
goroutine is cancelled and its cleanup no longer re-broadcasts a QUIT for
an already-deleted session. TestIntegrationKill now asserts the victim
reads to EOF and is gone from NAMES and WHO, not just that an observer saw
the QUIT relay.

HTTP MODE <othernick> with no body answered with the requester's own modes,
because the target check sat inside the mode-change branch. The check is
hoisted above the query/change split, and both transports now compare nicks
with EqualFold since IRC nicks are case-insensitive.

Service.QueryUserMode returned "+" for a database failure, making an
unreadable mode indistinguishable from an unset one; it now returns an
error, and both callers surface it. db.GetUserhostInfo likewise treated
every scan error as "nick not found"; only sql.ErrNoRows is skipped now.

The four new unsynchronized c.nick reads this branch introduced are read
through currentNick() under c.mu, and c.closed is now guarded everywhere
because KILL writes it from another client's goroutine. Conn.send takes a
write mutex, as a connection is now written to by three goroutines.

server.Server.Run was left with no in-tree callers when its body was
inlined into the fx OnStart hook; it is deleted rather than left to drift.

INFO and VERSION had two implementations that had already diverged: the
version string is now Service.ServerVersion and the INFO body is
Service.InfoLines, used verbatim by both transports. The ctx parameters on
handleVersion/handleAdmin/handleInfo/handleTime existed only to be
discarded and are gone.
2026-09-03 15:19:50 +00:00
clawbot f24e33a310 fix: resolve 43 lint findings blocking CI
check / check (push) Successful in 56s
- server.go: drop unused (*Server).serve int return (unparam) and
  remove the dead exitCode field so cleanShutdown no longer writes
  to a field nothing reads.
- service.go: rename range var ch -> modeChar in parseUserModeString
  and the isKnownUserModeChar parameter (varnamelen).
- service_test.go: rename tc -> testCase (varnamelen); lift the
  inline struct and caseState to package-level named types
  (applyUserModeCase, applyUserModeCaseState) with every field
  set explicitly (exhaustruct); split the 167-line case table into
  four categorised helpers (funlen); extract the per-case runner
  and outcome/state verifiers into helpers so TestApplyUserMode
  drops below gocognit 30 and flattens the wantErr nestif block.

No changes to .golangci.yml, Makefile, Dockerfile, or CI config.
No //nolint was used to silence any of these findings.

docker build --no-cache . passes clean: 0 lint issues, all tests
pass with -race, binary compiles.
2026-04-17 14:37:14 +00:00
clawbot 93611dad67 fix: rigorous atomic user mode parser and fix router race in server
check / check (push) Failing after 23s
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.
2026-04-17 10:46:24 +00:00
clawbot f5cc098b7b docs: update README for new endpoints, fix config name, remove dead field
check / check (push) Successful in 1m24s
- Document POST /api/v1/logout endpoint
- Document GET /api/v1/users/me endpoint
- Add 'users' field to GET /api/v1/server response docs
- Fix config: SESSION_TIMEOUT -> SESSION_IDLE_TIMEOUT
- Update storage section: session expiry is implemented
- Update roadmap: move session expiry to implemented
- Remove dead SessionTimeout config field from Go code
2026-03-01 06:41:10 -08:00
clawbot a57a73e94e fix: address all PR #10 review findings
check / check (push) Successful in 2m19s
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.
2026-02-26 21:21:49 -08:00
clawbot 69e1042e6e fix: rebase onto main, fix SQLite concurrency, lint clean
check / check (push) Successful in 2m11s
- Add busy_timeout PRAGMA and MaxOpenConns(1) for SQLite stability
- Use per-test temp DB in handler tests to prevent state leaks
- Pre-allocate migrations slice (prealloc lint)
- Remove invalid linter names (wsl_v5, noinlineerr) from .golangci.yml
- Remove unused //nolint:gosec directives
- Replace context.Background() with t.Context() in tests
- Use goimports formatting for all files
- All make check passes with zero failures
2026-02-26 20:25:46 -08:00
clawbot 6043e9b879 fix: suppress gosec false positives for trusted URL construction
Add nolint:gosec annotations for:
- Client.Do calls using URLs built from trusted BaseURL + hardcoded paths
- Test helper HTTP calls using test server URLs
- Safe integer-to-rune conversion in bounded loop (0-19)
2026-02-26 20:17:20 -08:00
clawbot d2bc467581 fix: resolve lint issues — rename api package, fix nolint directives
check / check (push) Failing after 1m3s
2026-02-26 07:45:37 -08:00