fix: add golangci config, restore CI timeouts, svelte-check warnings, RespondError helper
CI / Env docs check (push) Successful in 13s
CI / Nginx config check (push) Successful in 36s
CI / Frontend major deps (push) Successful in 37s
CI / Docker compose check (push) Successful in 38s
CI / Frontend deps check (push) Successful in 41s
CI / Secrets scan (push) Successful in 42s
CI / Go build (push) Successful in 42s
CI / Frontend build (push) Successful in 49s
CI / go mod tidy (push) Successful in 26s
CI / Go vet (dev) (push) Has been cancelled
CI / Go vet (prod) (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
CI / Staticcheck (dev) (push) Has been cancelled
CI / Staticcheck (prod) (push) Has been cancelled
CI / Security scan (dev) (push) Has been cancelled
CI / Security scan (prod) (push) Has been cancelled
CI / Tests (prod) (push) Has been cancelled
CI / Tests (dev) (push) Has been cancelled
CI / Race (prod) (push) Has been cancelled
CI / Race (dev) (push) Has been cancelled
CI / Go vulnerabilities (push) Has been cancelled
CI / Knip (push) Has been cancelled
CI / Frontend a11y check (push) Has been cancelled
CI / Svelte strict check (push) Has been cancelled
CI / Frontend QC (audit) (push) Has been cancelled
CI / Frontend QC (typecheck) (push) Has been cancelled
CI / Frontend QC (lint) (push) Has been cancelled

This commit is contained in:
2026-07-11 17:38:50 +01:00
parent b864873310
commit 8ae592d0c5
5 changed files with 120 additions and 52 deletions
+65 -43
View File
@@ -28,8 +28,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- uses: actions/setup-go@v5
with:
@@ -86,8 +87,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Build
run: go build ./...
@@ -120,8 +122,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Vet (dev tags)
run: go vet -tags "test,dev" ./...
@@ -154,8 +157,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Vet (prod tags)
run: go vet -tags "test,!dev" ./...
@@ -188,8 +192,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: golangci-lint
run: |
@@ -224,8 +229,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Staticcheck (dev tags)
run: |
@@ -260,8 +266,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Staticcheck (prod tags)
run: |
@@ -296,8 +303,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: gosec (dev tags)
run: |
@@ -332,8 +340,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: gosec (prod tags)
run: |
@@ -368,8 +377,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: go mod tidy check
run: |
@@ -381,6 +391,7 @@ jobs:
working-directory: backend
test:
timeout-minutes: 30
name: Tests (${{ matrix.label }})
needs: [secrets-scan, go-vet-dev, go-vet-prod, go-lint, go-staticcheck-dev, go-staticcheck-prod, go-gosec-dev, go-gosec-prod, go-mod-tidy, vulns]
runs-on: ubuntu-latest
@@ -431,8 +442,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Install psql client
run: apk add --no-cache postgresql-client
@@ -449,7 +461,7 @@ jobs:
- name: Run tests
working-directory: backend
run: go test -tags "${{ matrix.gotags }}" -count=1 -timeout 1800s ${{ matrix.verbose }} ${{ matrix.coverflags }} ./...
run: go test -tags "${{ matrix.gotags }}" -count=1 -timeout 120s ${{ matrix.verbose }} ${{ matrix.coverflags }} ./...
env:
GO_TESTING: "1"
DAV_SKIP_INIT: "1"
@@ -473,7 +485,7 @@ jobs:
run: |
if [ -f coverage.out ]; then
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
if (( $(echo "$COVERAGE < 60" | bc -l) )); then
if awk "BEGIN {exit !($COVERAGE < 60)}"; then
echo "FAIL: Coverage $COVERAGE% is below 60% minimum"
exit 1
fi
@@ -489,6 +501,7 @@ jobs:
fi
race:
timeout-minutes: 30
name: Race (${{ matrix.label }})
needs: [secrets-scan, go-vet-dev, go-vet-prod, go-lint, go-staticcheck-dev, go-staticcheck-prod, go-gosec-dev, go-gosec-prod, go-mod-tidy, vulns]
runs-on: ubuntu-latest
@@ -535,8 +548,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Install psql + build-base
run: apk add --no-cache postgresql-client build-base
@@ -553,7 +567,7 @@ jobs:
- name: Run race detector
working-directory: backend
run: go test -tags "${{ matrix.gotags }}" -race -count=1 -timeout 1800s ./...
run: go test -tags "${{ matrix.gotags }}" -race -count=1 -timeout 480s ./...
env:
GO_TESTING: "1"
DAV_SKIP_INIT: "1"
@@ -588,8 +602,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Go vulnerability scan
working-directory: backend
@@ -608,8 +623,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Cache npm dependencies
uses: actions/cache@v4
@@ -698,8 +714,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Restore npm dependencies
uses: actions/cache@v4
@@ -750,8 +767,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Restore npm dependencies
uses: actions/cache@v4
@@ -781,8 +799,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Restore npm dependencies
uses: actions/cache@v4
@@ -811,8 +830,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Cache npm dependencies
uses: actions/cache@v4
@@ -842,8 +862,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Restore npm dependencies
uses: actions/cache@v4
@@ -885,8 +906,9 @@ jobs:
- name: Fix node toolcache path for Post-step cleanup
run: |
mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin
ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node
NODE_MAJOR=$(node -e "console.log(process.version.slice(1).split('.')[0])")
mkdir -p /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin
ln -sf $(which node) /opt/hostedtoolcache/node/${NODE_MAJOR}.0.0/x64/bin/node
- name: Restore npm dependencies
uses: actions/cache@v4
+38
View File
@@ -0,0 +1,38 @@
linters:
enable:
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- unused
- gosec
- gocritic
disable:
- exhaustruct
- nlreturn
- wsl
- wrapcheck
linters-settings:
errcheck:
exclude-functions:
- encoding/json.Encoder.Encode
- io.WriteString
- (io.Closer).Close
issues:
exclude-rules:
- path: _test\.go
linters:
- errcheck
- gosec
- path: handlers/testutils/
linters:
- gosec
- path: internal/square/square_dev.go
linters:
- errcheck
run:
timeout: 5m
+8 -8
View File
@@ -86,7 +86,7 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) {
// Must accept terms
if !req.AgreedToPolicy {
http.Error(w, "must agree to terms", http.StatusBadRequest)
mw.RespondError(w, http.StatusBadRequest, "must agree to terms")
return
}
@@ -105,11 +105,11 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) {
// Password must not exceed bcrypt's 72-byte limit
if len(req.Password) > 72 {
http.Error(w, "password must be 72 characters or less", http.StatusBadRequest)
mw.RespondError(w, http.StatusBadRequest, "password must be 72 characters or less")
return
}
if len(req.Password) < 6 {
http.Error(w, "password must be at least 6 characters", http.StatusBadRequest)
mw.RespondError(w, http.StatusBadRequest, "password must be at least 6 characters")
return
}
// Server-side password strength check using the same @zxcvbn-ts/core as the frontend
@@ -353,13 +353,13 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
loginStateMu.Lock()
if t, ok := loginInProgress[userID]; ok && time.Since(t) < 30*time.Second {
loginStateMu.Unlock()
http.Error(w, "login already in progress", http.StatusConflict) // 409
mw.RespondError(w, http.StatusConflict, "login already in progress")
return
}
// Cap the map size - drop new request if at capacity
if len(loginInProgress) >= maxLoginInProgress {
loginStateMu.Unlock()
http.Error(w, "server busy, try again later", http.StatusTooManyRequests)
mw.RespondError(w, http.StatusTooManyRequests, "server busy, try again later")
return
}
loginInProgress[userID] = clock.Now()
@@ -429,7 +429,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
tx, err := db.Conn.Begin(r.Context())
if err != nil {
log.Printf("Failed to begin transaction: %v", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
mw.RespondError(w, http.StatusInternalServerError, "internal server error")
return
}
defer func() {
@@ -497,7 +497,7 @@ func RefreshTokenHandler(w http.ResponseWriter, r *http.Request) {
// Generate new token
newToken, jti, err := auth.GenerateToken(userID, currentRole)
if err != nil {
http.Error(w, "could not generate token", http.StatusInternalServerError)
mw.RespondError(w, http.StatusInternalServerError, "could not generate token")
return
}
@@ -518,7 +518,7 @@ func LogoutHandler(w http.ResponseWriter, r *http.Request) {
// Revoke the JTI — match the access token lifetime (1 hour)
if err := auth.RevokeJTI(r.Context(), jti, clock.Now().Add(1*time.Hour)); err != nil {
slog.Error("logout: failed to revoke JTI", "err", err)
http.Error(w, "Failed to revoke token. Please try again.", http.StatusInternalServerError)
mw.RespondError(w, http.StatusInternalServerError, "failed to revoke token. please try again.")
return
}
+8
View File
@@ -14,3 +14,11 @@ func RespondJSON(w http.ResponseWriter, status int, data any) {
_ = json.NewEncoder(w).Encode(data)
}
// RespondError sends a JSON error response with the given status code and message.
// It preserves the application/json Content-Type set by middleware.
func RespondError(w http.ResponseWriter, status int, msg string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
_ = json.NewEncoder(w).Encode(map[string]string{"error": msg})
}
+1 -1
View File
@@ -11,7 +11,7 @@
"build": "vite build",
"preview": "vite preview",
"prepare": "svelte-kit sync || echo ''",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --fail-on-warnings",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"format": "prettier --write .",
"lint": "prettier --check . && eslint .",