Skip to content

HYPERFLEET-1370 - refactor: introduce typed container for API server dependencies#309

Open
kuudori wants to merge 1 commit into
openshift-hyperfleet:mainfrom
kuudori:HYPERFLEET-1370-refactor-typed-container
Open

HYPERFLEET-1370 - refactor: introduce typed container for API server dependencies#309
kuudori wants to merge 1 commit into
openshift-hyperfleet:mainfrom
kuudori:HYPERFLEET-1370-refactor-typed-container

Conversation

@kuudori

@kuudori kuudori commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace plugin-based route registration (plugins/entities, adapterStatus, generic, resources) with a typed Container (cmd/hyperfleet-api/container) that lazily constructs and caches DAOs, services, and handlers via constructor injection
  • Refactor APIServer to take injected cfg and handler via its constructor instead of reaching into the global environments.Environment() singleton
  • Split router middleware into public (/openapi, /openapi.html, metadata) vs protected (auth + schema validation + transaction) subrouters, so public docs endpoints are never wrapped by auth/transaction middleware
  • Simplify JWTHandler to a multi-issuer, mux.MiddlewareFunc-based design, dropping the old PublicPaths/Next self-contained handler
  • Add a TODO(HYPERFLEET-1371) marking the remaining environments.Environment() callers (health_server.go, metrics_server.go) for follow-up once the environments/ package is removed

Test plan

  • make verify-all (go vet, gofmt, unit tests) passes
  • TestNewRouter_PublicVsProtectedMiddleware (new) verifies public routes bypass both apiMiddleware and protectedMiddleware, while registered routes are gated by both — confirmed it fails against the pre-fix router wiring and passes against the fix
  • TestContainerCachesDAOsAndServices updated to use BeIdenticalTo for genuine pointer-identity caching checks
  • Existing integration tests (test/integration/clusters_test.go, test/integration/openapi_test.go) continue to cover the public/protected boundary end-to-end under the default JWT-enabled config

@openshift-ci
openshift-ci Bot requested review from ldornele and tirthct July 23, 2026 14:56
@openshift-ci

openshift-ci Bot commented Jul 23, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign vkareh for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 38ef9539-01de-43ae-970e-ea97634aadf0

📥 Commits

Reviewing files that changed from the base of the PR and between 24bb5ee and b06edbb.

📒 Files selected for processing (24)
  • cmd/hyperfleet-api/container/container.go
  • cmd/hyperfleet-api/container/container_test.go
  • cmd/hyperfleet-api/main.go
  • cmd/hyperfleet-api/servecmd/cmd.go
  • cmd/hyperfleet-api/server/api_server.go
  • cmd/hyperfleet-api/server/api_server_test.go
  • cmd/hyperfleet-api/server/routes.go
  • cmd/hyperfleet-api/server/routes_entities.go
  • cmd/hyperfleet-api/server/routes_entities_test.go
  • cmd/hyperfleet-api/server/routes_test.go
  • cmd/hyperfleet-api/server/server.go
  • pkg/auth/jwt_handler.go
  • pkg/auth/jwt_handler_test.go
  • pkg/config/server.go
  • pkg/handlers/resource_handler.go
  • plugins/CLAUDE.md
  • plugins/adapterStatus/plugin.go
  • plugins/generic/plugin.go
  • plugins/resources/plugin.go
  • test/factories/clusters.go
  • test/factories/factory.go
  • test/factories/node_pools.go
  • test/helper.go
  • test/integration/resource_helpers.go
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • openshift-hyperfleet/architecture (manual)
  • openshift-hyperfleet/hyperfleet-api (manual)
  • openshift-hyperfleet/hyperfleet-sentinel (manual)
  • openshift-hyperfleet/hyperfleet-adapter (manual)
  • openshift-hyperfleet/hyperfleet-broker (manual)
💤 Files with no reviewable changes (5)
  • cmd/hyperfleet-api/main.go
  • plugins/CLAUDE.md
  • plugins/generic/plugin.go
  • plugins/resources/plugin.go
  • plugins/adapterStatus/plugin.go
