Skip to content
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

Merged
merged 24 commits into from
Jan 24, 2025
Merged

feat: api v2 init #2832

merged 24 commits into from
Jan 24, 2025

Conversation

chronark
Copy link
Collaborator

@chronark chronark commented Jan 22, 2025

  • wip
  • wip
  • wip
  • wip
  • wip
  • wip
  • welcome zen

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a new API server with comprehensive error handling and middleware support.
    • Introduced structured logging with multiple log levels.
    • Implemented a new fault handling system for robust error management.
    • Added OpenAPI specification for rate limit and liveness endpoints.
    • Created a new database schema with extensive table definitions.
    • Introduced a new task for generating SQL.
    • Added a new configuration management system for handling API specifications.
  • Infrastructure

    • Updated Docker Compose configuration to include a new API service.
    • Added configuration management for local and Docker environments.
    • Implemented a new Taskfile for managing project tasks.
  • Development Tools

    • Added linting configuration for Go projects.
    • Introduced code generation tools for SQL and OpenAPI.
    • Enhanced build and deployment scripts.
    • Added a new GitHub Actions workflow for local testing of the Go API.
  • Performance

    • Added metrics and logging middleware for API requests.
    • Implemented event buffering for request tracking.

Copy link

changeset-bot bot commented Jan 22, 2025

⚠️ No Changeset found

Latest commit: dc5f9de

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link

vercel bot commented Jan 22, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
engineering ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 24, 2025 6:57am
play ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 24, 2025 6:57am
www ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 24, 2025 6:57am
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
dashboard ⬜️ Ignored (Inspect) Visit Preview Jan 24, 2025 6:57am

Copy link
Contributor

coderabbitai bot commented Jan 22, 2025

📝 Walkthrough

Walkthrough

This 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

File/Directory Change Summary
Taskfile.yml Added new generate-sql task for SQL generation.
apps/agent/pkg/openapi/openapi.json Modified endpoint path and operation ID for clarity.
deployment/docker-compose.yaml Added new apiv2 service configuration.
go/.golangci.yaml Introduced a comprehensive linting configuration.
go/Dockerfile Implemented a multi-stage build process for the Go application.
go/Taskfile.yml Added multiple new tasks for project management.
go/cmd/api/config.go Introduced nodeConfig struct for agent configuration.
go/cmd/api/main.go Added CLI command for managing the API.
go/cmd/main.go Defined the main entry point for the application.
go/config.docker.json Added Docker-specific configuration file.
go/config.local.json Added local configuration file.
go/go.mod Updated dependencies, adding and removing several packages.
go/pkg/api/errors/base.go Removed error handling interface and struct.
go/pkg/api/errors/not_found.go Removed NotFoundError type and associated function.
go/pkg/api/handler.go Removed handler type alias.
go/pkg/api/openapi/config.yaml Removed OpenAPI generation configuration.
go/pkg/api/openapi/gen.go Removed OpenAPI model definitions.
go/pkg/api/openapi/openapi.json Removed OpenAPI specification file.
go/pkg/api/router/router.go Removed router interface and implementation.
go/pkg/api/session/session.go Removed session management interfaces and structs.
go/pkg/api/validation/validator.go Removed OpenAPI validation interface and struct.
go/pkg/clickhouse/client.go Introduced ClickHouse client for database interactions.
go/pkg/clickhouse/flush.go Added batch flush function for ClickHouse.
go/pkg/clickhouse/interface.go Defined Bufferer interface for request buffering.
go/pkg/clickhouse/noop.go Implemented a no-operation struct for the Bufferer interface.
go/pkg/clickhouse/schema/requests.go Added request types for ClickHouse operations.
go/pkg/config/json.go Introduced functions for loading and validating configuration files.
go/pkg/config/json_test.go Added tests for configuration loading functionality.
go/pkg/ctxutil/context.go Added utility functions for managing context values.
go/pkg/database/database.go Introduced database connection utilities.
go/pkg/database/generate.go Added SQL code generation directive.
go/pkg/database/queries/get_key_by_hash.sql Added SQL query for retrieving keys by hash.
go/pkg/database/queries/insert_override.sql Added SQL command for inserting rate limit overrides.
go/pkg/database/schema.sql Defined comprehensive database schema for API management.
go/pkg/database/sqlc.json Added SQL code generation configuration.
go/pkg/fault/README.md Added documentation for the Fault package.
go/pkg/fault/doc.go Added package documentation for the Fault package.
go/pkg/fault/dst_test.go Introduced tests for error chain generation.
go/pkg/fault/tag.go Added error tagging functionality.
go/pkg/fault/tag_test.go Added tests for error tagging functions.
go/pkg/fault/wrap.go Introduced functionality for wrapping errors with context.
go/pkg/fault/wrap_test.go Added tests for error wrapping functionality.
go/pkg/fault/wrapped.go Enhanced error handling with contextual information.
go/pkg/fault/wrapped_test.go Introduced tests for wrapped error functionality.
go/pkg/logging/interface.go Defined structured logging interface.
go/pkg/logging/slog.go Implemented structured logging with slog.
go/pkg/openapi/config.yaml Added configuration for OpenAPI code generation.
go/pkg/openapi/gen.go Introduced API interaction definitions.
go/pkg/openapi/openapi.json Added new OpenAPI specification for the Unkey API.
go/pkg/openapi/spec.go Updated package name from openapi to api.
go/api/config.yaml Added configuration for OpenAPI code generation.
go/api/gen.go Introduced API handling definitions and error models.
.github/workflows/job_test_go_api_local.yaml Added GitHub Actions workflow for local testing.
.github/workflows/pr.yaml Added job for local testing in the pull request workflow.
go/pkg/clock/test_clock.go Added linting directive for TestClock struct.
go/pkg/uid/uid.go Simplified the New function for ID generation.

