- SUMMARY.md: 2 tasks, 2 commits, threat mitigations T-05-03/04/05 applied - Deviation: go-netbox Cable model required url/display fields in test mock
6.5 KiB
6.5 KiB
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 05-cable-test-integration | 02 | netbox-client, api-handlers, router |
|
|
|
|
|
|
Phase 05 Plan 02: NetBox CreateCable + TestHandler + 3 Endpoints Summary
One-liner: NetBox cable creation via DcimCablesCreate with test_data/catalog_status custom fields, plus TestHandler providing SSE live readings, 20-item ring buffer, and auto-print with 1s rate limit on three /api/test/* routes.
Tasks Completed
| Task | Name | Commit | Files |
|---|---|---|---|
| 1 | NetBox CreateCable method + CableRecord type | 7908d40 |
internal/netbox/client.go, types.go, client_test.go |
| 2 | TestHandler (3 endpoints) + router wiring + main.go init | 1764c7b |
handlers/test.go, test_test.go, router.go, main.go |
What Was Built
Task 1: CreateCable + CableRecord
CableRecordtype added tointernal/netbox/types.gowith ID, HWID, Label, TestData (raw JSON), CatalogStatus fieldsCreateCable(ctx, label, assetTag, testDataJSON string) (int64, error)on*netbox.Client- Uses
nb.NewWritableCableRequest()→DcimCablesCreate(mirrorsCreateDevicepattern) - Sets
test_dataandcatalog_status: "complete"custom fields;hw_idif assetTag non-empty - Rejects empty label with sentinel error
"cable label must not be empty" - Unit tests: empty label rejection, 201 success (httptest mock with required
url/displayfields), 422 error
Task 2: TestHandler + Router + main.go
TestHandlerstruct withTestNetBoxClientandTestPrinterinterfaces for injectionPOST /api/test/cable: decodes JSON withDisallowUnknownFields(T-05-03), derives label viaderiveCableLabel, callsCreateCable, attempts auto-print with 1s cooldown (T-05-05), prepends to 20-item ring buffer, returns{hw_id, netbox_id, print_skipped}GET /api/test/events: SSE withContent-Type: text/event-stream, 30s keepalive ticker, exits onr.Context().Done()(T-05-04 goroutine-leak-safe)GET /api/test/recent: mutex-locked copy of ring buffer, returns[]when emptyAttachStream(ch <-chan tester.LiveReading): fans in from driver channel to internal buffered channel- Router:
NewRoutersignature extended with*handlers.TestHandler, three routes registered - main.go:
testHandlerconstructed withnbClient+mockDriver; USB Manager goroutine wired (stub logsRoleCableTesterconnect events)
Verification
go build ./... PASS
go test ./internal/netbox/... -run TestCreateCable -v 3/3 PASS
go test ./internal/api/handlers/... -race -v 7/7 PASS (TestTestHandler_*)
go test ./... -race All packages PASS
Threat Mitigations Applied
| Threat ID | Mitigation | Implementation |
|---|---|---|
| T-05-03 | Tampering — JSON body | json.NewDecoder(...).DisallowUnknownFields() on POST /api/test/cable |
| T-05-04 | DoS — SSE goroutine leak | select on r.Context().Done() in StreamEvents |
| T-05-05 | DoS — runaway print calls | 1s printCooldown in TestHandler, same pattern as LabelHandler |
Deviations from Plan
Auto-fixed Issues
1. [Rule 1 - Bug] go-netbox Cable response model requires url and display fields
- Found during: Task 1, GREEN phase —
TestCreateCable_Successfailed with "no value given for required property url" - Issue: The
Cableresponse model (generated from NetBox OpenAPI spec) validates required propertiesid,url,displayduring JSON unmarshal. Mock returning only{id, label}triggered validation error. - Fix: Updated mock to return
urlanddisplayfields; switched tohttptest.NewUnstartedServersosrv.URLis capturable for a realistic URL value in the response. - Files modified:
internal/netbox/client_test.go - Commit:
7908d40
Known Stubs
main.goUSB Manager goroutine forRoleCableTester: logs connection event, does NOT construct a real tester driver or callAttachStream. Comment marks theTODO(hardware)for Phase 5 hardware integration. This does not prevent the plan's goal —AttachStreamis wired and tested; hardware arrival is the blocker.
Threat Flags
None — no new network endpoints, auth paths, or file access patterns beyond those specified in the plan's threat model.
Self-Check: PASSED
internal/netbox/client.go— CreateCable method existsinternal/netbox/types.go— CableRecord type existsinternal/netbox/client_test.go— 3 CreateCable unit testsinternal/api/handlers/test.go— TestHandler with 3 endpointsinternal/api/handlers/test_test.go— 7 test casesinternal/api/router.go— NewRouter has testHandler param, 3 routescmd/hwlab/main.go— testHandler constructed and passed to NewRouter- Commit
7908d40exists (Task 1) - Commit
1764c7bexists (Task 2) go build ./...passesgo test ./... -raceall pass