fix: register missing harness-config import routes#376
Conversation
The hub import screen returned HTTP 404 when importing harness-configs
because two routes were never wired up:
1. The unified `/api/v1/resources/import` endpoint handler existed but
was not registered in registerRoutes() — global-scope imports for
both templates and harness-configs were unreachable.
2. The per-project `/api/v1/projects/{id}/import-harness-configs`
endpoint had no backend route or handler (only import-templates
existed).
Add the missing route registration, implement the per-project
handleProjectImportHarnessConfigs handler, and add tests covering
global harness-config import, single-directory (leaf) import, and
per-project import.
The handleProjectImportHarnessConfigs handler was passing raw user input to importHarnessConfigsFromRemote without URL normalization, unlike the analogous template handler and the unified import endpoint which both call config.NormalizeTemplateSourceURL. This meant bare hostnames (e.g. "github.com/org/repo") would fail with a non-remote URI error.
There was a problem hiding this comment.
Code Review
This pull request introduces a new endpoint and handler for importing harness configurations directly from a remote URL or workspace path into a project's harness-config store, along with registering a unified resource import endpoint. It also includes comprehensive unit tests to verify both global and project-scoped imports. The review feedback suggests improving consistency by replacing hardcoded error code strings with predefined constants (ErrCodeUnauthorized and ErrCodeInvalidRequest) in the new handler.
| return | ||
| } | ||
| } else { | ||
| writeError(w, http.StatusUnauthorized, "unauthorized", "Authentication required", nil) |
There was a problem hiding this comment.
Use the predefined constant ErrCodeUnauthorized instead of the hardcoded string literal "unauthorized" to maintain consistency and avoid typos.
| writeError(w, http.StatusUnauthorized, "unauthorized", "Authentication required", nil) | |
| writeError(w, http.StatusUnauthorized, ErrCodeUnauthorized, "Authentication required", nil) |
|
|
||
| var req ImportHarnessConfigsRequest | ||
| if err := readJSON(r, &req); err != nil { | ||
| writeError(w, http.StatusBadRequest, "invalid_request", "Invalid request body", nil) |
There was a problem hiding this comment.
Use the predefined constant ErrCodeInvalidRequest instead of the hardcoded string literal "invalid_request" to maintain consistency and avoid typos.
| writeError(w, http.StatusBadRequest, "invalid_request", "Invalid request body", nil) | |
| writeError(w, http.StatusBadRequest, ErrCodeInvalidRequest, "Invalid request body", nil) |
Replace hardcoded "unauthorized" and "invalid_request" strings with ErrCodeUnauthorized and ErrCodeInvalidRequest constants, matching the pattern used throughout the rest of the hub handlers.
The test uses newTestStore which is defined in teststore_test.go behind a !no_sqlite build constraint. Without the same tag, go vet -tags no_sqlite fails with "undefined: newTestStore".
Summary
Fixes issue 185
/api/v1/resources/importendpoint inregisterRoutes()— it was defined but never wired up, so all global-scope resource imports (templates and harness-configs) returned 404import-harness-configssub-route inhandleProjectRouteswith a newhandleProjectImportHarnessConfigshandler, mirroring the existingimport-templatesendpointTest plan
TestHandleResourcesImport_HarnessConfigGlobal— unified endpoint withkind: harness-configandscope: globalTestHandleResourcesImport_SingleHarnessConfig— importing a single harness-config dir (leaf, not parent-of-dirs)TestHandleProjectImportHarnessConfigs— per-project endpointPOST /api/v1/projects/{id}/import-harness-configs