Sequence Diagram

sequenceDiagram
    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
Loading

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
  • 📝 Generate Docstrings (Beta)

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?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

github-actions bot commented Jan 22, 2025

Thank you for following the naming conventions for pull request titles! 🙏

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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.

  1. Good handling of both nil errors and normal errors in TestWithTag, validating that tags are properly added.
  2. 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 uses RequestIDKey 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 to GetRequestID.

-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 renaming SetRequestId to SetRequestID 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: 20
go/pkg/logging/interface.go (1)

8-15: Interface design is clean and extensible.

The Logger interface includes all requisite log levels and a fluent With 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 and NoColor 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 the WithTag 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 the tag Tag field.
Currently, the Tag 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 in New(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 the fault package in some places, in others it still falls back to fmt.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 calls GenerateJsonSchema every time LoadFile 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 with strings.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.
Since GenerateJsonSchema takes a variadic file parameter but only writes to file[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 in errors, you collect them into messages, 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 set Type in BadRequestError to https://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 sets err = &wrapped{...} unconditionally. You may want to check if err 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.
While WithDesc stores both internal and public 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 the public 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 and BufferKeyVerification 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 to 1 server-side if nil.

 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 in Identifier. 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.
The BufferApiRequest and BufferKeyVerification 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 calling db.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 invoke Handler can help others integrate it faster.

go/pkg/zen/routes/register.go (1)

10-13: Add error checks or logs when registering routes.
In case srv.RegisterRoute() or v2RatelimitLimit.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 the EventBuffer interface.
Documenting how consumers should use BufferApiRequest 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 share Services, 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 the OpenApiValidator 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.
The Route interface is well-defined, but it may be helpful to include doc comments for each method to clarify usage, expected behavior, and the role of WithMiddleware.


10-14: Maintain consistent naming and expand documentation if necessary.
The route struct is concise and captures method, path, and the handler. Consider renaming handleFn to something like handler for consistency and clarity.


32-34: Add additional checks or logging.
The call to handleFn 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.
Types Request and Response 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 of ACCESS_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., accepted Outcome strings).

go/pkg/zen/middleware_errors.go (2)

18-27: Confirm that 404 responses include sufficient context for debugging.
The NotFoundError 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 for DatabaseError 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 like NodeId and Url typically follow Go’s capitalization style as NodeID and URL. 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, the Init method always returns nil. 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: Use Set instead of Add to avoid multiple headers with the same key.
When sending JSON responses multiple times, repeatedly calling Add("content-type", "application/json") will stack the headers. Using Set 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, if LoadFile 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 the errors.Is check.
The comment on errors.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 in TestDST 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.
Setting seed := 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 the keys table has an index on hash.

go/Taskfile.yml (1)

1-22: Consider adding coverage thresholds and more targeted tasks.
It may be helpful to add a coverage threshold to the test 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:

  1. A description of the task's purpose
  2. Error handling for the case when drizzle-kit is not installed
  3. 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:

  1. A clearer introduction
  2. 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 the audit_log table:

  1. Consider using INET6 type if your MySQL version supports it
  2. Add validation for IP address format
  3. 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 the apis 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 and features JSON columns in the workspaces 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

📥 Commits

Reviewing files that changed from the base of the PR and between 4ae663f and 323d4bb.

⛔ 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 for GetTag.

  1. You cover essential scenarios: nil errors, untagged errors, tagged errors, and deeply wrapped tagged errors.
  2. 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 of slog 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 codebase

The 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 5

Length of output: 1110


Script:

#!/bin/bash
# Check Go version in go.mod
cat go/go.mod

Length 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 in interface.go. Looks good.


43-53: Method With 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 the Tag 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 in GetTag.
The iterative approach via errors.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 in Error() correctly orders messages from the oldest to the newest. This is consistent with typical user expectations for error chains.


100-102: Unwrap method correctness.
The Unwrap() method looks correct, ensuring that Go's standard error unwrapping features work seamlessly for your wrapped errors.


9-19: Validate usage references for the wrapped type.
It's a good practice to ensure that no external package directly initializes wrapped bypassing fault.New() or fault.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 the wrapped struct are contained within the fault package, confirming that external packages are using the intended fault.New() or fault.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.go

Length of output: 8184

go/pkg/config/json.go (1)

63-70: Review the use of AdditionalProperties = 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 same OpenAPIValidator instance, confirm that libopenapi-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 the opts.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 on isListening checks.
The isListening 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 calls siw.ErrorHandlerFunc. Confirm that ErrorHandlerFunc 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.
The Handler interface, coupled with the HandleFunc type, is straightforward and easy to extend with middleware.

go/pkg/clickhouse/noop.go (2)

7-9: Minimal noop struct usage looks good.
Using an unexported struct and returning it via NewNoop() 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 the Route 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.
Using v2RatelimitLimit 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 of fmt.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.
The port field has a default of 8080, which is sensible, but confirm that your CLI or config loading mechanism recognizes the default 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.
Ensuring LoadFile 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 that eventBuffer.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 ensures Wrap(nil) remains nil, 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.
The UserFacingMessage 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 whether id 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 the async field defaults to false 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.md

Length of output: 46990

go/pkg/zen/openapi/openapi.json (1)

253-253: ⚠️ Potential issue

Remove 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 the audit_log table uses varchar(256):

  1. Modern user agent strings can be longer
  2. Consider increasing the length or using TEXT type
  3. Add truncation logic in the application layer

31-37: Consider validating IP whitelist format.

The ip_whitelist column in the apis table might benefit from additional validation:

  1. Consider using a CHECK constraint or trigger to validate IP format
  2. 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 in encrypted_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/null

Length 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.

go/.golangci.yaml Outdated Show resolved Hide resolved
Comment on lines +23 to +27
//
// err := errors.New("base error")
// withTag := Tag(DATABASE_ERROR)(err)
// wrapped := fmt.Errorf("wrapped: %w", withTag)
// fmt.Println(GetTag(wrapped)) // Output: DATABASE_ERROR
Copy link
Contributor

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.

Suggested change
//
// 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/fault/wrapped.go Outdated Show resolved Hide resolved
Comment on lines 95 to 98
func (c *Clickhouse) Shutdown(ctx context.Context) error {
c.requests.Close()
return c.conn.Close()
}
Copy link
Contributor

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.

Suggested change
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()
}

Comment on lines 174 to 209
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)
}

})
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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)
}
})
}

internal/db/drizzle/meta/0000_snapshot.json Show resolved Hide resolved
internal/db/drizzle/meta/0000_snapshot.json Show resolved Hide resolved
internal/db/drizzle/meta/0000_snapshot.json Show resolved Hide resolved
go/pkg/database/schema.sql Show resolved Hide resolved
Comment on lines +253 to +254
`event` enum('verifications.usage.record','xx') NOT NULL,
`time` bigint NOT NULL,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
`event` enum('verifications.usage.record','xx') NOT NULL,
`time` bigint NOT NULL,
`event` enum('verifications.usage.record') NOT NULL,
`time` bigint NOT NULL,

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📥 Commits

Reviewing files that changed from the base of the PR and between 323d4bb and 2a936d7.

📒 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 and BaseError 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 and V1RatelimitLimitParams usage are straightforward for parameter binding. The ServerInterface and ServerInterfaceWrapper 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 upstream oapi-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)

go/api/openapi.json Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 issue

Critical: 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 cause BindBody 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 suggestion

Move 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 the nolint: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 the Clock 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:

  1. Adding environment variables for test configuration
  2. Specifying test coverage thresholds
  3. 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:

  1. Adding needs dependency if this should run after specific jobs
  2. Cleaning up the commented test_agent_integration job if it's no longer needed
   test_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 using filepath utilities from the standard library.