🚧 Files skipped from review as they are similar to previous changes (18)
  • cmd/hyperfleet-api/server/routes_entities_test.go
  • cmd/hyperfleet-api/server/server.go
  • cmd/hyperfleet-api/server/routes_test.go
  • test/integration/resource_helpers.go
  • test/factories/node_pools.go
  • cmd/hyperfleet-api/server/api_server_test.go
  • pkg/handlers/resource_handler.go
  • test/factories/factory.go
  • cmd/hyperfleet-api/servecmd/cmd.go
  • pkg/config/server.go
  • cmd/hyperfleet-api/server/routes.go
  • cmd/hyperfleet-api/container/container_test.go
  • test/factories/clusters.go
  • cmd/hyperfleet-api/container/container.go
  • cmd/hyperfleet-api/server/api_server.go
  • pkg/auth/jwt_handler.go
  • test/helper.go
  • pkg/auth/jwt_handler_test.go

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added centralized API server setup with configurable HTTP timeouts and TLS support.
    • Added explicit route registration for entity and OpenAPI endpoints.
    • Added middleware-based authentication for protected API routes.
  • Bug Fixes
    • Improved server startup and shutdown resource handling.
    • Improved error reporting for invalid route and OpenAPI configuration.
  • Tests
    • Added coverage for HTTP/TLS serving, authentication middleware, routing, and lazy initialization.

Walkthrough

The API now centralizes lazy DAO, service, JWT, schema-validator, and server construction in a dependency container. Server configuration is injected, routing uses explicit registrars and middleware chains, and JWT validation is exposed as middleware. Application and integration-test startup obtain shared services and servers from the container, while plugin-based service registration is removed.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ServeCommand
  participant Container
  participant Router
  participant APIServer
  participant Client
  ServeCommand->>Container: create with session factory
  ServeCommand->>Container: request API server
  Container->>Router: build with middleware and registrars
  Router-->>Container: return configured router
  Container->>APIServer: inject configuration and router
  Client->>APIServer: send HTTP or HTTPS request
  APIServer-->>Client: return response
Loading

Suggested reviewers: ldornele, tirthct

🚥 Pre-merge checks | ✅ 9 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.68% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
No Pii Or Sensitive Data In Logs ⚠️ Warning CWE-532/200: pkg/auth/jwt_handler.go logs unredacted JWKS url/ca_file; url isn’t masked by default, so internal endpoint data can leak. Redact or omit jwkURL/caFile in logs, or add masking for url and confirm error paths never echo full endpoints or paths.
✅ Passed checks (9 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: introducing a typed container for API server dependencies.
Description check ✅ Passed The description aligns with the refactor and test coverage changes in the diff.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Sec-02: Secrets In Log Output ✅ Passed No non-test log statements include token/password/credential/secret; the only token text is a handleError reason, not a log call. CWE-532
No Hardcoded Secrets ✅ Passed No CWE-798 finding: touched production code has no hardcoded credentials; remaining PEM/HMAC literals are confined to test fixtures and are exempt.
No Weak Cryptography ✅ Passed No md5/des/rc4/SHA1/ECB or secret/HMAC compares in touched files; JWT uses RS256 and TLS 1.2+, so no CWE-327/CWE-208 issue.
No Injection Vectors ✅ Passed PASS: No new CWE-89/78/79/502 sinks in non-test changes; no exec.Command, template.HTML, yaml.Unmarshal, or SQL query string-concat added.
No Privileged Containers ✅ Passed No changed manifests/templates/Dockerfiles contain privileged:true, hostNetwork/PID/IPC, allowPrivilegeEscalation, SYS_ADMIN, or root USER/runAsUser (CWE-250/269).
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Comment @coderabbitai help to get the list of available commands.

@hyperfleet-ci-bot

hyperfleet-ci-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown

Risk Score: 5 — risk/high

Signal Detail Points
PR size 1323 lines (>500) +2
Sensitive paths cmd/ +2
Test coverage Missing tests for: cmd/hyperfleet-api cmd/hyperfleet-api/servecmd pkg/config pkg/handlers plugins/adapterStatus plugins/generic plugins/resources test test/factories test/integration +1

Computed by hyperfleet-risk-scorer

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
cmd/hyperfleet-api/server/api_server_test.go (1)

111-115: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

InsecureSkipVerify disables cert-chain/hostname validation (CWE-295).

Flagged by both OpenGrep and ast-grep. You already generate the self-signed cert in writeSelfSignedCert — build an x509.CertPool from it and set RootCAs instead of skipping verification entirely, and add MinVersion: tls.VersionTLS13.

🔒 Proposed fix
+	certPool := x509.NewCertPool()
+	certPEM, err := os.ReadFile(certFile)
+	Expect(err).NotTo(HaveOccurred())
+	Expect(certPool.AppendCertsFromPEM(certPEM)).To(BeTrue())
+
 	client := &http.Client{
 		Transport: &http.Transport{
-			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+			TLSClientConfig: &tls.Config{RootCAs: certPool, MinVersion: tls.VersionTLS13},
 		},
 	}
🤖 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/hyperfleet-api/server/api_server_test.go` around lines 111 - 115, Update
the HTTP client TLS configuration in the test to avoid InsecureSkipVerify: build
an x509.CertPool from the certificate generated by writeSelfSignedCert, assign
it to RootCAs, and set MinVersion to tls.VersionTLS13 while preserving trusted
self-signed certificate validation.

Source: Linters/SAST tools

pkg/auth/jwt_handler.go (1)

106-155: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Middleware is near the QUAL-03 branching/length threshold.

5+ distinct branch points (empty header, non-Bearer scheme, parse failure w/ expired precedence, terminal expired/invalid, no-credentials) in one closure. Extract the per-validator match loop into a helper (e.g. matchValidator(r *http.Request) (*jwt.Token, config.JWTIssuerConfig, error, bool)) returning either a matched token or the sticky "expired" error, keeping Middleware itself as thin dispatch + handleError calls.

As per path instructions, "Functions >50 lines or >5 branching paths — flag for decomposition."

🤖 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 `@pkg/auth/jwt_handler.go` around lines 106 - 155, Decompose the validator
iteration from JWTHandler.Middleware into a helper such as matchValidator that
evaluates headers and parsers, returns the matched token and issuer
configuration, or the sticky expired/validation error plus whether a non-Bearer
header was seen. Keep Middleware focused on invoking the helper, dispatching
successful requests, and preserving the existing handleError behavior and error
precedence.

Source: Path instructions

🤖 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/hyperfleet-api/server/routes.go`:
- Around line 48-54: Make authentication outermost on protected routes: in
cmd/hyperfleet-api/server/routes.go:48-54, register protectedMiddleware before
apiMiddleware so JWT and caller identity run before schema validation or
db.TransactionMiddleware. In cmd/hyperfleet-api/container/container.go:163-180,
adjust the middleware grouping consistently so transaction/schema middleware is
excluded from unauthenticated paths while authenticated requests still reach
db.TransactionMiddleware.

In `@test/integration/resource_helpers.go`:
- Line 15: Update the integration setup around test.RegisterIntegration(t) to
preserve and check its returned error before dereferencing h.Container. Fail the
test immediately with the original error when registration fails, then continue
to ResourceService only for a successful registration; ensure all error returns
in this setup are checked.

---

Nitpick comments:
In `@cmd/hyperfleet-api/server/api_server_test.go`:
- Around line 111-115: Update the HTTP client TLS configuration in the test to
avoid InsecureSkipVerify: build an x509.CertPool from the certificate generated
by writeSelfSignedCert, assign it to RootCAs, and set MinVersion to
tls.VersionTLS13 while preserving trusted self-signed certificate validation.

In `@pkg/auth/jwt_handler.go`:
- Around line 106-155: Decompose the validator iteration from
JWTHandler.Middleware into a helper such as matchValidator that evaluates
headers and parsers, returns the matched token and issuer configuration, or the
sticky expired/validation error plus whether a non-Bearer header was seen. Keep
Middleware focused on invoking the helper, dispatching successful requests, and
preserving the existing handleError behavior and error precedence.
🪄 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: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 63920e6b-ce80-41f8-aa45-a382cb43ee94

📥 Commits

Reviewing files that changed from the base of the PR and between 913cd01 and 24bb5ee.

📒 Files selected for processing (24)
  • cmd/hyperfleet-api/container/container.go
  • cmd/hyperfleet-api/container/container_test.go
  • cmd/hyperfleet-api/main.go
  • cmd/hyperfleet-api/servecmd/cmd.go
  • cmd/hyperfleet-api/server/api_server.go
  • cmd/hyperfleet-api/server/api_server_test.go
  • cmd/hyperfleet-api/server/routes.go
  • cmd/hyperfleet-api/server/routes_entities.go
  • cmd/hyperfleet-api/server/routes_entities_test.go
  • cmd/hyperfleet-api/server/routes_test.go
  • cmd/hyperfleet-api/server/server.go
  • pkg/auth/jwt_handler.go
  • pkg/auth/jwt_handler_test.go
  • pkg/config/server.go
  • pkg/handlers/resource_handler.go
  • plugins/CLAUDE.md
  • plugins/adapterStatus/plugin.go
  • plugins/generic/plugin.go
  • plugins/resources/plugin.go
  • test/factories/clusters.go
  • test/factories/factory.go
  • test/factories/node_pools.go
  • test/helper.go
  • test/integration/resource_helpers.go
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • openshift-hyperfleet/architecture (manual)
  • openshift-hyperfleet/hyperfleet-api (manual)
  • openshift-hyperfleet/hyperfleet-sentinel (manual)
  • openshift-hyperfleet/hyperfleet-adapter (manual)
  • openshift-hyperfleet/hyperfleet-broker (manual)
💤 Files with no reviewable changes (5)
  • plugins/CLAUDE.md
  • plugins/resources/plugin.go
  • plugins/generic/plugin.go
  • plugins/adapterStatus/plugin.go
  • cmd/hyperfleet-api/main.go

Comment thread cmd/hyperfleet-api/server/routes.go
Comment thread test/integration/resource_helpers.go
…dependencies

Replace the plugin-based route registration (plugins/entities,
adapterStatus, generic, resources) with a typed Container
(cmd/hyperfleet-api/container) that lazily constructs and caches DAOs,
services, and handlers via constructor injection instead of a global
environments singleton.

- Add Container with lazy-cached DAO/service/handler accessors and an
  APIServer(tracingEnabled) builder
- Move entity route registration into cmd/hyperfleet-api/server
  (routes_entities.go, renamed from plugins/entities/plugin.go)
- Refactor APIServer to take injected cfg and handler via its
  constructor rather than reaching into environments.Environment()
- Split router middleware into public (metadata/openapi) vs protected
  (auth + transaction) subrouters so JWT, schema-validation, and
  transaction middleware never wrap the public docs endpoints
- Simplify JWTHandler to a multi-issuer, mux.MiddlewareFunc-based
  design, dropping the old PublicPaths/Next self-contained handler
- Add unit coverage: container_test.go, api_server_test.go, and
  routes_test.go (asserts public routes bypass middleware while
  protected routes are gated by it)
@kuudori
kuudori force-pushed the HYPERFLEET-1370-refactor-typed-container branch from 24bb5ee to b06edbb Compare July 23, 2026 16:04
@Ruclo

Ruclo commented Jul 24, 2026

Copy link
Copy Markdown

@kuudori The container abstraction is nice but wouldn't it make more sense to have it store only the dependencies ? so without APIServer, JWTHandler and SchemaValidator ? The APIServer could be created somewhere in cmd/hyperfleet-api/server/. What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants