fix: code principles audit — correctness, security, testability

- Add rows.Err() checks after all scan loops (entities, tags, resolve)
- Surface time.Parse errors instead of silently discarding
- Extract entityRow scan helper to eliminate Get/List duplication
- Cap request body at 1MB via MaxBytesReader
- Stop leaking internal errors to API clients (log server-side only)
- Block javascript: URIs in link card open button (XSS)
- Fix all go vet failures in api_test.go (unchecked http errors)
- Add tests for display package, generateCardData, absorb-source-card
- Run go mod tidy to fix direct/indirect dep markers
This commit is contained in:
2026-05-14 17:41:30 -04:00
parent e708ea5c13
commit 6278cb1022
12 changed files with 500 additions and 104 deletions
+14 -14
View File
@@ -100,7 +100,7 @@ func listEntities(store *db.Store) http.HandlerFunc {
entities, err := store.List(p)
if err != nil {
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
@@ -151,7 +151,7 @@ func createEntity(store *db.Store) http.HandlerFunc {
}
if err := store.Create(e); err != nil {
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
@@ -168,7 +168,7 @@ func getEntity(store *db.Store) http.HandlerFunc {
writeError(w, http.StatusNotFound, "not_found", "no entity with id "+id)
return
}
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
writeJSON(w, http.StatusOK, entityToResponse(e))
@@ -215,13 +215,13 @@ func updateEntity(store *db.Store) http.HandlerFunc {
writeError(w, http.StatusNotFound, "not_found", "no entity with id "+id)
return
}
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
e, err := store.Get(id)
if err != nil {
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
writeJSON(w, http.StatusOK, entityToResponse(e))
@@ -241,7 +241,7 @@ func deleteEntity(store *db.Store) http.HandlerFunc {
writeError(w, http.StatusNotFound, "not_found", "no entity with id "+id)
return
}
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
label := "soft"
@@ -279,13 +279,13 @@ func promoteEntity(store *db.Store) http.HandlerFunc {
writeError(w, http.StatusBadRequest, "invalid_promote", "entity is already crystallized")
return
}
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
e, err := store.Get(id)
if err != nil {
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
writeJSON(w, http.StatusOK, entityToResponse(e))
@@ -305,13 +305,13 @@ func demoteEntity(store *db.Store) http.HandlerFunc {
writeError(w, http.StatusBadRequest, "invalid_demote", "entity is already fluid")
return
}
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
e, err := store.Get(id)
if err != nil {
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
writeJSON(w, http.StatusOK, entityToResponse(e))
@@ -349,13 +349,13 @@ func absorbEntity(store *db.Store) http.HandlerFunc {
writeError(w, http.StatusBadRequest, "invalid_absorb", "target is crystallized — demote first")
return
}
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
e, err := store.Get(id)
if err != nil {
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
writeJSON(w, http.StatusOK, entityToResponse(e))
@@ -371,13 +371,13 @@ func useEntity(store *db.Store) http.HandlerFunc {
writeError(w, http.StatusNotFound, "not_found", "no entity with id "+id)
return
}
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
e, err := store.Get(id)
if err != nil {
writeError(w, http.StatusInternalServerError, "internal", err.Error())
writeInternalError(w, err)
return
}
writeJSON(w, http.StatusOK, entityToResponse(e))