156-215: Add a test for tagged errors without public messages
Since you use WithTag("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 uses ResponseWriter() for header manipulation but has direct access to s.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:

  1. Adding benchmarks to measure the impact
  2. Documenting performance characteristics
  3. 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 using API_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.

  1. The max-same-issues: 50 is very high (default: 3) and might hide systematic problems.
  2. 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
        - errcheck
go/pkg/fault/dst_test.go (4)

1-5: Consider enhancing the documentation.

While the comment explains the experimental nature, it would be helpful to:

  1. Document what "DST" stands for (Differential/Dynamic Software Testing)
  2. Explain the benefits and limitations of this testing approach
  3. 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:

  1. Using a pre-generated word list for better realism
  2. Caching generated words to reduce string allocations
  3. Using strings.Builder with a pre-allocated capacity
 func (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:

  1. Making these probabilities configurable
  2. Adding documentation explaining the chosen values
  3. 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:

  1. Test with different seeds
  2. Verify error chain structure, not just string representation
  3. Add negative test cases (different seeds should produce different results)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a936d7 and dc5f9de.

📒 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 the go 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"
fi

Length 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.
The tag 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.
In New(), the provided message is assigned to the internal field rather than the public field. Verify whether this is intentional. If you intend to show the message to end users, consider using a WithDesc wrapper or storing it in the public 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 the public 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:

  1. The code references an undefined wrapped struct and getLocation() function
  2. The tag field is initialized but appears unused
  3. Consider validating the wraps parameter for nil/empty cases

Let's verify the dependencies:

✅ Verification successful

Dependencies verified, implementation is sound

The concerns have been addressed:

  1. The wrapped struct and getLocation() are properly defined in wrapped.go
  2. The tag field is an intentional part of the error wrapping mechanism
  3. The current validation for err == nil is sufficient, and the variadic wraps 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:

  1. Profiling the lint execution to identify slow linters
  2. 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 -n

Length 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.yaml

Length 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 suggestion

Enable additional critical linters.

Consider enabling these important linters for better code quality:

  1. Security:
    • errorlint: Ensures proper error wrapping (Go 1.13+)
    • noctx: Prevents HTTP requests without context
  2. Best practices:
    • goimports: Ensures consistent import formatting
    • stylecheck: Modern replacement for golint
  3. Documentation:
    • godot: Ensures consistent comment formatting

Apply these changes:

  enable:
    # existing linters...
+   - errorlint
+   - noctx
+   - goimports
+   - stylecheck
+   - godot

Likely 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) and numTestCases (10000) could lead to:

  1. Long test execution times
  2. Potential memory pressure from deep error chains
  3. 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:
Copy link
Contributor

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.

Suggested change
test_agent_local:
test_api_local:

Comment on lines +56 to +64
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
}
Copy link
Contributor

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.

Suggested change
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
}

Comment on lines +70 to +83
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
}
Copy link
Contributor

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.

Suggested change
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
}

Comment on lines +75 to +91
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,
}
}

}
Copy link
Contributor

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:

  1. The location field is set to empty string, while Wrap uses getLocation(). Consider using getLocation() here for consistency.
  2. Consider validating that internal and public strings are not empty.
  3. 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.

Suggested change
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,
}
}
}

go/cmd/api/main.go Show resolved Hide resolved
go/cmd/api/main.go Show resolved Hide resolved
go/cmd/api/main.go Show resolved Hide resolved
go/cmd/api/main.go Show resolved Hide resolved
go/.golangci.yaml Show resolved Hide resolved
go/pkg/fault/dst_test.go Show resolved Hide resolved
@chronark chronark merged commit c4c7112 into main Jan 24, 2025
28 of 30 checks passed
@chronark chronark deleted the api-v2-init branch January 24, 2025 08:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant