fix(daemon): log CLI-triggered ban/unban/allow at INFO (#45)#46
Open
evertramos wants to merge 1 commit into
Open
fix(daemon): log CLI-triggered ban/unban/allow at INFO (#45)#46evertramos wants to merge 1 commit into
evertramos wants to merge 1 commit into
Conversation
Manual actions via the control socket wrote to bans_active + audit_log but produced no slog line. Operators tailing journalctl -u ezyshield saw no confirmation of CLI verbs and could not distinguish a manual ban from an automatic (pipeline-triggered) one. Adds three additive slog.InfoContext calls at the tail of handleBan / handleUnban / handleAllow, each reusing the pipeline path's message "daemon: action" so a single grep still catches every state change. source="cli" discriminates the CLI path from the automatic rules/AI path. - handleBan: op is "ban" or "dry_ban" (when policy.Armed=false), ttl is the parsed duration (0 for permanent), reason is the operator-supplied string or "manual ban via CLI" if empty. The line is emitted only after the primary store write succeeds — the audit-fallback ERROR branch stays as-is (§10: no false confirmation of a lost write). - handleUnban: op="unban", ttl=0, reason empty (CLI doesn't send one). - handleAllow: op="allow", ttl matches the value passed to AuditOp so the log and the audit_log agree. No schema change, no socket wire-format change, no change to the automatic path's message string. Additive only. Tests: internal/daemon/socket_test.go captures slog via a text-handler attached to slog.Default() (matches the existing package pattern) and asserts one INFO line per verb with the expected op/ip/ttl/source attributes, plus the dry_ban and permanent-allow variants. Security review notes: §10 improvement — closes a gap where CLI state changes were invisible to journal-based monitoring. No new attacker surface: reason is already stored in audit_log with the same shape. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
This PR successfully addresses issue #45 by adding INFO-level logging for CLI-triggered ban/unban/allow operations. The implementation is well-designed with proper error handling, comprehensive test coverage, and consistent attribute naming that matches the existing pipeline logging pattern.
Key strengths:
- Correctly guards INFO logging behind the
storedflag inhandleBanto prevent false success indicators when writes fail - Consistent message format across all three handlers enables unified grep patterns for operational monitoring
- Comprehensive test suite covers all scenarios including dry-run mode and permanent vs. temporary operations
- Additive-only changes with no modifications to existing behavior or security boundaries
The changes are ready to merge.
You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Closes #45
Manual
ezyshield ban/unban/allowvia the control socket wrote tobans_active+audit_logbut produced no slog line. Operators tailingjournalctl -u ezyshieldcouldn't confirm CLI actions or tell a manual ban apart from a pipeline-triggered one. The pipeline path already logsmsg="daemon: action"at INFO (internal/daemon/daemon.go:571); this PR gives the socket handlers the equivalent line so a single grep pattern catches every state change.Acceptance (per issue):
op={ban|unban|allow|dry_ban},ip,ttl,reason,source=cliafter each successful CLI verb."daemon: action") — onlysource=clidiscriminates.Changes
internal/daemon/socket.go: threeslog.InfoContext(ctx, "daemon: action", ...)calls at the tail ofhandleBan,handleUnban,handleAllow.handleBanguards the log behind astoredflag so the fallback ERROR branch (RecordManualBan failure) does not falsely emit a success line.handleBanreuses its localopvariable soop="dry_ban"whenpolicy.Armed=false.handleAllowreuses the samettlhanded tostore.AuditOpso the log and audit row agree (0for permanent, computed duration otherwise).handleUnbanemitsttl=0,reason=req.Reason(empty from today's CLI — issue says leave as-is; do not invent a placeholder).internal/daemon/socket_test.go: new file. Captures slog via a text handler attached toslog.Default()(matches the package pattern —slog.Default()is already how the socket handlers dispatch, and no other daemon test needed a scoped logger). Asserts one INFO line per verb with the expected attributes, including thedry_banand permanent-allow variants.Tests
internal/daemon/socket_test.go)fixtures/— N/Ago test -race ./...green locally on Go 1.26 (see note below on lint)Note on local lint: this environment ships a golangci-lint built against Go 1.24, which refuses the repo's
go 1.26module directive.go vet ./...andgofmt -lare clean; CI's own toolchain will run the full lint.Security review (per docs/SECURITY-REVIEW.md)
reasonattribute is operator-supplied text from the socket request; it already flowed intoaudit_logunchanged prior to this PR, so no new exposure surface. It is logged at INFO because the automatic path already treats reason as INFO-safe (daemon.go:571).req.Reasonandopare not secret material. No token, URL, or credential reaches these attributes; the socket request struct has no secret fields.secret_leak_test.goininternal/configandinternal/aicover the paths that do handle secrets and are untouched.0660group ownership; only the log output on an existing verb changed.log/slog,net,bytes,encoding/json,strings,testingare already used across the daemon package.handleBanguards the INFO emission onstoredso a failedRecordManualBan+ failedAuditOpdoes not produce a misleading "action" line while the audit-fallback ERROR log already exists.handleUnban/handleAllowreturn early on primary store-write failure via the existing error paths, so the tail INFO is only reached in the happy path. Reason and IP are the same values already persisted toaudit_log; no new secret-exposure surface.Self-assessment: Does this change give an attacker a step toward lock-out / injection / privilege-escalation / secret-exfil / evasion? No. The change is additive, only touches the log sink on three already-audited paths, adds no new import, no new interface, and no new attacker-controlled surface. An attacker with socket access already had full ban/unban/allow power before this PR; the only difference is that their actions are now visible to the operator on stdout/journal.
Checklist
🤖 Generated with Claude Code