-
Notifications
You must be signed in to change notification settings - Fork 529
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: api v2 init #2832
feat: api v2 init #2832
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
1 Skipped Deployment
|
📝 WalkthroughWalkthroughThis pull request introduces a comprehensive update to the Unkey API's backend infrastructure, enhancing the codebase with new features and improved organization. Key changes include the addition of a new task for SQL generation, modifications to the OpenAPI specification, the introduction of a new ClickHouse client, and the establishment of a custom web framework called Zen. The updates also include enhanced error handling, structured logging, and a robust configuration system, along with various new routes and middleware for improved request processing. Changes
Sequence DiagramsequenceDiagram
participant Client
participant ZenServer
participant Middleware
participant Handler
participant Database
participant ClickHouse
Client->>ZenServer: HTTP Request
ZenServer->>Middleware: Apply Global Middleware
Middleware->>Middleware: Logging
Middleware->>Middleware: Metrics
Middleware->>Middleware: Error Handling
Middleware->>Handler: Execute Route Handler
Handler->>Database: Query/Mutate Data
Database-->>Handler: Return Result
Handler->>ClickHouse: Buffer Event
Handler->>ZenServer: Return Response
ZenServer->>Client: Send HTTP Response
This sequence diagram illustrates the request flow through the new Zen framework, showcasing the middleware pipeline, route handling, database interaction, and event buffering. ✨ Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Thank you for following the naming conventions for pull request titles! 🙏 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 25
🔭 Outside diff range comments (1)
apps/agent/pkg/openapi/openapi.json (1)
Line range hint
1-438
: Add rate limit headers to API responses.The OpenAPI spec should include standard rate limit headers in the responses.
Add the following headers to all 2xx responses:
"responses": { "200": { "headers": { + "X-RateLimit-Limit": { + "schema": { "type": "integer" }, + "description": "The maximum number of requests allowed" + }, + "X-RateLimit-Remaining": { + "schema": { "type": "integer" }, + "description": "The number of requests remaining" + }, + "X-RateLimit-Reset": { + "schema": { "type": "integer" }, + "description": "The time when the rate limit resets" + } + }, "content": {
🧹 Nitpick comments (85)
go/pkg/fault/tag_test.go (1)
48-81
: Well-structured test cases with an opportunity to add more coverage.
- Good handling of both
nil
errors and normal errors inTestWithTag
, validating that tags are properly added.- Consider adding a scenario to check how
WithTag
behaves if the error is already tagged (e.g., does the new tag override the existing one?). This can ensure correctness for potential re-tagging scenarios.go/pkg/ctxutil/context.go (3)
7-9
: Prefer CamelCase naming for context key constants in Go.
Go convention typically usesRequestIDKey
or something similar. Avoid mixing snake case and lowerCamelCase.Here's a possible rename:
-const ( - request_id contextKey = "request_id" -) +const ( + requestIDKey contextKey = "request_id" +)
22-24
: Use "ID" consistently instead of "Id" in function names.
In Go, acronyms are often capitalized. Recommend renaming toGetRequestID
.-func GetRequestId(ctx context.Context) string { +func GetRequestID(ctx context.Context) string { return getValue[string](ctx, request_id) }
26-28
: Maintain consistent naming in context setter.
Similarly, consider renamingSetRequestId
toSetRequestID
for clarity.-func SetRequestId(ctx context.Context, requestId string) context.Context { - return context.WithValue(ctx, request_id, requestId) +func SetRequestID(ctx context.Context, requestID string) context.Context { + return context.WithValue(ctx, request_id, requestID) }go/.golangci.yaml (4)
10-13
: Consider optimizing the linting timeout.The 3-minute timeout might be excessive for most projects and could slow down CI/CD pipelines. Consider starting with the default 1-minute timeout and only increase if necessary based on your project's specific needs.
- timeout: 3m + timeout: 1m
19-26
: Consider stricter complexity limits.The current max complexity of 30 is quite lenient and might allow overly complex functions to pass linting. Consider reducing this to improve code maintainability:
- max-complexity: 15-20 is a more common threshold
- package-average: 7.0-8.0 would encourage better code organization
- max-complexity: 30 - package-average: 10.0 + max-complexity: 15 + package-average: 7.0
72-83
: Review function length limits.The current limits are quite permissive:
- 100 lines per function
- 50 statements per function
Consider stricter limits to encourage better function decomposition and maintainability.
- lines: 100 - statements: 50 + lines: 60 + statements: 30
331-335
: Reduce the maximum same-issues limit.A limit of 50 for the same issue type is quite high and might hide systematic problems in the codebase. Consider reducing this to help identify and address recurring issues more effectively.
- max-same-issues: 50 + max-same-issues: 20go/pkg/logging/interface.go (1)
8-15
: Interface design is clean and extensible.The
Logger
interface includes all requisite log levels and a fluentWith
method, promoting structured logging. Consider adding optional doc comments to further describe each method’s intended usage or any side effects.type Logger interface { + // With returns a new Logger containing the given attributes. With(attrs ...slog.Attr) Logger + // Debug logs a message at Debug level. Debug(ctx context.Context, message string, attrs ...slog.Attr) + // Info logs a message at Info level. Info(ctx context.Context, message string, attrs ...slog.Attr) + // Warn logs a message at Warn level. Warn(ctx context.Context, message string, attrs ...slog.Attr) + // Error logs a message at Error level. Error(ctx context.Context, message string, attrs ...slog.Attr) }go/pkg/logging/slog.go (2)
12-15
: Add doc comments for config fields.Clearly document what
Development
andNoColor
do so that future maintainers and dev users can configure them properly.type Config struct { + // Development indicates whether to enable development-friendly logging output (e.g., text-based, colored). Development bool + // NoColor disables color output, even in development mode. NoColor bool }
21-41
: Suggest a fallback for environment-based configurations.If the logger configuration is commonly toggled based on environment variables, you could parse such variables here (or in a dedicated config layer) rather than requiring the caller to supply the flags. This encourages uniform usage across different environments.
go/pkg/fault/tag.go (1)
11-14
: Clarify the phrase "explicitly withTag" for better readability.
It might be clearer to say "explicitly assigned a tag" or "explicitly tagged." This helps maintain consistent terminology aligned with theWithTag
function name.- // UNTAGGED is the default tag for errors that haven't been explicitly withTag. + // UNTAGGED is the default tag for errors that haven't been explicitly tagged.go/pkg/fault/wrapped.go (2)
20-36
: Clarify purpose and usage of thetag Tag
field.
Currently, theTag
field is declared but never used. If you plan to leverage it later, consider adding at least a brief documentation inline. Otherwise, remove or comment it out until needed.type wrapped struct { err error location string + // tag can be used for further categorization or grouping of error types. tag Tag public string internal string }
38-63
: Consider renaming "message" to "internalMessage" for clarity.
To align with the struct fields (public
vs.internal
), consider renaming the argument inNew(message string, wraps ...Wrapper)
. This avoids ambiguity and preserves consistent naming.-func New(message string, wraps ...Wrapper) error { +func New(internalMessage string, wraps ...Wrapper) error { ... - internal: message, + internal: internalMessage, ... }go/pkg/config/json.go (4)
21-34
: Ensure consistent usage of 'fault' vs. 'fmt.Errorf' for error reporting.
While the function uses thefault
package in some places, in others it still falls back tofmt.Errorf
. You might want to unify your approach to keep error handling consistent across the application.
29-32
: Consider caching the JSON schema to avoid repeated generation.
Current implementation callsGenerateJsonSchema
every timeLoadFile
is invoked, which could negatively affect performance for bigger configurations or frequent loads. Caching the schema or generating it only when the configuration type changes might be more optimal.
41-52
: Improve readability of validation error formatting.
The final error message is built by concatenating multiple lines withstrings.Join
; it might be clearer to format these details in structured fields or a dedicated error object, preserving each validation issue in a structured fashion instead of building a large string.
76-81
: Validate handling of multiple output file paths.
SinceGenerateJsonSchema
takes a variadicfile
parameter but only writes tofile[0]
, ensure that no confusion arises if multiple paths are passed inadvertently. It might be safer to explicitly handle or reject additional paths.go/pkg/zen/validation/validator.go (2)
28-46
: Expand logging around validator creation errors.
When multiple validation errors are returned inerrors
, you collect them intomessages
, which is good. Including more context (like the relevant portion of the OpenAPI spec) might help troubleshooting.
47-80
: Refine the error response details.
Currently, you setType
inBadRequestError
tohttps://unkey.com/docs/api-reference/errors/TODO
; consider assigning a more finalized URL or an internal error code to ensure clarity for API clients.go/pkg/fault/wrap.go (2)
8-34
: Skip wrapping if error is already captured with location.
The code setserr = &wrapped{...}
unconditionally. You may want to check iferr
is already of type*wrapped
(i.e., has location info) to avoid duplicating location wrappers in longer error chains.
36-86
: Expose the 'public' part of the description for typed retrieval.
WhileWithDesc
stores bothinternal
andpublic
strings, the latter is not easily accessible unless you parse the entire error chain. If you plan to show a user-facing message, consider providing a helper method for extracting thepublic
portion.go/pkg/clickhouse/client.go (3)
47-54
: Increase retry interval for ClickHouse ping if needed.
The current retry logic reattempts ping requests 10 times with an incrementally increasing delay (1s, 2s, etc.). This might be too short or too long depending on production constraints. Ensure it matches your operational needs.
59-71
: Dynamically configure batch parameters.
Batch size (1000), buffer size (100000), and flush intervals (1 second) are a good start, but can be made configurable to adapt to different workloads.
100-106
: No backpressure or error handling on buffer insertion.
BufferApiRequest
andBufferKeyVerification
do not return errors if the buffer is full or if something else fails. Consider adding backpressure or returning an error to handle overflow gracefully.go/pkg/zen/server.go (2)
26-28
: Enhance clarity on middleware ordering.
The comment clarifies the execution order, but it’s somewhat inverted. Defining the order from inside-out or top-to-bottom might reduce confusion.
40-58
: Set connection timeouts dynamically.
The read/write timeouts are hard-coded to 10/20 seconds. You may want to allow dynamic configuration, especially for production environments with different SLAs.go/pkg/zen/openapi/gen.go (2)
76-88
: Validate optional input.
V2RatelimitLimitRequestBody.Cost
is optional but might be vital for certain calculations. Consider defaulting it to1
server-side ifnil
.func V1RatelimitLimit(w http.ResponseWriter, r *http.Request, params V1RatelimitLimitParams) { // ... + if body.Cost == nil { + defaultCost := int64(1) + body.Cost = &defaultCost + } // ... }
110-120
: Clarify docstring for wildcard overrides.
You mention wildcard usage inIdentifier
. A short code example or reference to actual usage might improve clarity.go/pkg/clickhouse/interface.go (1)
7-10
: Consider returning errors from buffering operations.
TheBufferApiRequest
andBufferKeyVerification
methods do not return errors or status indicators. If buffering might fail, returning an error or status code could improve reliability and error handling.-type Bufferer interface { - BufferApiRequest(schema.ApiRequestV1) - BufferKeyVerification(schema.KeyVerificationRequestV1) +type Bufferer interface { + BufferApiRequest(req schema.ApiRequestV1) error + BufferKeyVerification(req schema.KeyVerificationRequestV1) error }go/pkg/database/database.go (1)
11-19
: Ping the database to ensure connectivity.
sql.Open
does not validate the DSN or perform an actual network connection. Consider callingdb.Ping()
before returning to detect connection issues early.func New(dsn string) (Database, error) { db, err := sql.Open("mysql", dsn) if err != nil { return nil, err } + + if pingErr := db.Ping(); pingErr != nil { + return nil, pingErr + } return gen.New(db), nil }go/pkg/zen/handler.go (1)
3-9
: Provide usage examples in the doc.
Although the doc is reasonably clear, including a short code snippet or scenario illustrating how to invokeHandler
can help others integrate it faster.go/pkg/zen/routes/register.go (1)
10-13
: Add error checks or logs when registering routes.
In casesrv.RegisterRoute()
orv2RatelimitLimit.New(svc)
fail, it might be beneficial to log or handle the error rather than silently proceeding.func Register(srv *zen.Server, svc *zen.Services) { - srv.RegisterRoute(v2RatelimitLimit.New(svc)) + route := v2RatelimitLimit.New(svc) + if route == nil { + // log error or handle feedback + return + } + srv.RegisterRoute(route) }go/pkg/clickhouse/noop.go (2)
3-5
: Consider adding a package-level doc comment.
While this is a simple file, a short doc comment can help explain the file’s purpose in the larger system.
11-16
: Add clarifying comments for no-op methods.
It’s helpful to briefly explain why these methods are intentionally empty so that future contributors understand the purpose of the no-op design (e.g., test stubs, placeholders, or feature toggles).func (n *noop) BufferApiRequest(schema.ApiRequestV1) { + // Deliberately does nothing for now (no-op). } func (n *noop) BufferKeyVerification(schema.KeyVerificationRequestV1) { + // Deliberately does nothing for now (no-op). }go/pkg/zen/services.go (2)
9-11
: Add doc comments for theEventBuffer
interface.
Documenting how consumers should useBufferApiRequest
improves clarity when multiple buffering implementations exist in the system.
13-17
: Consider concurrency safety or usage guidelines.
Services
combines logging, database, and event buffering into a single struct. If multiple goroutines shareServices
, clarifying concurrency usage or adding synchronization (if needed) helps avoid data races.go/pkg/zen/errors.go (1)
5-13
: Add doc comments for error tags.
Providing inline documentation on why these specific error tags exist (e.g., typical scenarios in which they are used) helps new contributors or other teams quickly grasp their usage.go/pkg/zen/middleware_validate.go (2)
7-10
: Document theOpenApiValidator
struct’s purpose.
A brief explanation of how it works and the expected usage pattern can help future maintainers quickly understand its role in request processing.
12-26
: Optionally log validation errors.
Adding a log event before returning the JSON response in case of validation failure can be helpful for troubleshooting validation issues.err, valid := validator.Validate(s.r) if !valid { + s.Logger.Warn("Validation failed", "request_id", s.requestID, "error", err) err.RequestId = s.requestID return s.JSON(err.Status, err) } return next(s)
go/pkg/zen/middleware_logger.go (3)
10-10
: Consider exporting an interface or type alias for the Middleware.While the
Middleware
type is presumably defined elsewhere, if it's part of your public API, consider clarifying it with a doc comment here or exporting a common interface/alias. This can increase reusability and improve discoverability for others integrating with this middleware.
14-17
: Log the handler error for observability.Currently, if
next(s)
returns an error, that error isn’t logged. Logging this error or handling it in some way can improve debuggability and observability in production.nextErr := next(s) serviceLatency := time.Since(start) + if nextErr != nil { + logger.Error(s.Context(), "request failed", + slog.String("method", s.r.Method), + slog.String("path", s.r.URL.Path), + slog.Any("error", nextErr), + ) + }
19-24
: Augment log fields with remote IP or user agent if needed.Capturing additional request metadata (e.g., client IP, user agent) can help in incident tracing and analytics. If privacy or compliance is a concern, ensure these fields are properly sanitized.
go/cmd/main.go (2)
3-10
: Move command imports under a dedicated CLI package group.Grouping CLI-related imports together and standard library imports separately helps keep imports organized. This is a minor style preference but could improve clarity, especially as CLI commands scale.
22-40
: Provide structured error output.Currently, errors are flattened and printed to stdout. Leveraging structured logging (similar to
slog
usage) for these errors may help correlate failures with logs from other components.go/pkg/zen/routes/v2_ratelimit_limit/handler.go (2)
12-13
: Document route usage or add a short doc comment.Consider adding a short comment describing the purpose of this route (
/v2/ratelimit.limit
), clarifying what the handler does for new contributors or maintainers.
15-21
: Return a standardized error response body.Right now, a wrapped error is returned if parsing fails. You could benefit from consistently returning an RFC-compliant error response (e.g., standardized JSON error fields) to ensure alignment with API best practices.
go/pkg/clickhouse/flush.go (3)
12-12
: Export the function if needed externally; consider naming clarity.If this function is intended for public reuse, consider making it an exported function (capitalized) and providing a doc comment. Also confirm that “flush” is the best name to convey batch insertion, as “flush” often implies clearing a buffer.
18-22
: Consider partial successes and retries.Appending each row in a loop makes it harder to handle partial insertion failures or do a retry strategy on specific problematic rows. Investigate whether you need a more robust error-handling flow for advanced scenarios.
23-26
: Leverage logging or metrics on batch insert completion.Logging or emitting metrics upon successful batch insertion can help monitor throughput and identify bottlenecks, especially in high-load usage scenarios.
go/pkg/zen/route.go (3)
3-8
: Consider adding method-level doc comments.
TheRoute
interface is well-defined, but it may be helpful to include doc comments for each method to clarify usage, expected behavior, and the role ofWithMiddleware
.
10-14
: Maintain consistent naming and expand documentation if necessary.
Theroute
struct is concise and captures method, path, and the handler. Consider renaminghandleFn
to something likehandler
for consistency and clarity.
32-34
: Add additional checks or logging.
The call tohandleFn
is straightforward. However, adding structured logging or additional error context before returning could improve observability.go/pkg/zen/routes/v2_ratelimit_set_override/handler.go (2)
10-11
: Alias usage is fine, but consider documentation.
TypesRequest
andResponse
are helpful aliases. Consider adding a brief comment about their usage.
13-26
: Handle database insertion errors more extensively.
Returning a wrapped error is good. You may also want to add logging or metrics around the database call to track override setting attempts.go/pkg/system_errors/errors.go (1)
21-25
: Code type and constants are succinct.
Use ofACCESS_DENIED
as a single known code is fine; consider adding more codes or clarifying expansion strategy in doc comments.go/pkg/clickhouse/schema/requests.go (1)
18-27
: Key verification request structure is descriptive.
KeyVerificationRequestV1
includes essential fields for identity-based request tracking. Consider a doc comment to clarify usage and permitted values (e.g., acceptedOutcome
strings).go/pkg/zen/middleware_errors.go (2)
18-27
: Confirm that 404 responses include sufficient context for debugging.
TheNotFoundError
response is clean and descriptive. Consider also logging the original error to aid diagnostics in server logs.
28-31
: Incomplete handling for DatabaseError.
Currently, the code block forDatabaseError
is commented out. Ensure that database-related errors return helpful details or logs. Otherwise, the fallback 500 handling might obscure specific root causes.Would you like a proposed snippet for handling database errors more gracefully?
go/cmd/api/config.go (1)
3-27
: Consider aligning field names with Go conventions.
Fields likeNodeId
andUrl
typically follow Go’s capitalization style asNodeID
andURL
. This improves consistency and readability across the codebase.- NodeId string `json:"nodeId,omitempty" description:"A unique node id"` + NodeID string `json:"nodeId,omitempty" description:"A unique node id"` - Clickhouse *struct { - Url string `json:"url" minLength:"1"` + Clickhouse *struct { + URL string `json:"url" minLength:"1"`go/pkg/zen/middleware_metrics.go (2)
13-16
: Multiple regex passes could impact performance on large requests.
Because the code applies each pattern sequentially, consider merging or optimizing patterns if performance or overhead becomes an issue for big payloads.
18-24
: Redaction strategy is straightforward but potentially incomplete.
Currently, only"key"
and"plaintext"
fields are redacted. Review whether other sensitive fields (e.g.,"password"
,"token"
, or"secret"
) need redaction.go/pkg/zen/session.go (2)
28-36
: Avoid returning a nil error from a function that declares an error return.
Currently, theInit
method always returnsnil
. Consider removing the error return type or introducing validation logic that can actually return an error if initialization fails.-func (s *Session) Init(w http.ResponseWriter, r *http.Request) error { - s.requestID = uid.Request() - s.w = w - s.r = r - return nil +func (s *Session) Init(w http.ResponseWriter, r *http.Request) { + s.requestID = uid.Request() + s.w = w + s.r = r }
81-92
: UseSet
instead ofAdd
to avoid multiple headers with the same key.
When sending JSON responses multiple times, repeatedly callingAdd("content-type", "application/json")
will stack the headers. UsingSet
ensures only one content-type header is present.- s.ResponseWriter().Header().Add("content-type", "application/json") + s.ResponseWriter().Header().Set("content-type", "application/json")go/cmd/api/main.go (1)
35-42
: Consider handling missing or incorrect config files more gracefully.
Currently, ifLoadFile
fails, the function simply returns the error. Depending on usage, you might want to log additional context or retry.go/pkg/fault/wrap_test.go (1)
54-72
: Useful debugging statements but consider removing or refining logs (e.g., "ABC", "DEF", "GHI").
These logs may clutter test output and are typically used only for temporary debugging.- t.Log("ABC") ... - t.Log("DEF") ... - t.Log("GHI")go/pkg/fault/wrapped_test.go (1)
133-140
: Consider reintroducing theerrors.Is
check.
The comment onerrors.Is(wrapped2, baseErr)
suggests partial usage of Go's error unwrapping. Reintroducing or extending that test would verify that the wrapped error chain works seamlessly with standard library checks.go/pkg/fault/dst_test.go (3)
1-5
: Consider potential performance and maintainability trade-offs for the large-scale random test.
The disclaimers in this comment suggest that this code is experimental and might be removed if it breaks. However, generating up to 10,000 error chains, each of which can be up to 1,000 stack frames deep, may slow down CI and local test runs. Be mindful of possible timeouts or resource constraints in certain environments, and consider adding a more direct or deterministic test for critical logic.
21-22
: Evaluate feasibility of extensive test coverage with 10,000 runs.
Using 10,000 random test cases inTestDST
is thorough but might be excessive and time-consuming, especially when running in CI pipelines. Lowering this number or providing a quick-test vs. full-test mode could strike a better balance between coverage and runtime.Also applies to: 189-212
177-181
: Clarify random seed usage to facilitate reproduction.
Settingseed := time.Now().UnixNano()
ensures each run is unique but can complicate reproducing a specific failing test. You might consider printing the seed in failure messages or letting users supply a custom seed via environment variables to facilitate debugging.Also applies to: 214-235
go/pkg/database/queries/get_key_by_hash.sql (1)
1-3
: Ensure optimal query performance by adding an index on the hash column if not already present.
A parameterized query prevents SQL injection, but to avoid full table scans, confirm that thekeys
table has an index onhash
.go/Taskfile.yml (1)
1-22
: Consider adding coverage thresholds and more targeted tasks.
It may be helpful to add a coverage threshold to thetest
task (e.g.,-coverprofile
) and a subsequent step to fail the task if coverage falls below a certain percentage. You might also introduce separate tasks for release builds, or tasks that strip debug data or embed version metadata.go/Dockerfile (2)
1-4
: Remove unnecessary empty lines.Multiple consecutive empty lines can be consolidated into one for better readability.
1-20
: Add .dockerignore file to optimize builds.A .dockerignore file would prevent unnecessary files from being sent to the Docker daemon during builds.
Would you like me to generate a .dockerignore file with recommended exclusions?
Taskfile.yml (1)
53-56
: Enhance the generate-sql task with error handling and documentation.Consider adding:
- A description of the task's purpose
- Error handling for the case when drizzle-kit is not installed
- Validation of the generated SQL
generate-sql: + desc: Generate MySQL schema using drizzle-kit dir: internal/db cmds: + - command -v pnpm >/dev/null 2>&1 || { echo "pnpm is required but not installed. Aborting." >&2; exit 1; } - pnpm drizzle-kit generate --dialect=mysql + - echo "Validating generated SQL..." + - test -f drizzle/*.sql || { echo "SQL generation failed"; exit 1; }go/schema.json (2)
41-45
: Add URL pattern validation for heartbeat URL.The URL field should include a pattern to validate the URL format.
"url": { "type": "string", "description": "URL to send heartbeat to", - "minLength": 1 + "minLength": 1, + "pattern": "^https?://[\\w\\-\\.]+[\\w\\-]+(?::\\d+)?(?:/[\\w\\-\\./?%&=]*)?$" }
58-61
: Add enum for platform values.Define allowed values for the platform field to ensure consistency.
"platform": { "type": "string", - "description": "The platform this agent is running on" + "description": "The platform this agent is running on", + "enum": ["linux", "darwin", "windows"] },go/pkg/fault/README.md (2)
12-12
: Fix typo and improve clarity in inspiration section.The current text is hard to read and contains a typo.
-I goodartistscopygreatartistssteal'd a lot from [Southclaws/fault](https://github.com/Southclaws/fault). +This package is inspired by [Southclaws/fault](https://github.com/Southclaws/fault).
46-50
: Replace tabs with spaces in code example.The code example uses hard tabs which should be replaced with spaces for consistent formatting.
switch fault.GetTag(err) { - case DATABASE_ERROR: - // handle - default: - // handle + case DATABASE_ERROR: + // handle + default: + // handle }🧰 Tools
🪛 Markdownlint (0.37.0)
46-46: Column: 1
Hard tabs(MD010, no-hard-tabs)
47-47: Column: 1
Hard tabs(MD010, no-hard-tabs)
48-48: Column: 1
Hard tabs(MD010, no-hard-tabs)
49-49: Column: 1
Hard tabs(MD010, no-hard-tabs)
go/pkg/zen/README.md (2)
1-3
: Consider using native markdown for centering.Instead of HTML tags, consider using standard markdown for better compatibility and maintainability.
-<div align="center"> - <h1 align="center">Zen</h1> -</div> +<p align="center"> + <h1 align="center">Zen</h1> +</p>
27-31
: Enhance the philosophy section and improve wording.The philosophy section could be more impactful with:
- A clearer introduction
- More concise wording
## Philosophy -Zen is for developers who embrace Go's simplicity and power. By focusing only -on essential abstractions, it keeps your code clean, maintainable, and in -harmony with Go's design principles. +Zen is for developers who embrace Go's simplicity and power. By focusing on +essential abstractions, it keeps your code clean, maintainable, and aligned +with Go's design principles.🧰 Tools
🪛 LanguageTool
[style] ~30-~30: ‘in harmony with’ might be wordy. Consider a shorter alternative.
Context: ...eeps your code clean, maintainable, and in harmony with Go’s design principles.(EN_WORDINESS_PREMIUM_IN_HARMONY_WITH)
internal/db/drizzle/meta/0000_snapshot.json (1)
2472-2478
: Add IP address validation for audit logs.The
remote_ip
column in theaudit_log
table:
- Consider using INET6 type if your MySQL version supports it
- Add validation for IP address format
- Consider splitting into separate IPv4 and IPv6 columns if format validation is critical
go/pkg/database/schema.sql (2)
5-6
: Consider using CIDR notation for IP whitelist.The
ip_whitelist
field in theapis
table uses varchar(512) which might not be the most efficient way to store IP ranges.Consider using a specialized column type or format:
- `ip_whitelist` varchar(512), + `ip_whitelist` text CHECK (ip_whitelist IS NULL OR ip_whitelist ~ '^(\d{1,3}\.){3}\d{1,3}(/\d{1,2})?$'),
187-188
: Consider using JSON Schema for feature flags.The
beta_features
andfeatures
JSON columns in theworkspaces
table lack schema validation.Consider adding CHECK constraints to validate the JSON structure:
- `beta_features` json NOT NULL, - `features` json NOT NULL, + `beta_features` json NOT NULL CHECK (JSON_VALID(beta_features) AND JSON_SCHEMA_VALID('{ + "type": "object", + "properties": { + "enabled": {"type": "array", "items": {"type": "string"}} + } + }', beta_features)), + `features` json NOT NULL CHECK (JSON_VALID(features)),internal/db/drizzle/0000_aspiring_agent_zero.sql (1)
415-438
: Consider composite indexes for common query patterns.While the individual column indexes are good, consider adding composite indexes for common query patterns:
-- For filtering keys by workspace and status CREATE INDEX `workspace_enabled_idx` ON `keys` (`workspace_id`, `enabled`); -- For audit log queries by time range within workspace CREATE INDEX `workspace_time_idx` ON `audit_log` (`workspace_id`, `time`);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (6)
go/go.sum
is excluded by!**/*.sum
go/pkg/database/gen/db.go
is excluded by!**/gen/**
go/pkg/database/gen/get_key_by_hash.sql.go
is excluded by!**/gen/**
go/pkg/database/gen/insert_override.sql.go
is excluded by!**/gen/**
go/pkg/database/gen/models.go
is excluded by!**/gen/**
go/pkg/database/gen/querier.go
is excluded by!**/gen/**
📒 Files selected for processing (80)
Taskfile.yml
(1 hunks)apps/agent/pkg/openapi/openapi.json
(1 hunks)deployment/docker-compose.yaml
(1 hunks)go/.golangci.yaml
(1 hunks)go/Dockerfile
(1 hunks)go/Taskfile.yml
(1 hunks)go/cmd/api/config.go
(1 hunks)go/cmd/api/main.go
(1 hunks)go/cmd/main.go
(1 hunks)go/config.docker.json
(1 hunks)go/config.local.json
(1 hunks)go/go.mod
(1 hunks)go/pkg/api/errors/base.go
(0 hunks)go/pkg/api/errors/not_found.go
(0 hunks)go/pkg/api/handler.go
(0 hunks)go/pkg/api/openapi/config.yaml
(0 hunks)go/pkg/api/openapi/gen.go
(0 hunks)go/pkg/api/openapi/openapi.json
(0 hunks)go/pkg/api/router/router.go
(0 hunks)go/pkg/api/session/session.go
(0 hunks)go/pkg/api/validation/validator.go
(0 hunks)go/pkg/clickhouse/client.go
(1 hunks)go/pkg/clickhouse/flush.go
(1 hunks)go/pkg/clickhouse/interface.go
(1 hunks)go/pkg/clickhouse/noop.go
(1 hunks)go/pkg/clickhouse/schema/requests.go
(1 hunks)go/pkg/config/json.go
(1 hunks)go/pkg/config/json_test.go
(1 hunks)go/pkg/ctxutil/context.go
(1 hunks)go/pkg/database/database.go
(1 hunks)go/pkg/database/generate.go
(1 hunks)go/pkg/database/queries/get_key_by_hash.sql
(1 hunks)go/pkg/database/queries/insert_override.sql
(1 hunks)go/pkg/database/schema.sql
(1 hunks)go/pkg/database/sqlc.json
(1 hunks)go/pkg/fault/README.md
(1 hunks)go/pkg/fault/doc.go
(1 hunks)go/pkg/fault/dst_test.go
(1 hunks)go/pkg/fault/tag.go
(1 hunks)go/pkg/fault/tag_test.go
(1 hunks)go/pkg/fault/wrap.go
(1 hunks)go/pkg/fault/wrap_test.go
(1 hunks)go/pkg/fault/wrapped.go
(1 hunks)go/pkg/fault/wrapped_test.go
(1 hunks)go/pkg/logging/axiom.go
(0 hunks)go/pkg/logging/interface.go
(1 hunks)go/pkg/logging/logger.go
(0 hunks)go/pkg/logging/slog.go
(1 hunks)go/pkg/openapi/config.yaml
(0 hunks)go/pkg/openapi/gen.go
(0 hunks)go/pkg/openapi/openapi.json
(0 hunks)go/pkg/openapi/spec.go
(0 hunks)go/pkg/system_errors/errors.go
(1 hunks)go/pkg/tools/dependencies.go
(1 hunks)go/pkg/version/version.go
(1 hunks)go/pkg/zen/README.md
(1 hunks)go/pkg/zen/errors.go
(1 hunks)go/pkg/zen/handler.go
(1 hunks)go/pkg/zen/middleware.go
(1 hunks)go/pkg/zen/middleware_errors.go
(1 hunks)go/pkg/zen/middleware_logger.go
(1 hunks)go/pkg/zen/middleware_metrics.go
(1 hunks)go/pkg/zen/middleware_validate.go
(1 hunks)go/pkg/zen/openapi/config.yaml
(1 hunks)go/pkg/zen/openapi/gen.go
(1 hunks)go/pkg/zen/openapi/generate.go
(1 hunks)go/pkg/zen/openapi/openapi.json
(1 hunks)go/pkg/zen/openapi/scalar.config.json
(1 hunks)go/pkg/zen/route.go
(1 hunks)go/pkg/zen/routes/register.go
(1 hunks)go/pkg/zen/routes/v2_ratelimit_limit/handler.go
(1 hunks)go/pkg/zen/routes/v2_ratelimit_set_override/handler.go
(1 hunks)go/pkg/zen/server.go
(1 hunks)go/pkg/zen/services.go
(1 hunks)go/pkg/zen/session.go
(1 hunks)go/pkg/zen/validation/validator.go
(1 hunks)go/schema.json
(1 hunks)internal/db/drizzle/0000_aspiring_agent_zero.sql
(1 hunks)internal/db/drizzle/meta/0000_snapshot.json
(1 hunks)internal/db/drizzle/meta/_journal.json
(1 hunks)
💤 Files with no reviewable changes (15)
- go/pkg/api/handler.go
- go/pkg/openapi/spec.go
- go/pkg/api/openapi/config.yaml
- go/pkg/openapi/config.yaml
- go/pkg/openapi/gen.go
- go/pkg/openapi/openapi.json
- go/pkg/api/errors/not_found.go
- go/pkg/logging/logger.go
- go/pkg/api/router/router.go
- go/pkg/logging/axiom.go
- go/pkg/api/errors/base.go
- go/pkg/api/validation/validator.go
- go/pkg/api/openapi/openapi.json
- go/pkg/api/session/session.go
- go/pkg/api/openapi/gen.go
✅ Files skipped from review due to trivial changes (12)
- go/pkg/zen/openapi/generate.go
- go/pkg/version/version.go
- go/pkg/database/generate.go
- go/pkg/database/sqlc.json
- go/pkg/tools/dependencies.go
- go/pkg/zen/openapi/scalar.config.json
- go/config.docker.json
- go/pkg/zen/middleware.go
- internal/db/drizzle/meta/_journal.json
- go/config.local.json
- go/pkg/zen/openapi/config.yaml
- go/pkg/fault/doc.go
🧰 Additional context used
🪛 LanguageTool
go/pkg/fault/README.md
[style] ~65-~65: ‘in harmony with’ might be wordy. Consider a shorter alternative.
Context: ...eeps your code clean, maintainable, and in harmony with Go’s design principles. ## Usage Faul...
(EN_WORDINESS_PREMIUM_IN_HARMONY_WITH)
go/pkg/zen/README.md
[style] ~30-~30: ‘in harmony with’ might be wordy. Consider a shorter alternative.
Context: ...eeps your code clean, maintainable, and in harmony with Go’s design principles.
(EN_WORDINESS_PREMIUM_IN_HARMONY_WITH)
🪛 Markdownlint (0.37.0)
go/pkg/fault/README.md
46-46: Column: 1
Hard tabs
(MD010, no-hard-tabs)
47-47: Column: 1
Hard tabs
(MD010, no-hard-tabs)
48-48: Column: 1
Hard tabs
(MD010, no-hard-tabs)
49-49: Column: 1
Hard tabs
(MD010, no-hard-tabs)
56-56: Column: 43
Hard tabs
(MD010, no-hard-tabs)
🪛 checkov (3.2.334)
go/pkg/zen/openapi/openapi.json
[HIGH] 1-376: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[HIGH] 1-376: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Test Agent Local / test_agent_local
- GitHub Check: Build / Build
🔇 Additional comments (59)
go/pkg/fault/tag_test.go (2)
1-9
: Excellent use of sub-tests and imports.The package declaration and required imports are appropriate, and the usage of
"github.com/stretchr/testify/require"
keeps assertions concise. No issues identified here.
10-46
: Comprehensive test coverage forGetTag
.
- You cover essential scenarios:
nil
errors, untagged errors, tagged errors, and deeply wrapped tagged errors.- The table-driven approach using sub-tests improves readability and maintainability, making it straightforward to add new scenarios as needed.
go/pkg/ctxutil/context.go (1)
13-20
: Generic function usage is appropriate.
This is a clean approach to retrieving typed values from context. No further concerns.go/pkg/logging/interface.go (2)
1-2
: Package structure consistency looks good.The
package logging
aligns with the rest of the codebase, suggesting a coherent structure. No issues found here.
3-6
: Confirm compatibility ofslog
import version.Ensure that the imported
log/slog
package matches the version constraints used in the rest of the codebase. This prevents potential issues if older or newer versions differ in method signatures or behavior.✅ Verification successful
log/slog
import is compatible with the codebaseThe project uses Go 1.23.4 which fully supports the
log/slog
package (introduced in Go 1.21). Being a standard library package, it's guaranteed to be compatible with the specified Go version.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # This script checks all module definitions and go.mod files for the 'log/slog' package usage/version. rg 'log/slog' -A 5Length of output: 1110
Script:
#!/bin/bash # Check Go version in go.mod cat go/go.modLength of output: 6739
go/pkg/logging/slog.go (3)
1-2
: Package declaration is aligned with the intended logging functionalities.This file extends the
logging
package, staying consistent with the layering proposed ininterface.go
. Looks good.
43-53
: MethodWith
ensures immutability of logger state.Returning a new
logger
preserves immutability, which is beneficial if concurrency or multi-context usage is possible. Nice approach!
55-70
: Level-specific logging methods are straightforward and consistent.Each method leverages
LogAttrs
at the correct levels. Consider adding a trace or fatal method if required by the application. Otherwise, this satisfies most use cases.go/pkg/fault/tag.go (3)
5-7
: Good use of descriptive comments for theTag
type.
These comments clearly explain the rationale for using tags to classify errors, ensuring proper context and usage across the application.
33-39
: Efficient unwrapping loop inGetTag
.
The iterative approach viaerrors.Unwrap(err)
is correct and safe. Make sure you’re covering all nested error layers.
44-55
:WithTag
function design is straightforward and consistent.
Returning a closure allows you to lazily wrap errors with tags. This pattern is both idiomatic and convenient for chained error handling.go/pkg/fault/wrapped.go (5)
1-7
: Avoid confusion in package imports.
All imported packages appear relevant for error handling. If you anticipate implementing structured logging or different error formatting, consider organizing or grouping imports by domain.
65-99
: Ensure older messages appear first in the chain.
Your logic inError()
correctly orders messages from the oldest to the newest. This is consistent with typical user expectations for error chains.
100-102
: Unwrap method correctness.
TheUnwrap()
method looks correct, ensuring that Go's standard error unwrapping features work seamlessly for your wrapped errors.
9-19
: Validate usage references for thewrapped
type.
It's a good practice to ensure that no external package directly initializeswrapped
bypassingfault.New()
orfault.Wrap()
.Please run a quick search script to confirm that no external code is directly calling
wrapped{}
:✅ Verification successful
wrapped
struct initialization is properly encapsulated
All direct initializations of thewrapped
struct are contained within thefault
package, confirming that external packages are using the intendedfault.New()
orfault.Wrap()
functions.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # search references for direct usage of 'wrapped{' rg -A 3 $'wrapped\\{'Length of output: 645
104-121
: Confirm correct stack frame depth.
getLocation()
skips 3 frames, which commonly aligns with your function calling structure. If you have deeply nested constructor methods, consider adjusting this skip level.✅ Verification successful
Stack frame depth of 3 is correct and optimal
The current implementation correctly captures the location of error creation in user code by skipping internal implementation frames (getLocation, constructor, and public API function) while maintaining a consistent call depth across all error creation paths (New, Wrap).🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Attempt to locate any calls to getLocation to confirm correctness. rg -A 3 "getLocation"Length of output: 1176
Script:
#!/bin/bash # Find wrap/wrapped constructor implementations and their usage ast-grep --pattern 'func $_($$) *error { $$$ location: getLocation(), $$$ }' # Show the context of wrap.go and wrapped.go files cat go/pkg/fault/wrap.go go/pkg/fault/wrapped.goLength of output: 8184
go/pkg/config/json.go (1)
63-70
: Review the use ofAdditionalProperties = true
.
Allowing extra fields could introduce subtle issues if unrecognized properties sneak into your configuration. Consider requiring strict schema enforcement unless the requirement for flexible additions is intentional.go/pkg/zen/validation/validator.go (1)
14-22
: Add concurrency safety considerations if the validator is used in parallel.
If multiple goroutines use the sameOpenAPIValidator
instance, confirm thatlibopenapi-validator
is thread-safe. Otherwise, consider clarifying usage patterns or introducing locks.go/pkg/clickhouse/client.go (1)
31-41
: Handle potential TLS configuration and sensitive connections.
You’ve commented out theopts.TLS
line. Consider re-enabling or extending TLS for secure connections, especially if you’re sending credentials over untrusted networks.Do you want me to verify if secure connections are mandated by your deployment environment?
go/pkg/zen/server.go (2)
21-22
: Check for concurrency on the shared http.Server.
s.srv
is shared across the entire application. Ensure that no concurrency hazards occur when adding or modifying server configurations at runtime.
100-107
: Avoid race conditions onisListening
checks.
TheisListening
boolean is guarded by a mutex here, which is good. Confirm that the rest of the listening lifecycle (e.g., shutdown calls) also respects that lock to avoid inconsistent states.go/pkg/zen/openapi/gen.go (2)
1-6
: Auto-generated header comment.
This file explicitly states it’s code-generated. Usually, you should avoid directly modifying generated files; instead, configure the generator or apply post-generation scripts if changes are needed.
193-232
: Expose missing JSON body errors consistently.
The error handling logic for missing and malformed body parameters is consistent, but ensure that you always return a JSON error response if that’s your standard. Right now, it callssiw.ErrorHandlerFunc
. Confirm thatErrorHandlerFunc
itself writes JSON or an appropriate format matching the rest of the specification.go/pkg/zen/handler.go (1)
10-14
: Interface design looks good.
TheHandler
interface, coupled with theHandleFunc
type, is straightforward and easy to extend with middleware.go/pkg/clickhouse/noop.go (2)
7-9
: Minimalnoop
struct usage looks good.
Using an unexported struct and returning it viaNewNoop()
helps enforce controlled instantiation.
18-20
: Constructor usage is concise and consistent.
Returning a pointer to an unexported struct is a clean pattern.go/pkg/zen/routes/v2_ratelimit_limit/handler.go (1)
23-27
: Ensure functionality is tested.While a stub for request/response flow exists, confirm that the business logic (the “do stuff” part) and any side effects (e.g., DB updates, caching, etc.) have unit tests or integration tests in place.
go/pkg/zen/route.go (3)
16-22
: Constructor usage looks good.
NewRoute
properly returns theRoute
interface, which is a good practice for encapsulation and design flexibility.
36-38
: Method accessor is fine.
No significant concerns here.
40-42
: Path accessor is fine.
Similarly, this aligns with the minimal accessor pattern.go/pkg/zen/routes/v2_ratelimit_set_override/handler.go (2)
1-2
: Package name is clear.
Usingv2RatelimitLimit
conveys versioning convention.
3-8
: Imports are straightforward.
All dependencies are relevant.go/pkg/system_errors/errors.go (5)
5-11
: Fault type and constants are clear.
Explicit enumeration of known faults (AWS, Unkey, GitHub) is good for clarity and strongly typed usage.
13-19
: Service type and constants are well-defined.
Maintains clarity for scoping errors to particular services.
27-34
: EID comment is coherent.
The detailed doc comment helps maintain consistent usage and fosters readability.
36-40
: Error struct fields are properly typed.
This struct sets the foundation for structured error handling.
42-44
: EID generation is clear.
The use offmt.Sprintf
ensures a clean error ID format.go/pkg/clickhouse/schema/requests.go (1)
3-16
: Structured logging approach looks correct.
ApiRequestV1
comprehensively captures necessary request details. Ensure that sensitive data is handled or scrubbed before storing.Need help setting up a process for automatically anonymizing or hashing sensitive fields? Let me know!
go/pkg/zen/middleware_errors.go (2)
8-16
: Centralized error handling approach looks solid.
By wrapping the next handler with this middleware, you ensure that all errors funnel through a single handling mechanism, simplifying maintenance and making error responses consistent.
33-39
: Verify logging for unrecognized errors.
It’s common to log or capture unrecognized error details at the 500 level for observability. Without logging, debugging root causes of server errors can be challenging once returned to the client.go/cmd/api/config.go (1)
3-27
: Verify default values and validation rules.
Theport
field has a default of 8080, which is sensible, but confirm that your CLI or config loading mechanism recognizes thedefault
struct tag. Some frameworks may ignore it unless explicitly supported.go/pkg/config/json_test.go (3)
12-28
: Good negative test for missing required fields.
EnsuringLoadFile
catches a missing required field affirms robust input validation. Consider adding more tests to handle invalid JSON to further strengthen reliability.
30-46
: Ensuring correct struct assignment.
This test confirms field population, which is crucial for downstream logic. If the struct eventually expands, consider adding boundary and null checks.
48-65
: Environment variable expansion coverage is solid.
Testing configuration loading with template variables helps prevent misconfigurations. This is a best practice for flexible deployments.go/pkg/zen/middleware_metrics.go (1)
46-59
: Potential concurrency consideration with shared event buffers.
If multiple requests arrive simultaneously, ensure thateventBuffer.BufferApiRequest
is concurrency-safe. Confirm that the underlying data structure can handle parallel writes without data races.go/cmd/api/main.go (1)
62-69
: Approved use of panic capture for logging.
The deferred function effectively logs panic details with stack traces. This is a robust approach for debugging catastrophic failures.go/pkg/fault/wrap_test.go (2)
10-13
: Good check for nil wrapping.
The test ensuresWrap(nil)
remainsnil
, which is consistent with expected error handling patterns.
25-42
: Commendable coverage for single-wrapper scenarios.
The table-driven tests validate different wrapper use cases (description, tag, etc.), ensuring thorough coverage.go/pkg/fault/wrapped_test.go (1)
158-217
: Adequate test coverage for user-facing messages.
TheUserFacingMessage
function is comprehensively tested, including mixed public and internal messages and potential edge cases.go/pkg/database/queries/insert_override.sql (1)
1-23
: Review ID handling and concurrency precautions.
It's unclear whetherid
is auto-generated or controlled externally. If collisions are possible or concurrency is a concern, consider generating unique IDs (e.g., UUIDs) in the database. Also confirm that theasync
field defaults tofalse
in other inserts, if consistency is required.go/go.mod (2)
118-118
: Verify security advisories for crypto-related packages.These security-sensitive packages should be checked for known vulnerabilities:
- golang.org/x/crypto v0.32.0
- golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e
Also applies to: 119-119, 120-120, 121-121
✅ Verification successful
golang.org/x/crypto version is secure
The current version (v0.32.0) is not affected by any known vulnerabilities. All reported security issues were patched in earlier versions.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for security advisories in crypto-related packages # Check for security advisories gh api graphql -f query=' { securityVulnerabilities(first: 5, ecosystem: GO, package: "golang.org/x/crypto") { nodes { advisory { summary severity publishedAt } vulnerableVersionRange firstPatchedVersion { identifier } } } }'Length of output: 1705
6-6
: Verify ClickHouse client version compatibility.The ClickHouse client version
v2.28.1
is being added. Let's verify its compatibility with the server version.✅ Verification successful
The ClickHouse client version v2.28.1 is compatible and stable
This version was released in August 2024 and contains important stability fixes. No compatibility issues or breaking changes have been reported in newer versions (up to v2.30.1). The changes since v2.28.1 are mostly additive features and bug fixes.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check ClickHouse client compatibility with server version # Get the latest versions and compatibility info curl -s https://api.github.com/repos/ClickHouse/clickhouse-go/releases | jq -r '.[0] | {tag_name, body}' # Check for any known issues or breaking changes curl -s https://raw.githubusercontent.com/ClickHouse/clickhouse-go/master/CHANGELOG.mdLength of output: 46990
go/pkg/zen/openapi/openapi.json (1)
253-253
:⚠️ Potential issueRemove placeholder enum value.
The event enum contains a placeholder value 'xx' which should be replaced with actual event types.
- "event": enum('verifications.usage.record','xx') NOT NULL, + "event": enum('verifications.usage.record','key.created','key.deleted','key.updated') NOT NULL,Likely invalid or redundant comment.
internal/db/drizzle/meta/0000_snapshot.json (3)
1-5
: Schema versioning looks good.The schema is properly versioned with MySQL dialect specified.
2479-2485
: Consider user agent length limitation.The
user_agent
column in theaudit_log
table uses varchar(256):
- Modern user agent strings can be longer
- Consider increasing the length or using TEXT type
- Add truncation logic in the application layer
31-37
: Consider validating IP whitelist format.The
ip_whitelist
column in theapis
table might benefit from additional validation:
- Consider using a CHECK constraint or trigger to validate IP format
- The current varchar(512) might be too long for typical IP whitelist needs
go/pkg/database/schema.sql (1)
88-89
: Review encryption key length for security compliance.The
encrypted
field inencrypted_keys
table is limited to varchar(1024) which might be insufficient for some encryption algorithms.✅ Verification successful
The
encrypted
field length is appropriately sized for the current encryption implementation.The field length of 1024 characters is sufficient for the AES-256-GCM encryption implementation used in the codebase. The system includes comprehensive testing with various payload sizes and supports re-encryption if needed in the future.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check if there are any encryption-related configuration files fd -t f "encrypt|cipher|crypto" -x cat {} \; 2>/dev/nullLength of output: 17912
internal/db/drizzle/0000_aspiring_agent_zero.sql (1)
377-414
: LGTM! Comprehensive foreign key constraints.The foreign key constraints are well-defined with appropriate ON DELETE CASCADE rules for workspace-dependent tables.
apps/agent/pkg/openapi/openapi.json (1)
626-628
: Approve endpoint renaming for REST compliance.The endpoint renaming from
/ratelimit.v1.RatelimitService/Ratelimit
to/v1/ratelimit.limit
follows REST conventions better.
// | ||
// err := errors.New("base error") | ||
// withTag := Tag(DATABASE_ERROR)(err) | ||
// wrapped := fmt.Errorf("wrapped: %w", withTag) | ||
// fmt.Println(GetTag(wrapped)) // Output: DATABASE_ERROR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Correct the example usage to match the actual function calls.
Currently, the documentation sample uses Tag(DATABASE_ERROR)(err)
. The actual usage should call WithTag(DATABASE_ERROR)(err)
.
-// withTag := Tag(DATABASE_ERROR)(err)
+// withTag := WithTag(DATABASE_ERROR)(err)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// | |
// err := errors.New("base error") | |
// withTag := Tag(DATABASE_ERROR)(err) | |
// wrapped := fmt.Errorf("wrapped: %w", withTag) | |
// fmt.Println(GetTag(wrapped)) // Output: DATABASE_ERROR | |
// | |
// err := errors.New("base error") | |
// withTag := WithTag(DATABASE_ERROR)(err) | |
// wrapped := fmt.Errorf("wrapped: %w", withTag) | |
// fmt.Println(GetTag(wrapped)) // Output: DATABASE_ERROR |
go/pkg/clickhouse/client.go
Outdated
func (c *Clickhouse) Shutdown(ctx context.Context) error { | ||
c.requests.Close() | ||
return c.conn.Close() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Graceful shutdown: ensure flush completion.
Currently, the Shutdown
method only closes the requests
processor and then the DB connection. To avoid data loss, consider waiting for in-flight batches to be flushed before closing.
func (c *Clickhouse) Shutdown(ctx context.Context) error {
- c.requests.Close()
+ c.requests.Close() // Ensure all pending batches are fully processed.
return c.conn.Close()
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func (c *Clickhouse) Shutdown(ctx context.Context) error { | |
c.requests.Close() | |
return c.conn.Close() | |
} | |
func (c *Clickhouse) Shutdown(ctx context.Context) error { | |
c.requests.Close() // Ensure all pending batches are fully processed. | |
return c.conn.Close() | |
} |
go/pkg/zen/server.go
Outdated
func (s *Server) RegisterRoute(route Route) { | ||
|
||
s.mux.HandleFunc( | ||
fmt.Sprintf("%s %s", route.Method(), route.Path()), | ||
func(w http.ResponseWriter, r *http.Request) { | ||
|
||
sess, ok := s.getSession().(*Session) | ||
if !ok { | ||
panic("Unable to cast session") | ||
} | ||
defer func() { | ||
sess.reset() | ||
s.returnSession(sess) | ||
}() | ||
|
||
err := sess.Init(w, r) | ||
if err != nil { | ||
s.logger.Error(context.Background(), "failed to init session") | ||
return | ||
} | ||
|
||
// Apply middleware | ||
var handle HandleFunc = route.Handle | ||
|
||
for _, mw := range s.middlewares { | ||
handle = mw(handle) | ||
} | ||
|
||
err = handle(sess) | ||
|
||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarify routing with HTTP method constraints.
Using fmt.Sprintf("%s %s", route.Method(), route.Path())
as the pattern might confuse the standard net/http mux, which doesn't inherently parse this. Typically, you’d call mux.HandleFunc(path, handler)
and then check the method inside the handler. This pattern might lead to unmatched requests.
-func (s *Server) RegisterRoute(route Route) {
- s.mux.HandleFunc(
- fmt.Sprintf("%s %s", route.Method(), route.Path()),
- func(w http.ResponseWriter, r *http.Request) {
- // ...
- },
- )
+func (s *Server) RegisterRoute(route Route) {
+ s.mux.HandleFunc(route.Path(), func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != route.Method() {
+ http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
+ return
+ }
+ // ...
+ })
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func (s *Server) RegisterRoute(route Route) { | |
s.mux.HandleFunc( | |
fmt.Sprintf("%s %s", route.Method(), route.Path()), | |
func(w http.ResponseWriter, r *http.Request) { | |
sess, ok := s.getSession().(*Session) | |
if !ok { | |
panic("Unable to cast session") | |
} | |
defer func() { | |
sess.reset() | |
s.returnSession(sess) | |
}() | |
err := sess.Init(w, r) | |
if err != nil { | |
s.logger.Error(context.Background(), "failed to init session") | |
return | |
} | |
// Apply middleware | |
var handle HandleFunc = route.Handle | |
for _, mw := range s.middlewares { | |
handle = mw(handle) | |
} | |
err = handle(sess) | |
if err != nil { | |
panic(err) | |
} | |
}) | |
} | |
func (s *Server) RegisterRoute(route Route) { | |
s.mux.HandleFunc(route.Path(), func(w http.ResponseWriter, r *http.Request) { | |
if r.Method != route.Method() { | |
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) | |
return | |
} | |
sess, ok := s.getSession().(*Session) | |
if !ok { | |
panic("Unable to cast session") | |
} | |
defer func() { | |
sess.reset() | |
s.returnSession(sess) | |
}() | |
err := sess.Init(w, r) | |
if err != nil { | |
s.logger.Error(context.Background(), "failed to init session") | |
return | |
} | |
// Apply middleware | |
var handle HandleFunc = route.Handle | |
for _, mw := range s.middlewares { | |
handle = mw(handle) | |
} | |
err = handle(sess) | |
if err != nil { | |
panic(err) | |
} | |
}) | |
} |
`event` enum('verifications.usage.record','xx') NOT NULL, | ||
`time` bigint NOT NULL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove placeholder enum value 'xx'.
The event
enum in the events
table contains a placeholder value 'xx' which should be removed or replaced with actual event types.
- `event` enum('verifications.usage.record','xx') NOT NULL,
+ `event` enum('verifications.usage.record') NOT NULL,
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
`event` enum('verifications.usage.record','xx') NOT NULL, | |
`time` bigint NOT NULL, | |
`event` enum('verifications.usage.record') NOT NULL, | |
`time` bigint NOT NULL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
go/api/openapi.json (1)
208-376
: Endpoints are thoroughly specified; consider including security fields.The liveness and rate-limit endpoints are clearly documented with robust request/response schemas. As the static analysis hints, you may add a
security
object at the path/operation or global level, ensuring you can enforce authentication or authorization if needed.Would you like assistance adding a global security definition in the OpenAPI file to address the checkov findings?
🧰 Tools
🪛 checkov (3.2.334)
[HIGH] 1-376: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[HIGH] 1-376: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
go/Dockerfile
(1 hunks)go/api/config.yaml
(1 hunks)go/api/gen.go
(1 hunks)go/api/generate.go
(1 hunks)go/api/openapi.json
(1 hunks)go/api/scalar.config.json
(1 hunks)go/api/spec.go
(1 hunks)go/pkg/zen/middleware_errors.go
(1 hunks)go/pkg/zen/routes/v2_ratelimit_limit/handler.go
(1 hunks)go/pkg/zen/routes/v2_ratelimit_set_override/handler.go
(1 hunks)go/pkg/zen/validation/validator.go
(1 hunks)
✅ Files skipped from review due to trivial changes (4)
- go/api/generate.go
- go/api/spec.go
- go/api/config.yaml
- go/api/scalar.config.json
🚧 Files skipped from review as they are similar to previous changes (5)
- go/pkg/zen/middleware_errors.go
- go/Dockerfile
- go/pkg/zen/routes/v2_ratelimit_set_override/handler.go
- go/pkg/zen/routes/v2_ratelimit_limit/handler.go
- go/pkg/zen/validation/validator.go
🧰 Additional context used
🪛 checkov (3.2.334)
go/api/openapi.json
[HIGH] 1-376: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[HIGH] 1-376: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Build / Build
- GitHub Check: Test Agent Local / test_agent_local
🔇 Additional comments (8)
go/api/gen.go (7)
1-7
: Good use of build constraint & package annotation.These lines set up the file for Go 1.22 and reference that it’s generated code. No issues found here; everything looks consistent and properly annotated.
8-16
: Imports look consistent.All imported packages appear to be used, and the runtime references align with the generated code approach. No obvious improvements needed.
18-61
: Well-structured error models.The
BadRequestError
andBaseError
structs clearly define standard problem-details-style fields. This layout aligns with best practices for returning descriptive HTTP error responses. Keep in mind that concurrency aspects aren’t relevant here, and performance overhead is minimal. Everything looks good.
63-127
: Consistent aliasing for specialized errors & request/response bodies.Using type aliases (
type InternalServerError = BaseError
etc.) is a neat approach to unify error structures while providing distinct semantic types. The newly added request/response bodies (e.g.,V2LivenessResponseBody
,V2RatelimitLimitRequestBody
,V2RatelimitLimitResponseBody
,V2RatelimitSetOverrideRequestBody
,V2RatelimitSetOverrideResponseBody
) also fit well into an API-first design. No major concerns.
129-233
: Validation and rate-limit wrapper logic appear seamless.The
ValidationError
struct andV1RatelimitLimitParams
usage are straightforward for parameter binding. TheServerInterface
andServerInterfaceWrapper
present a well-defined contract, elevating clarity for the request flow.
234-293
: Middleware and param error definitions.These definitions (
UnescapedCookieParamError
,UnmarshalingParamError
,RequiredParamError
,RequiredHeaderError
, etc.) comprehensively handle edge cases in request parsing. This approach significantly enhances reliability.
295-617
: Comprehensive routing and strict mode handlers.The
HandlerWithOptions
,StrictServerInterface
, and related functions/middleware provide a flexible framework. The code generation approach ensures type safety and minimal boilerplate. Keep an eye on versioning for upstreamoapi-codegen
to stay current with improvements. Overall, this is clean and robust.go/api/openapi.json (1)
1-14
: Clear metadata and versioning.The title, version, and servers provide a strong foundation for discoverability. The use of
2.0.0
clarifies a breaking or new major release.🧰 Tools
🪛 checkov (3.2.334)
[HIGH] 1-376: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[HIGH] 1-376: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
♻️ Duplicate comments (2)
go/pkg/zen/session.go (1)
29-35
:⚠️ Potential issueCritical: Request body is not being read in Init.
The
Init
method should read and store the request body. Currently,requestBody
is never populated, which will causeBindBody
to fail.func (s *Session) Init(w http.ResponseWriter, r *http.Request) error { s.requestID = uid.Request() s.w = w s.r = r + // Read and store the request body + if r.Body != nil { + var err error + s.requestBody, err = io.ReadAll(r.Body) + if err != nil { + return fault.Wrap(err, fault.WithDesc("failed to read request body", "Unable to read the request body.")) + } + // Restore the body for potential future reads + r.Body = io.NopCloser(bytes.NewBuffer(s.requestBody)) + } return nil }Don't forget to add these imports:
+ "bytes" + "io"go/cmd/api/main.go (1)
110-116
: 🛠️ Refactor suggestionMove schema generation to a build step.
Generating schema at runtime impacts performance and complicates deployments. Consider moving this to a dedicated command or build step.
🧹 Nitpick comments (18)
go/pkg/clock/test_clock.go (1)
16-16
: Provide a brief rationale for thenolint:exhaustruct
directive and keep the interface assertion.While ignoring certain lint checks is sometimes necessary, it's helpful to provide a short explanation or comment to guide future maintainers on why the linter rule must be bypassed. Meanwhile, asserting that
TestClock
implements theClock
interface in this manner is a clean and conventional approach in Go..github/workflows/job_test_go_api_local.yaml (1)
24-24
: Ensure tparse is available and consider adding test configuration.The test command uses
tparse
but there's no step to install it. Additionally, consider:
- Adding environment variables for test configuration
- Specifying test coverage thresholds
- Configuring test result artifacts
- run: go test -cover -json -timeout=60m -failfast ./... | tparse -all -progress + run: | + go install github.com/mfridman/tparse@latest + go test -coverprofile=coverage.out -json -timeout=60m -failfast ./... | tparse -all -progress + env: + GO_ENV: test + MIN_COVERAGE: 80.github/workflows/pr.yaml (2)
48-50
: Consider job dependencies and cleanup commented code.The new
test_go_api_local
job looks good, but consider:
- Adding
needs
dependency if this should run after specific jobs- Cleaning up the commented
test_agent_integration
job if it's no longer neededtest_go_api_local: name: Test GO API Local + needs: [test_packages, build] uses: ./.github/workflows/job_test_go_api_local.yaml
47-47
: Remove unnecessary blank line.There's an extra blank line before the new job definition that can be removed for better readability.
go/pkg/fault/wrapped.go (1)
105-122
: Consider capturing a full stack trace.
Currently, only the file name and line number are stored, but more detailed traces may be beneficial to diagnose deeply nested errors.go/pkg/fault/wrapped_test.go (3)
13-54
: Consider adding test coverage for an empty message with no wrappers
While these table-driven tests are thorough, it could be valuable to add a scenario where the base message is an empty string and no wrappers are provided, to confirm that the function handles this edge case gracefully.
119-132
: Consider platform differences in path separators
getLocation()
currently checks for a file suffix of ".go". On some platforms or under special build contexts, the path separator could differ. While it’s unlikely to cause issues here, a minor improvement could be to normalize paths or split usingfilepath
utilities from the standard library.
156-215
: Add a test for tagged errors without public messages
Since you useWithTag("ERROR_TAG")
in some places, consider adding a scenario where the error is tagged but provides no public message. Verifying that the user-facing message remains empty in that case would strengthen coverage for the tag-based error flow.go/pkg/zen/session.go (2)
12-27
: Add field documentation for better maintainability.While the struct-level documentation is excellent, adding field-level documentation would improve maintainability and make the code more self-documenting.
Add documentation for each field:
type Session struct { + // requestID uniquely identifies the request requestID string + // w is the HTTP response writer w http.ResponseWriter + // r is the HTTP request r *http.Request + // requestBody holds the raw request body bytes requestBody []byte + // responseStatus holds the HTTP status code of the response responseStatus int + // responseBody holds the raw response body bytes responseBody []byte }
85-96
: Use cached ResponseWriter consistently.The
JSON
method usesResponseWriter()
for header manipulation but has direct access tos.w
. This is inconsistent with the rest of the code.func (s *Session) JSON(status int, body any) error { b, err := json.Marshal(body) if err != nil { return fault.Wrap(err, fault.WithDesc("json marshal failed", "The response body could not be marshalled to JSON."), ) } - s.ResponseWriter().Header().Add("Content-Type", "application/json") + s.w.Header().Add("Content-Type", "application/json") return s.send(status, b) }go/pkg/fault/wrap.go (1)
1-91
: Consider performance implications of deep error wrapping.The error handling design is robust and provides excellent separation between internal and public error information. However, deep error wrapping can impact performance in hot paths. Consider:
- Adding benchmarks to measure the impact
- Documenting performance characteristics
- Providing guidelines for appropriate wrapping depth
Would you like me to generate benchmark tests for the error wrapping implementation?
go/cmd/api/main.go (2)
23-30
: Consider renaming the environment variable for consistency.The environment variable
AGENT_CONFIG_FILE
seems inconsistent with the command name "api". Consider usingAPI_CONFIG_FILE
instead to maintain naming consistency.- EnvVars: []string{"AGENT_CONFIG_FILE"}, + EnvVars: []string{"API_CONFIG_FILE"},
52-52
: Development mode is hardcoded.The logger is always created in development mode with colors enabled. Consider making these configurable via the configuration file.
- logger := logging.New(logging.Config{Development: true, NoColor: false}) + logger := logging.New(logging.Config{ + Development: cfg.Development, + NoColor: cfg.NoColor, + })go/.golangci.yaml (1)
331-351
: Adjust issue handling configuration.
- The
max-same-issues: 50
is very high (default: 3) and might hide systematic problems.- Consider keeping security-related linters enabled for test files.
Apply these changes:
# Maximum count of issues with the same text. # Set to 0 to disable. # Default: 3 - max-same-issues: 50 + max-same-issues: 10 exclude-rules: - path: "_test\\.go" linters: - bodyclose - dupl - funlen - goconst - - gosec - noctx - wrapcheck - errcheckgo/pkg/fault/dst_test.go (4)
1-5
: Consider enhancing the documentation.While the comment explains the experimental nature, it would be helpful to:
- Document what "DST" stands for (Differential/Dynamic Software Testing)
- Explain the benefits and limitations of this testing approach
- Add criteria for when to "yank it out"
55-74
: Optimize word generation for better performance.The current word generation alternates between vowels and consonants, which might produce unrealistic words. Consider:
- Using a pre-generated word list for better realism
- Caching generated words to reduce string allocations
- Using
strings.Builder
with a pre-allocated capacityfunc (g *Generator) generateRandomWord(minLen, maxLen int) string { + word := strings.Builder{} + word.Grow(maxLen) // Pre-allocate capacity consonants := "bcdfghjklmnpqrstvwxyz" vowels := "aeiou" length := g.rng.Intn(maxLen-minLen+1) + minLen - var word strings.Builder useVowel := g.rng.Float32() < 0.5 for i := 0; i < length; i++ {
144-175
: Consider making error chain generation more configurable.The error chain generation uses hardcoded probabilities (0.7 for tags, 0.8 for descriptions). Consider:
- Making these probabilities configurable
- Adding documentation explaining the chosen values
- Using constants for better maintainability
+const ( + tagProbability = 0.7 + descProbability = 0.8 +) func (g *ErrorChainGenerator) generateErrorChain() (error, []fault.Tag, []string) { // ... - if g.rng.Float32() < 0.7 { + if g.rng.Float32() < tagProbability { // ... } - if g.rng.Float32() < 0.8 { + if g.rng.Float32() < descProbability { // ... }
214-235
: Consider expanding reproducibility test coverage.The reproducibility test is good but could be enhanced:
- Test with different seeds
- Verify error chain structure, not just string representation
- Add negative test cases (different seeds should produce different results)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (31)
.github/workflows/job_test_go_api_local.yaml
(1 hunks).github/workflows/pr.yaml
(1 hunks)go/.golangci.yaml
(1 hunks)go/cmd/api/main.go
(1 hunks)go/pkg/clickhouse/client.go
(1 hunks)go/pkg/clock/test_clock.go
(1 hunks)go/pkg/config/json.go
(1 hunks)go/pkg/config/json_test.go
(1 hunks)go/pkg/database/database.go
(1 hunks)go/pkg/fault/dst_test.go
(1 hunks)go/pkg/fault/tag.go
(1 hunks)go/pkg/fault/wrap.go
(1 hunks)go/pkg/fault/wrap_test.go
(1 hunks)go/pkg/fault/wrapped.go
(1 hunks)go/pkg/fault/wrapped_test.go
(1 hunks)go/pkg/logging/slog.go
(1 hunks)go/pkg/system_errors/errors.go
(1 hunks)go/pkg/uid/uid.go
(1 hunks)go/pkg/zen/errors.go
(1 hunks)go/pkg/zen/handler.go
(1 hunks)go/pkg/zen/middleware_errors.go
(1 hunks)go/pkg/zen/middleware_logger.go
(1 hunks)go/pkg/zen/middleware_metrics.go
(1 hunks)go/pkg/zen/middleware_validate.go
(1 hunks)go/pkg/zen/route.go
(1 hunks)go/pkg/zen/routes/register.go
(1 hunks)go/pkg/zen/routes/v2_ratelimit_limit/handler.go
(1 hunks)go/pkg/zen/routes/v2_ratelimit_set_override/handler.go
(1 hunks)go/pkg/zen/server.go
(1 hunks)go/pkg/zen/session.go
(1 hunks)go/pkg/zen/validation/validator.go
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- go/pkg/uid/uid.go
🚧 Files skipped from review as they are similar to previous changes (20)
- go/pkg/zen/routes/register.go
- go/pkg/zen/handler.go
- go/pkg/zen/middleware_validate.go
- go/pkg/zen/errors.go
- go/pkg/zen/middleware_errors.go
- go/pkg/zen/routes/v2_ratelimit_limit/handler.go
- go/pkg/zen/validation/validator.go
- go/pkg/database/database.go
- go/pkg/zen/middleware_logger.go
- go/pkg/fault/wrap_test.go
- go/pkg/fault/tag.go
- go/pkg/config/json.go
- go/pkg/zen/routes/v2_ratelimit_set_override/handler.go
- go/pkg/zen/route.go
- go/pkg/zen/middleware_metrics.go
- go/pkg/system_errors/errors.go
- go/pkg/zen/server.go
- go/pkg/logging/slog.go
- go/pkg/config/json_test.go
- go/pkg/clickhouse/client.go
⏰ Context from checks skipped due to timeout of 90000ms (6)
- GitHub Check: Test Packages / Test ./packages/nextjs
- GitHub Check: Test Packages / Test ./packages/cache
- GitHub Check: Test Packages / Test ./internal/clickhouse
- GitHub Check: Test Agent Local / test_agent_local
- GitHub Check: Test API / API Test Local
- GitHub Check: Build / Build
🔇 Additional comments (21)
.github/workflows/job_test_go_api_local.yaml (1)
20-21
: Verify the working directory structure.The
working-directory: go
assumes a specific repository structure. Please ensure this matches your repository layout.✅ Verification successful
Directory structure verification successful
The
working-directory: go
setting is correct. The repository has a properly structured Go project in thego
directory with the required Taskfile.yml present.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Verify the existence of the go directory and its contents if [ -d "go" ]; then echo "✓ 'go' directory exists" ls -la go/ else echo "✗ 'go' directory not found" fi # Check for task configuration if [ -f "go/Taskfile.yml" ] || [ -f "go/Taskfile.yaml" ]; then echo "✓ Taskfile found" else echo "✗ No Taskfile found in go directory" fiLength of output: 968
go/pkg/fault/wrapped.go (7)
1-2
: Package definition looks good.
No issues identified here.
9-19
: Well-documented struct.
The doc comments clearly describe the purpose and usage of the wrapped error type.
25-25
: Unused field check.
Thetag Tag
field appears in the struct but is never referenced in this file.Do you plan on using this field from other parts of the codebase, or can it be removed to reduce clutter?
38-64
: Inconsistent usage of message fields.
InNew()
, the providedmessage
is assigned to theinternal
field rather than thepublic
field. Verify whether this is intentional. If you intend to show the message to end users, consider using aWithDesc
wrapper or storing it in thepublic
field.
66-99
: Duplicate: fallback behavior for unwrapped errors may disclose sensitive details.
This code appends the entire unwrapped error string, which can inadvertently leak internal info. Past reviews have suggested returning a generic error.Apply this diff if you prefer a safer fallback:
-if !ok { - errs = append(errs, current.err.Error()) - break +if !ok { + errs = append(errs, "An unexpected error occurred.") + break }
101-103
: Unwrap method is well-structured.
This is consistent with Go's error idioms and ensures proper chain unwrapping.
124-193
: UserFacingMessage design is clear.
Collecting only thepublic
field in a chain is a robust approach to avoid exposing sensitive details.go/pkg/fault/wrapped_test.go (2)
56-117
: Great coverage of wrapped error scenarios
Your tests cover empty wrappers, deeply nested errors, and mixing standard library errors with custom ones. It thoroughly validates the error messages formed by sequential wraps.
134-155
: Comprehensive test for multi-level unwrapping
This test ensures that each level of wrapping is correctly unwrapped all the way down to the base error. The logic and coverage here look robust.go/pkg/zen/session.go (2)
1-10
: LGTM! Clean package structure and imports.The package structure is well-organized with necessary imports from both standard library and internal packages.
98-110
: LGTM! Thorough cleanup in reset method.The reset method properly cleans up all fields, which is crucial for session reuse.
go/pkg/fault/wrap.go (4)
1-7
: Well-documented type definition!The
Wrapper
type is clearly documented and follows Go idioms for error handling transformations.
8-20
: Excellent documentation with examples!The function documentation is comprehensive and includes practical usage examples.
39-75
: Comprehensive documentation with clear examples!The function documentation is excellent, providing both basic and advanced usage examples with clear parameter descriptions.
20-37
: Verify dependencies and consider additional validations.A few concerns about the implementation:
- The code references an undefined
wrapped
struct andgetLocation()
function- The
tag
field is initialized but appears unused- Consider validating the
wraps
parameter for nil/empty casesLet's verify the dependencies:
✅ Verification successful
Dependencies verified, implementation is sound
The concerns have been addressed:
- The
wrapped
struct andgetLocation()
are properly defined inwrapped.go
- The
tag
field is an intentional part of the error wrapping mechanism- The current validation for
err == nil
is sufficient, and the variadicwraps
parameter is handled appropriately🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for wrapped struct definition echo "Searching for wrapped struct..." rg -p "type wrapped struct" ./go/pkg/fault/ # Search for getLocation implementation echo "Searching for getLocation function..." rg -p "func getLocation" ./go/pkg/fault/ # Search for tag field usage echo "Searching for tag field usage..." rg "tag.*string" ./go/pkg/fault/Length of output: 465
Script:
#!/bin/bash # Get complete wrapped struct implementation and surrounding context echo "=== Wrapped struct implementation ===" rg -A 10 "type wrapped struct" ./go/pkg/fault/wrapped.go # Search for methods using wrapped struct echo -e "\n=== Methods using wrapped struct ===" rg "func.*\*wrapped" ./go/pkg/fault/ # Search for validation patterns echo -e "\n=== Validation patterns ===" rg "if.*nil|len.*wraps" ./go/pkg/fault/Length of output: 1432
go/cmd/api/main.go (1)
1-18
: LGTM! Well-organized imports.The package name and imports are appropriate for the API implementation.
go/.golangci.yaml (2)
10-13
: Verify if 3-minute timeout is necessary.The timeout is set to 3 minutes, which is significantly higher than the default 1 minute. While this might be necessary for a large codebase, consider:
- Profiling the lint execution to identify slow linters
- Running linters in parallel if not already enabled
✅ Verification successful
3-minute timeout setting is appropriate
The timeout setting is justified given:
- Codebase size (~23K lines across 239 files)
- Multiple thorough analysis linters enabled (staticcheck, gocognit, exhaustive)
- Complex checks including cognitive complexity and exhaustiveness analysis
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check the actual time taken by golangci-lint # Test: Time the linting process time golangci-lint run --timeout 3m --verbose 2>&1 | tee lint.log # Analyze which linters are taking the most time grep "took" lint.log | sort -k4 -nLength of output: 270
Script:
#!/bin/bash # Check repository structure and complexity echo "=== Go Files Count and Size ===" fd -e go -x wc -l {} \; | awk '{total += $1} END {print "Total files:", NR, "\nTotal lines:", total}' echo -e "\n=== Complex Patterns ===" # Check for large functions (potential complexity) rg -U "func.*{.*}" -A 50 | grep -c "}" echo -e "\n=== CI Configuration ===" # Look for CI configs fd -e yml -e yaml . .github/workflows/ # Check for parallel settings in golangci config echo -e "\n=== Parallel Settings ===" grep -A 5 "run:" go/.golangci.yamlLength of output: 1919
Script:
#!/bin/bash # Check for large functions and parallel settings echo "=== Function Complexity ===" # Count functions with more than 50 lines rg "^func\s+\w+.*{" -A 50 | grep -c "^}" echo -e "\n=== Parallel Settings ===" # Check all run-related settings cat go/.golangci.yaml | grep -A 10 "^run:" echo -e "\n=== Linter Configuration ===" # Check which linters are enabled cat go/.golangci.yaml | grep -A 30 "^linters:"Length of output: 2840
216-306
: 🛠️ Refactor suggestionEnable additional critical linters.
Consider enabling these important linters for better code quality:
- Security:
errorlint
: Ensures proper error wrapping (Go 1.13+)noctx
: Prevents HTTP requests without context- Best practices:
goimports
: Ensures consistent import formattingstylecheck
: Modern replacement for golint- Documentation:
godot
: Ensures consistent comment formattingApply these changes:
enable: # existing linters... + - errorlint + - noctx + - goimports + - stylecheck + - godotLikely invalid or redundant comment.
go/pkg/fault/dst_test.go (2)
1-235
: Overall implementation looks good!The DST framework is well-structured and provides good test coverage. While there are opportunities for optimization and configuration improvements, the current implementation is solid and serves its experimental purpose well.
20-35
: Review test parameters for performance impact.The high values for
maxDepth
(1000) andnumTestCases
(10000) could lead to:
- Long test execution times
- Potential memory pressure from deep error chains
- CI pipeline slowdowns
Consider:
- Adding justification comments for these values
- Making them configurable via environment variables
- Reducing values for regular test runs
|
||
|
||
jobs: | ||
test_agent_local: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Rename job to match its purpose.
The job name test_agent_local
seems incorrect as this workflow is for testing the Go API (based on the workflow name and file path). Consider renaming it to test_api_local
for consistency.
- test_agent_local:
+ test_api_local:
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
test_agent_local: | |
test_api_local: |
func (s *Session) BindBody(dst any) error { | ||
err := json.Unmarshal(s.requestBody, dst) | ||
if err != nil { | ||
return fault.Wrap(err, | ||
fault.WithDesc("failed to unmarshal request body", "The request body was not valid json."), | ||
) | ||
} | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add nil check in BindBody.
Add a nil check to prevent panic when unmarshaling empty request body.
func (s *Session) BindBody(dst any) error {
+ if len(s.requestBody) == 0 {
+ return fault.New(
+ fault.WithDesc("empty request body", "The request body was empty but the handler expected JSON data."),
+ )
+ }
err := json.Unmarshal(s.requestBody, dst)
if err != nil {
return fault.Wrap(err,
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func (s *Session) BindBody(dst any) error { | |
err := json.Unmarshal(s.requestBody, dst) | |
if err != nil { | |
return fault.Wrap(err, | |
fault.WithDesc("failed to unmarshal request body", "The request body was not valid json."), | |
) | |
} | |
return nil | |
} | |
func (s *Session) BindBody(dst any) error { | |
if len(s.requestBody) == 0 { | |
return fault.New( | |
fault.WithDesc("empty request body", "The request body was empty but the handler expected JSON data."), | |
) | |
} | |
err := json.Unmarshal(s.requestBody, dst) | |
if err != nil { | |
return fault.Wrap(err, | |
fault.WithDesc("failed to unmarshal request body", "The request body was not valid json."), | |
) | |
} | |
return nil | |
} |
func (s *Session) send(status int, body []byte) error { | ||
// Store the status and body for middleware use | ||
// Unlike the headers, we can't access it on the responseWriter | ||
s.responseStatus = status | ||
s.responseBody = body | ||
|
||
s.w.WriteHeader(status) | ||
_, err := s.w.Write(body) | ||
if err != nil { | ||
return fault.Wrap(err, fault.WithDesc("failed to send bytes", "Unable to send response body.")) | ||
} | ||
|
||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add Content-Length header in send method.
The send
method should set the Content-Length header to ensure proper HTTP/1.1 behavior.
func (s *Session) send(status int, body []byte) error {
// Store the status and body for middleware use
// Unlike the headers, we can't access it on the responseWriter
s.responseStatus = status
s.responseBody = body
+ s.w.Header().Set("Content-Length", strconv.Itoa(len(body)))
s.w.WriteHeader(status)
_, err := s.w.Write(body)
Don't forget to add this import:
+ "strconv"
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func (s *Session) send(status int, body []byte) error { | |
// Store the status and body for middleware use | |
// Unlike the headers, we can't access it on the responseWriter | |
s.responseStatus = status | |
s.responseBody = body | |
s.w.WriteHeader(status) | |
_, err := s.w.Write(body) | |
if err != nil { | |
return fault.Wrap(err, fault.WithDesc("failed to send bytes", "Unable to send response body.")) | |
} | |
return nil | |
} | |
func (s *Session) send(status int, body []byte) error { | |
// Store the status and body for middleware use | |
// Unlike the headers, we can't access it on the responseWriter | |
s.responseStatus = status | |
s.responseBody = body | |
s.w.Header().Set("Content-Length", strconv.Itoa(len(body))) | |
s.w.WriteHeader(status) | |
_, err := s.w.Write(body) | |
if err != nil { | |
return fault.Wrap(err, fault.WithDesc("failed to send bytes", "Unable to send response body.")) | |
} | |
return nil | |
} |
func WithDesc(internal string, public string) Wrapper { | ||
|
||
return func(err error) error { | ||
if err == nil { | ||
return nil | ||
} | ||
|
||
return &wrapped{ | ||
err: err, | ||
tag: "", | ||
location: "", | ||
internal: internal, | ||
public: public, | ||
} | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider improvements to error wrapping consistency.
Several suggestions for the implementation:
- The
location
field is set to empty string, whileWrap
usesgetLocation()
. Consider usinggetLocation()
here for consistency. - Consider validating that
internal
andpublic
strings are not empty. - The
tag
field initialization appears unnecessary if unused.
Here's a suggested improvement:
func WithDesc(internal string, public string) Wrapper {
+ if internal == "" || public == "" {
+ panic("internal and public descriptions must not be empty")
+ }
return func(err error) error {
if err == nil {
return nil
}
return &wrapped{
err: err,
- tag: "",
- location: "",
+ location: getLocation(),
internal: internal,
public: public,
}
}
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func WithDesc(internal string, public string) Wrapper { | |
return func(err error) error { | |
if err == nil { | |
return nil | |
} | |
return &wrapped{ | |
err: err, | |
tag: "", | |
location: "", | |
internal: internal, | |
public: public, | |
} | |
} | |
} | |
func WithDesc(internal string, public string) Wrapper { | |
if internal == "" || public == "" { | |
panic("internal and public descriptions must not be empty") | |
} | |
return func(err error) error { | |
if err == nil { | |
return nil | |
} | |
return &wrapped{ | |
err: err, | |
location: getLocation(), | |
internal: internal, | |
public: public, | |
} | |
} | |
} |
Summary by CodeRabbit
Release Notes
New Features
Infrastructure
Development Tools
Performance