All checks were successful
Check / check (push) Successful in 4s
Bumps golangci-lint from v2.10.1 to v2.12.2 everywhere it is pinned and installs the canonical `.golangci.yml`, then fixes every finding the new linter surfaces so `make check` is green. ## Version pins - `Dockerfile` lint stage: `golangci/golangci-lint:v2.12.2` (Debian-based), tag plus digest pin - `script/bootstrap`: `GOLANGCI_LINT_VERSION=2.12.2` with updated `linux-amd64`/`linux-arm64` release-archive sha256 pins ## Config `.golangci.yml` replaced with the canonical config. Material change: the old file declared `version: "2"` but kept settings under the legacy top-level `linters-settings` key, which golangci-lint v2 ignores — so the intended thresholds (`lll` 88, `funlen` 80/50, `cyclop` 15, `dupl` 100) were not being applied. The canonical file moves them under `linters.settings` and drops `issues.exclude-use-default`. ## Lint fixes (216 findings) - `lll` (96): wrapped lines to the 88-column limit - `noctx` (46): `httptest.NewRequestWithContext` with `t.Context()` throughout the tests - `goconst` (24): shared constants for template/JSON keys in `internal/handlers` and repeated test literals - `gosec` (23): app-page redirects now go through a `redirectToApp` helper that path-escapes the app ID (G710 open redirect); `http.ServeFile` of the internally derived deployment log path annotated like the adjacent `os.Stat` (G703) - `dupl` (22): extracted a generic `findAllByAppID` in `internal/models`, a `deleteAppResource` helper in `internal/handlers`, a shared `parsePush` in `internal/service/webhook`, and table-driven/helper-based dedup in tests - `nolintlint` (5): removed `//nolint:funlen` directives made obsolete by the new limits (plus one more that became obsolete after refactoring) - `nilerr` (3, surfaced during fixing): resource-delete lookups now propagate the find error to the caller No behavior changes intended; all tests pass and `make check` is green. Note: golangci-lint v2.12 warns that `gomodguard` is deprecated in favor of `gomodguard_v2` — a future canonical-config update should address this centrally. Co-authored-by: sneak <sneak@sneak.berlin> Reviewed-on: #187 Co-authored-by: clawbot <clawbot@noreply.example.org> Co-committed-by: clawbot <clawbot@noreply.example.org>
80 lines
2.2 KiB
Go
80 lines
2.2 KiB
Go
package middleware //nolint:testpackage // tests internal CORS behavior
|
|
|
|
import (
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"sneak.berlin/go/upaas/internal/config"
|
|
)
|
|
|
|
//nolint:gosec // test credentials
|
|
func newCORSTestMiddleware(corsOrigins string) *Middleware {
|
|
return &Middleware{
|
|
log: slog.Default(),
|
|
params: &Params{
|
|
Config: &config.Config{
|
|
CORSOrigins: corsOrigins,
|
|
SessionSecret: "test-secret-32-bytes-long-enough",
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// assertNoCORSHeaders runs a request with the given Origin header through
|
|
// CORS middleware configured with corsOrigins and asserts that no
|
|
// Access-Control-Allow-Origin header is set.
|
|
func assertNoCORSHeaders(t *testing.T, corsOrigins, origin, msg string) {
|
|
t.Helper()
|
|
|
|
m := newCORSTestMiddleware(corsOrigins)
|
|
handler := m.CORS()(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
|
|
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
|
|
req.Header.Set("Origin", origin)
|
|
|
|
rec := httptest.NewRecorder()
|
|
handler.ServeHTTP(rec, req)
|
|
|
|
assert.Empty(t, rec.Header().Get("Access-Control-Allow-Origin"), msg)
|
|
}
|
|
|
|
func TestCORS_NoOriginsConfigured_NoCORSHeaders(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
assertNoCORSHeaders(t, "", "https://evil.com",
|
|
"expected no CORS headers when no origins configured")
|
|
}
|
|
|
|
func TestCORS_OriginsConfigured_AllowsMatchingOrigin(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := newCORSTestMiddleware("https://app.example.com,https://other.example.com")
|
|
handler := m.CORS()(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
|
|
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
|
|
req.Header.Set("Origin", "https://app.example.com")
|
|
|
|
rec := httptest.NewRecorder()
|
|
handler.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, "https://app.example.com",
|
|
rec.Header().Get("Access-Control-Allow-Origin"))
|
|
assert.Equal(t, "true",
|
|
rec.Header().Get("Access-Control-Allow-Credentials"))
|
|
}
|
|
|
|
func TestCORS_OriginsConfigured_RejectsNonMatchingOrigin(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
assertNoCORSHeaders(t, "https://app.example.com", "https://evil.com",
|
|
"expected no CORS headers for non-matching origin")
|
|
}
|