Add validate input --server flag for persistent HTTP/REST#3386
Add validate input --server flag for persistent HTTP/REST#3386simonbaird wants to merge 18 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds persistent HTTP server mode for ChangesValidate Input Server Mode
Estimated code review effort: 4 (Complex) | ~60 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Add --server and --server-port flags to `ec validate input` that start a persistent HTTP server instead of running a one-shot evaluation. Policies are loaded once at startup via pre-created evaluators. The server shuts down gracefully on context cancellation. Health endpoints /live and /ready support Kubernetes-style probes. Ref: https://redhat.atlassian.net/browse/EC-1883 Ref: https://redhat.atlassian.net/browse/EC-1886 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add POST /v1/validate/input endpoint that accepts JSON or YAML input, evaluates it against pre-loaded policies, and returns the same JSON report structure as `--output json`. Includes Content-Type detection, 10MB body size limit, structured JSON error responses, and panic recovery middleware. Ref: https://redhat.atlassian.net/browse/EC-1884 Ref: https://redhat.atlassian.net/browse/EC-1887 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add request logging middleware that logs method, path, status code, latency, and remote address for every request. Switch to JSON log format in server mode for log aggregation in containerized environments. Log server lifecycle events (startup config, policy loading, shutdown). Ref: https://redhat.atlassian.net/browse/EC-1908 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Test health endpoints (/live, /ready), evaluation endpoint (success, violations, errors, YAML input, empty body, invalid input), recovery middleware, and server lifecycle (start, request handling, shutdown). Uses mock evaluators and stub policy for isolation. Ref: https://redhat.atlassian.net/browse/EC-1888 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update CLI help text to describe server mode, available endpoints, request/response format, and configuration options. Add usage examples for starting the server and sending evaluation requests with curl. Ref: https://redhat.atlassian.net/browse/EC-1889 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The way the http service is tested is to start, access, then stop the http service synchronously, rather than have a persistent http service running in a container. Ref: https://redhat.atlassian.net/browse/EC-1888 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
f38bff3 to
f00abb9
Compare
Codecov Report❌ Patch coverage is
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (1)
docs/modules/ROOT/pages/ec_validate_input.adoc (1)
12-22: 🔒 Security & Privacy | 🔵 TrivialConsider documenting network exposure/security guidance for server mode.
The server binds on all interfaces (
:<port>) with no authentication (perinternal/server/server.go). Given this is now a persistent network-facing service, docs could note that it should be run behind a firewall/reverse proxy or restricted to trusted networks.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/modules/ROOT/pages/ec_validate_input.adoc` around lines 12 - 22, Update the server-mode documentation in ec_validate_input.adoc to add a brief security note that the persistent HTTP server started by --server binds on all interfaces and has no authentication. Mention that users should run it behind a firewall or reverse proxy, or restrict it to trusted networks, and place this guidance near the existing endpoint/server-mode description so it is easy to find.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cmd/validate/input.go`:
- Around line 146-159: The `--workers` option is currently ignored when
`data.serverMode` is true because `server.New(server.Config{...})` does not use
`Config.Workers`. Update the server path by either plumbing `data.workers`
through `internal/server` and consuming it in the relevant server code, or
remove/hide the flag from server mode so `cmd/validate/input.go` and
`server.Config` do not expose a misleading no-op setting.
- Around line 146-162: Pass a signal-aware context from the root command so
server shutdown can observe cancellation on SIGINT/SIGTERM. Update the root
execution path in cmd/root.go to use a context tied to OS signals instead of
context.Background(), and ensure validate/input.go’s server.New/srv.Start path
continues to consume cmd.Context() so srv.Start can react to ctx.Done() and exit
gracefully.
In `@internal/server/handler.go`:
- Around line 81-84: The evaluation and report build failure paths in handler
logic are leaking raw internal error text to API clients. Keep the detailed
error in server-side logging via the existing log.WithField("error", err) calls
in the handler flow, but change the client-facing responses in the evaluation
and report-build branches to return a generic message instead of fmt.Sprintf
with %v. Update the relevant error handling in the handler method that writes
responses so both failure cases use safe, non-internal text.
- Around line 149-159: The isValidInput helper currently skips validation for
explicit YAML content types, so malformed YAML can slip through and fail later
as a server error. Update isValidInput to validate application/yaml,
application/x-yaml, and text/yaml with utils.IsYamlMap instead of returning
true, and keep the existing JSON parsing behavior for application/json and the
default fallback. Since inputExtension uses the same content-type switch,
consider centralizing the YAML/JSON content-type handling there to avoid
divergence between the two helpers.
- Around line 78-87: Add a timeout around the evaluation flow in
handleValidateInput, since the request context is passed directly into each
evaluator and a slow run can hang the handler. Create a derived context with
context.WithTimeout before the loop that calls e.Evaluate, use that context for
every evaluator invocation, and cancel it when finished. Keep the existing error
handling and logging in the evaluator loop unchanged, but ensure the new
deadline applies to the entire evaluation sequence.
In `@internal/server/server.go`:
- Around line 35-43: The Config.Workers field is currently unused, so request
validation still runs with unbounded concurrency. Update Server to use Workers
as a concurrency limit by adding a semaphore (or equivalent limiter) in the
request path, wiring it through New/Start and enforcing it inside
handleValidateInput before policy evaluation begins. If you do not intend to
bound concurrency, remove Workers from Config and any related setup so the API
stays consistent.
- Around line 83-87: `httpServer` in the server startup setup only sets
`ReadHeaderTimeout`, so add explicit `ReadTimeout`, `WriteTimeout`, and
`IdleTimeout` on the `http.Server` configuration to bound slow client
connections. Update the `http.Server` initialization in the code path that
builds the listener for `handler`, keeping the existing `Addr` and
`ReadHeaderTimeout` values, and choose sensible timeout values consistent with
the service’s expected request/response behavior.
---
Nitpick comments:
In `@docs/modules/ROOT/pages/ec_validate_input.adoc`:
- Around line 12-22: Update the server-mode documentation in
ec_validate_input.adoc to add a brief security note that the persistent HTTP
server started by --server binds on all interfaces and has no authentication.
Mention that users should run it behind a firewall or reverse proxy, or restrict
it to trusted networks, and place this guidance near the existing
endpoint/server-mode description so it is easy to find.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Enterprise
Run ID: 1c1eb87d-d23f-4ada-87fa-e76939c91a9a
⛔ Files ignored due to path filters (1)
features/__snapshots__/validate_input_server.snapis excluded by!**/*.snap
📒 Files selected for processing (9)
acceptance/acceptance_test.goacceptance/cli/server.gocmd/validate/input.godocs/modules/ROOT/pages/ec_validate_input.adocfeatures/validate_input_server.featureinternal/server/handler.gointernal/server/middleware.gointernal/server/server.gointernal/server/server_test.go
The --workers flag was being passed to server.Config but never consumed by the server package. The flag continues to work in CLI mode where the worker pool actually uses it. Ref: https://redhat.atlassian.net/browse/EC-1883 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
A slow evaluator could hang the handler indefinitely since the request context had no deadline. Wrap the evaluation loop in a 90-second timeout and add a test that verifies the handler returns an error when exceeded. Ref: https://redhat.atlassian.net/browse/EC-1883 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously isValidInput returned true for YAML content types without checking the body, so malformed YAML would pass validation and fail later with a 500. Now it validates with IsYamlMap, consistent with the default fallback branch and the rest of the codebase. Ref: https://redhat.atlassian.net/browse/EC-1884 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only ReadHeaderTimeout was set, leaving the server vulnerable to slow client connections. Added ReadTimeout (30s), WriteTimeout (120s to cover the 90s evaluation timeout), and IdleTimeout (60s). Ref: https://redhat.atlassian.net/browse/EC-1883 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace http.Get/http.Post with http.NewRequestWithContext and http.DefaultClient.Do to satisfy the linter and propagate context. Ref: https://redhat.atlassian.net/browse/EC-1888 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The root command passed context.Background() which is never cancelled, so SIGINT/SIGTERM could not propagate to the server's ctx.Done() select. Use signal.NotifyContext to tie the root context to OS signals. Ref: https://redhat.atlassian.net/browse/EC-1883 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The evaluation and report-build error paths were passing raw error text to the client via fmt.Sprintf. Return generic messages instead, with a distinct "evaluation timed out" for deadline exceeded. Full details are still logged server-side. Ref: https://redhat.atlassian.net/browse/EC-1887 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover the --server and --file mutual exclusion check and the full server startup path (flag reads, Config construction, srv.Start) using a cancelled context for clean shutdown. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
🤖 Finished Review · ✅ Success · Started 11:15 AM UTC · Completed 11:21 AM UTC |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
cmd/validate/input_test.go (1)
312-325: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winFixed sleep risks flakiness and the assertion is too weak to validate graceful shutdown.
The 100ms sleep before
cancel()is a fixed race window; under CI load, PreRunE/server startup may not have progressed enough, making the test pass without actually exercising the server path. Also, whenerr == nilthe test asserts nothing — it can't confirm the server actually started and then shut down cleanly on context cancellation (which is also the scenario flagged incmd/root.goaround theExecute()fatal-error path). Consider synchronizing on an actual readiness signal instead of a sleep, and assertingrequire.NoError(t, err)for the graceful-shutdown case once ctx-cancellation is confirmed to return nil.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmd/validate/input_test.go` around lines 312 - 325, The test in validateCmd.Execute relies on a fixed time.Sleep before canceling, which makes the server-path check flaky and non-deterministic. Replace that timing-based pause with a real readiness/synchronization signal from the server startup path (for example in the PreRunE/server startup flow) so the test only cancels after the server is actually running. Then strengthen the assertion in the graceful-shutdown case by requiring a nil error after context cancellation, and keep the existing flag-validation negative checks only for the error path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@cmd/validate/input_test.go`:
- Around line 312-325: The test in validateCmd.Execute relies on a fixed
time.Sleep before canceling, which makes the server-path check flaky and
non-deterministic. Replace that timing-based pause with a real
readiness/synchronization signal from the server startup path (for example in
the PreRunE/server startup flow) so the test only cancels after the server is
actually running. Then strengthen the assertion in the graceful-shutdown case by
requiring a nil error after context cancellation, and keep the existing
flag-validation negative checks only for the error path.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Enterprise
Run ID: 44a54a24-52ab-41d0-9626-d0380a433d6d
📒 Files selected for processing (7)
acceptance/cli/server.gocmd/root.gocmd/validate/input.gocmd/validate/input_test.gointernal/server/handler.gointernal/server/server.gointernal/server/server_test.go
💤 Files with no reviewable changes (1)
- cmd/validate/input.go
🚧 Files skipped from review as they are similar to previous changes (4)
- acceptance/cli/server.go
- internal/server/handler.go
- internal/server/server_test.go
- internal/server/server.go
Review —
|
The comment previously said "Download all sources" which suggests I/O on every call. Updated to explain that getPolicyThroughCache with sync.OnceValues ensures only the first call per source URL downloads. Ref: https://redhat.atlassian.net/browse/EC-1884 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Explain why reusing evaluators across requests is safe: shared directories are read-only after initial download, and each request gets its own conftest runner and input file. Ref: https://redhat.atlassian.net/browse/EC-1884 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
I don't think it's important enough to worry about now, but let's make a note for later. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
As mentioned, it might be a concern if the web service was embedded in something else. Let's make a note about it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Last change is adding explanatory comments to address the potential concerns. |
|
🤖 Finished Review · ✅ Success · Started 3:40 PM UTC · Completed 3:45 PM UTC |
This adds an
ec validate input --servercommand that starts up a web service that responds on/v1/validate/inputwith the results the same as if you ranec validate input --output jsonwith the request body as the input fileRef: https://redhat.atlassian.net/browse/EC-1882