Closed mrheinen closed 1 day ago
Here are some key observations to aid the review process:
β±οΈ Estimated effort to review: 4 π΅π΅π΅π΅βͺ |
π§ͺ PR contains tests |
π No security concerns identified |
β‘ Recommended focus areas for review Potential Race Condition The `UpdateSessionWithRule` method updates the session state without apparent synchronization. This could lead to race conditions if multiple goroutines access the same session concurrently. Error Handling The `CleanupStaleSessions` method continues processing even if there's an error ending a session. This might lead to inconsistent state or missed cleanup for some sessions. Potential Memory Leak The `RuleIDsServed` map in the `Session` struct is initialized but never cleaned up. This could potentially lead to memory growth over time if sessions accumulate a large number of served rules. |
Failed to generate code suggestions for PR
Explore these optional code suggestions:
Category | Suggestion | Score |
Possible issue |
Add error handling for cache storage operation in session management___ **Consider adding error handling for thed.activeSessions.Store(ip, retSession) call in the StartSession method. If this operation fails, it could lead to inconsistencies between the database and the cache.** [pkg/backend/session/session.go [137-139]](https://github.com/mrheinen/lophiid/pull/73/files#diff-f6cfd2239c48d34a79a86f35c0074d4672fe9ef6ad474cc61104ab339c4192d5R137-R139) ```diff retSession := dm.(*database.Session) -d.activeSessions.Store(ip, retSession) +if err := d.activeSessions.Store(ip, retSession); err != nil { + return nil, fmt.Errorf("error storing session in cache: %w", err) +} return retSession, nil ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 8Why: This suggestion addresses a potential bug by adding error handling for a critical operation. It prevents silent failures and improves reliability. | 8 |
Best practice |
β Remove trailing comma in SQL table definition for better compatibility___Suggestion Impact:The trailing comma was removed from the last column definition in the 'session' table creation statement, as suggested. However, an additional column 'ended_at' was also added. code diff: ```diff - updated_at TIMESTAMP NOT NULL DEFAULT (timezone('utc', now())), + ended_at TIMESTAMP NOT NULL DEFAULT (timezone('utc', now())), + updated_at TIMESTAMP NOT NULL DEFAULT (timezone('utc', now())) ```creation statement to ensure compatibility with all SQL databases.** [config/database.sql [146-153]](https://github.com/mrheinen/lophiid/pull/73/files#diff-002629893f0a5eb6f8e9a6d036047c92784e918c0afc132f6992827aae6121bcR146-R153) ```diff CREATE TABLE session ( id SERIAL PRIMARY KEY, active BOOL DEFAULT FALSE, ip VARCHAR(52) NOT NULL, started_at TIMESTAMP NOT NULL DEFAULT (timezone('utc', now())), created_at TIMESTAMP NOT NULL DEFAULT (timezone('utc', now())), - updated_at TIMESTAMP NOT NULL DEFAULT (timezone('utc', now())), + updated_at TIMESTAMP NOT NULL DEFAULT (timezone('utc', now())) ); ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 8Why: Removing the trailing comma after the last column definition is crucial for ensuring compatibility across all SQL databases. This small change can prevent potential syntax errors and improve the portability of the database schema. | 8 |
Use context for graceful shutdown in cache management goroutine___ **Consider using a context for graceful shutdown instead of a separate channel. Thiswould allow for more consistent cancellation patterns across the application.** [pkg/util/string_map_cache.go [171-184]](https://github.com/mrheinen/lophiid/pull/73/files#diff-0ab41f6168af62cb8c68239c7c78cd0e807513c6264c91521b0f218500cbdb17R171-R184) ```diff -func (r *StringMapCache[T]) StartWithCallback(callback func(T) bool) { +func (r *StringMapCache[T]) StartWithCallback(ctx context.Context, callback func(T) bool) { ticker := time.NewTicker(time.Minute * 1) go func() { + defer ticker.Stop() for { select { - case <-r.bgChan: - ticker.Stop() + case <-ctx.Done(): return case <-ticker.C: r.CleanExpiredWithCallback(callback) } } }() } ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 7Why: This suggestion improves the shutdown mechanism and aligns with Go best practices. It's a valuable improvement for resource management and consistency. | 7 | |
Performance |
β Add an index to improve query performance on frequently accessed columns___Suggestion Impact:The commit implemented an index on the 'session' table that includes the 'ip' column, along with 'started_at' and 'active' columns code diff: ```diff +CREATE INDEX session_ip ON session ( + started_at desc, + active, + ip +); ```performance when searching or filtering by IP address.** [config/database.sql [146-153]](https://github.com/mrheinen/lophiid/pull/73/files#diff-002629893f0a5eb6f8e9a6d036047c92784e918c0afc132f6992827aae6121bcR146-R153) ```diff CREATE TABLE session ( id SERIAL PRIMARY KEY, active BOOL DEFAULT FALSE, ip VARCHAR(52) NOT NULL, started_at TIMESTAMP NOT NULL DEFAULT (timezone('utc', now())), created_at TIMESTAMP NOT NULL DEFAULT (timezone('utc', now())), updated_at TIMESTAMP NOT NULL DEFAULT (timezone('utc', now())), ); +CREATE INDEX idx_session_ip ON session(ip); + ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 7Why: Adding an index on the 'ip' column can significantly improve query performance for operations involving IP addresses, which are likely to be frequent in a session table. This is a valuable optimization for database efficiency. | 7 |
Maintainability |
Refactor test setup to use a helper function for creating BackendServer instances___ **Consider using a test helper function to create the BackendServer instance withcommon parameters. This would reduce code duplication and make the tests more maintainable.** [pkg/backend/backend_test.go [200-203]](https://github.com/mrheinen/lophiid/pull/73/files#diff-841290eccbd676c43597489825cc8f1628359283c634321e496e76e31f6fed9cR200-R203) ```diff fSessionMgr := session.NewDatabaseSessionManager(fdbc, time.Hour) fIpMgr := analysis.FakeIpEventManager{} fakeRes := &responder.FakeResponder{} -b := NewBackendServer(fdbc, bMetrics, &fakeJrunner, alertManager, &vt.FakeVTManager{}, &whoisManager, &queryRunner, &fakeLimiter, &fIpMgr, fakeRes, fSessionMgr, GetDefaultBackendConfig()) +b := createTestBackendServer(fdbc, fSessionMgr, &fIpMgr, fakeRes) +// Helper function (defined elsewhere in the test file): +// func createTestBackendServer(fdbc *database.FakeDatabaseClient, fSessionMgr session.SessionManager, fIpMgr *analysis.FakeIpEventManager, fakeRes *responder.FakeResponder) *BackendServer { +// return NewBackendServer(fdbc, bMetrics, &fakeJrunner, alertManager, &vt.FakeVTManager{}, &whoisManager, &queryRunner, &fakeLimiter, fIpMgr, fakeRes, fSessionMgr, GetDefaultBackendConfig()) +// } + ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 6Why: This suggestion improves code maintainability by reducing duplication in test setup. It's a good practice but not critical for functionality. | 6 |
Extract session cleanup logic into a separate function for improved code organization___ **Consider extracting the session cleanup logic into a separate function for betterreadability and maintainability. This would also make it easier to test the cleanup process independently.** [cmd/backend/backend_main.go [201-217]](https://github.com/mrheinen/lophiid/pull/73/files#diff-aea9d0ad7326cd6083f662c484917c42ab9ff66183cbe981873c671cedc76b7cR201-R217) ```diff -slog.Info("Cleaning up any stale sessions") -totalSessionsCleaned := 0 - -for { - cnt, err := sessionMgr.CleanupStaleSessions(50) - if err != nil { - slog.Error("Error cleaning up sessions: %s", err) - return +func cleanupStaleSessions(sessionMgr *session.DatabaseSessionManager) (int, error) { + totalSessionsCleaned := 0 + for { + cnt, err := sessionMgr.CleanupStaleSessions(50) + if err != nil { + return totalSessionsCleaned, fmt.Errorf("error cleaning up sessions: %w", err) + } + totalSessionsCleaned += cnt + if cnt < 50 { + break + } } - - totalSessionsCleaned += cnt - if cnt < 50 { - break - } + return totalSessionsCleaned, nil } +// In main(): +slog.Info("Cleaning up any stale sessions") +totalSessionsCleaned, err := cleanupStaleSessions(sessionMgr) +if err != nil { + slog.Error("Error during session cleanup: %s", err) + return +} slog.Info("Cleaned up %d stale sessions", totalSessionsCleaned) ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 5Why: This suggestion enhances code readability and maintainability. While beneficial, it's not addressing a critical issue or bug. | 5 |
π‘ Need additional feedback ? start a PR chat
/add_docs
The docstring
command only supports the following languages: python, java, cpp, javascript, typescript, jsx, tsx, csharp
Generating Documentation...
/ask "Make suggestions based on compliance with the Golang style guide at https://golang.org/doc/effective_go.html"
Make suggestions based on compliance with the Golang style guide at https://golang.org/doc/effective_go.html
Based on the Golang style guide and the provided PR diff, here are some suggestions for improvement:
Naming Conventions:
SessionManager
interface and DatabaseSessionManager
struct follow the recommended naming conventions for interfaces and types.CleanupStaleSessions
, GetCachedSession
, and UpdateCachedSession
follow the MixedCaps naming convention as recommended.Error Handling:
errors.Wrap()
function from the github.com/pkg/errors
package to add more context to errors, especially in the DatabaseSessionManager
methods.Comments:
session
package is good, but consider adding more detailed comments for exported functions and types.SessionManager
interface.Concurrency:
StringMapCache
for managing active sessions is a good approach for concurrent access.sync.RWMutex
for any operations that don't modify the session data to allow multiple concurrent reads.Error Wrapping:
GetCachedSession
and StartSession
, consider wrapping errors with more context, e.g., fmt.Errorf("failed to fetch session: %w", err)
.Consistency:
CleanupStaleSessions
, use fmt.Errorf("error fetching session: %w", err)
instead of string concatenation.Logging:
slog
for logging is good. Consider adding more log levels (e.g., Debug, Info) for better log management in production.Testing:
session_test.go
is great. Ensure comprehensive test coverage for all new methods in the DatabaseSessionManager
.Configuration:
NewDatabaseSessionManager
function.Documentation:
SessionManager
interface and DatabaseSessionManager
struct to explain their purpose and usage.Overall, the new session management code follows many good Go practices. Implementing these suggestions will further improve its compliance with the Go style guide and make the code more maintainable and robust.
Preparing answer...
**Action:** build |
**Failed stage:** [Build](https://github.com/mrheinen/lophiid/actions/runs/11596668123/job/32288264490) [β] |
**Failure summary:**
The action failed due to a Go compilation error in the file pkg/util/string_map_cache.go . Specifically: (e.g., as a map key), but the type constraint doesn't ensure that T is comparable. pkg/util:util_test target. |
Relevant error logs:```yaml 1: ##[group]Operating System 2: Ubuntu ... 569: Analyzing: 39 targets (249 packages loaded, 11087 targets configured) 570: [8 / 30] GoToolchainBinaryBuild external/go_sdk/builder [for tool]; 19s linux-sandbox 571: Analyzing: 39 targets (286 packages loaded, 11604 targets configured) 572: [38 / 198] GoToolchainBinaryBuild external/go_sdk/builder [for tool]; 20s linux-sandbox 573: INFO: Analyzed 39 targets (299 packages loaded, 11750 targets configured). 574: [76 / 347] GoStdlib external/io_bazel_rules_go/stdlib_/pkg; 0s linux-sandbox 575: [76 / 347] GoStdlib external/io_bazel_rules_go/stdlib_/pkg; 10s linux-sandbox 576: [77 / 347] [Prepa] GoCompilePkg pkg/util/constants/constants.a ... (3 actions, 0 running) 577: ERROR: /home/runner/work/lophiid/lophiid/pkg/util/BUILD.bazel:20:8: GoCompilePkg pkg/util/util_test.internal.a failed: (Exit 1): builder failed: error executing GoCompilePkg command (from target //pkg/util:util_test) bazel-out/k8-opt-exec-ST-d57f47055a04/bin/external/go_sdk/builder_reset/builder compilepkg -sdk external/go_sdk -installsuffix linux_amd64 -src pkg/util/command.go -src pkg/util/contains.go -src ... (remaining 45 arguments skipped) 578: Use --sandbox_debug to see verbose messages from the sandbox and retain the sandbox build root for debugging 579: ##[error]pkg/util/string_map_cache.go:41:83: T does not satisfy comparable 580: ##[error]pkg/util/string_map_cache.go:42:25: T does not satisfy comparable 581: compilepkg: error running subcommand external/go_sdk/pkg/tool/linux_amd64/compile: exit status 2 582: Use --verbose_failures to see the command lines of failed build steps. 583: INFO: Elapsed time: 53.960s, Critical Path: 37.83s 584: INFO: 90 processes: 62 internal, 28 linux-sandbox. 585: ERROR: Build did NOT complete successfully 586: ##[error]Process completed with exit code 1. ``` |
User description
Up to now sessions weren't a real entity in lophiid. They were inferred from database records. This change makes sessions a real thing. They are stored in the database and a memory cache. For performance reasons the session in the database are only stored on creation and updated on completion of the session (timeout).
Maybe in the future we can actually update the sessions in the database periodically and add some session information to the UI as well.
PR Type
Enhancement, Bug fix
Description
SessionManager
interface andDatabaseSessionManager
implementationsession
table for persistent storage of session dataAttackTrackingDuration
configuration and related codeStringMapCache
with callback functionality for session expirationChanges walkthrough π
7 files
backend_main.go
Integrate session manager in backend main
cmd/backend/backend_main.go
backend.go
Refactor backend to use session manager
pkg/backend/backend.go
ruleVsCache
and related methodssessionMgr
toBackendServer
structGetMatchedRule
to use session managerUpdateSessionWithRule
methodrule_cache.go
Remove rule cache implementation
pkg/backend/rule_cache.go - Entire file removed
session.go
Implement session management
pkg/backend/session/session.go
SessionManager
interfaceDatabaseSessionManager
struct and methodsdatabase.go
Add session support to database
pkg/database/database.go
Session
struct and related methodsDatabaseClient
interfacestring_map_cache.go
Enhance string map cache with callback
pkg/util/string_map_cache.go - Added `StartWithCallback` method to `StringMapCache`
database.sql
Add session table to database schema
config/database.sql - Added `session` table definition
2 files
backend_test.go
Update backend tests for session management
pkg/backend/backend_test.go
ruleVsCache
session_test.go
Add tests for session manager
pkg/backend/session/session_test.go - Added tests for session manager functionality
4 files
config.go
Remove attack tracking duration from config
pkg/backend/config.go - Removed `AttackTrackingDuration` from config
backend-config.yaml
Update backend configuration
config/backend-config.yaml - Removed `attack_tracking_duration` configuration
BUILD.bazel
Update Bazel build for backend changes
pkg/backend/BUILD.bazel
rule_cache.go
andrule_cache_test.go
session
dependencyBUILD.bazel
Add Bazel build for session package
pkg/backend/session/BUILD.bazel - Added new Bazel build file for session package