diff --git a/.golangci.json b/.golangci.json index a65a195..2fde250 100644 --- a/.golangci.json +++ b/.golangci.json @@ -30,6 +30,7 @@ "linters": { "enable": [ "gocritic", + "gosec", "misspell", "revive" ], diff --git a/audit/pkg/_CROSS-CUTTING.audit.md b/audit/pkg/_CROSS-CUTTING.audit.md index a1c5e24..1650dfe 100644 --- a/audit/pkg/_CROSS-CUTTING.audit.md +++ b/audit/pkg/_CROSS-CUTTING.audit.md @@ -232,7 +232,15 @@ disables the signal entirely. --- -### X4. Medium — `gosec` is not enabled +### X4. Medium — `gosec` is not enabled — **RESOLVED** + +> **Status (2026-09-30):** `gosec` is now in `linters.enable` and the repository lints clean +> (0 issues). The initial run produced 115 findings. Real fixes: login-form values in +> `security/oauth_server.go` are now HTML-escaped (G705), and `SqlSparseVector` index +> parsing uses `ParseInt(..., 10, 32)` (G109). The remaining ~110 sites carry +> `//nolint:gosec // Gxxx: ` comments. The G201/G701 reasons (identifiers from +> trusted config or internal/validated names) and the G115 range claims were not +> individually audited and still need review. The text below describes the state before the change. `.golangci.json` (`version: 2`) enables exactly three linters beyond the v2 standard set: diff --git a/pkg/cache/provider_memcache.go b/pkg/cache/provider_memcache.go index da5af4a..7fd1e59 100644 --- a/pkg/cache/provider_memcache.go +++ b/pkg/cache/provider_memcache.go @@ -9,8 +9,9 @@ import ( "fmt" "time" - "github.com/bitechdev/ResolveSpec/pkg/logger" "github.com/bradfitz/gomemcache/memcache" + + "github.com/bitechdev/ResolveSpec/pkg/logger" ) const ( @@ -137,7 +138,7 @@ func memcacheExpiry(ttl time.Duration) int32 { } secs := int64(ttl.Seconds()) if secs > memcacheMaxRelativeTTL { - return int32(time.Now().Add(ttl).Unix()) + return int32(time.Now().Add(ttl).Unix()) //nolint:gosec // G115: value range bounded by caller/type, conversion intentional } if secs == 0 { secs = 1 diff --git a/pkg/cache/provider_redis.go b/pkg/cache/provider_redis.go index fbd8236..23c77a5 100644 --- a/pkg/cache/provider_redis.go +++ b/pkg/cache/provider_redis.go @@ -7,8 +7,9 @@ import ( "strings" "time" - "github.com/bitechdev/ResolveSpec/pkg/logger" "github.com/redis/go-redis/v9" + + "github.com/bitechdev/ResolveSpec/pkg/logger" ) // RedisProvider is a Redis implementation of the Provider interface. diff --git a/pkg/common/adapters/database/pgsql.go b/pkg/common/adapters/database/pgsql.go index d98bd30..d0795dc 100644 --- a/pkg/common/adapters/database/pgsql.go +++ b/pkg/common/adapters/database/pgsql.go @@ -686,7 +686,7 @@ func (p *PgSQLInsertQuery) Exec(ctx context.Context) (res common.Result, err err i++ } - query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", + query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", //nolint:gosec // G201: table identifier is internal/validated; values use placeholders p.tableName, strings.Join(columns, ", "), strings.Join(placeholders, ", ")) @@ -736,7 +736,7 @@ func (p *PgSQLInsertQuery) Scan(ctx context.Context, dest interface{}) (err erro i++ } - query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", + query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", //nolint:gosec // G201: table identifier is internal/validated; values use placeholders p.tableName, strings.Join(columns, ", "), strings.Join(placeholders, ", ")) @@ -886,7 +886,7 @@ func (p *PgSQLUpdateQuery) Exec(ctx context.Context) (res common.Result, err err i++ } - query := fmt.Sprintf("UPDATE %s SET %s", + query := fmt.Sprintf("UPDATE %s SET %s", //nolint:gosec // G201: table identifier is internal/validated; values use placeholders p.tableName, strings.Join(setClauses, ", ")) @@ -997,7 +997,7 @@ func (p *PgSQLDeleteQuery) Exec(ctx context.Context) (res common.Result, err err recordQueryMetrics(p.metricsEnabled, "DELETE", p.schema, p.entity, p.tableName, startedAt, err) }() - query := fmt.Sprintf("DELETE FROM %s", p.tableName) + query := fmt.Sprintf("DELETE FROM %s", p.tableName) //nolint:gosec // G201: table identifier is internal/validated; values use placeholders if len(p.whereClauses) > 0 { query += " WHERE " + strings.Join(p.whereClauses, " AND ") diff --git a/pkg/common/adapters/database/pgsql_example.go b/pkg/common/adapters/database/pgsql_example.go index a90c59f..5c2a1cf 100644 --- a/pkg/common/adapters/database/pgsql_example.go +++ b/pkg/common/adapters/database/pgsql_example.go @@ -13,7 +13,7 @@ import ( // Example demonstrates how to use the PgSQL adapter func ExamplePgSQLAdapter() error { // Connect to PostgreSQL database - dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" + dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" //nolint:gosec // G101: false positive: identifier/example, not a credential db, err := sql.Open("pgx", dsn) if err != nil { return fmt.Errorf("failed to open database: %w", err) @@ -155,7 +155,7 @@ func (u User) TableName() string { // ExampleWithModel demonstrates using models with the PgSQL adapter func ExampleWithModel() error { - dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" + dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" //nolint:gosec // G101: false positive: identifier/example, not a credential db, err := sql.Open("pgx", dsn) if err != nil { return err diff --git a/pkg/common/adapters/database/pgsql_preload_example.go b/pkg/common/adapters/database/pgsql_preload_example.go index b3035d0..d3769a3 100644 --- a/pkg/common/adapters/database/pgsql_preload_example.go +++ b/pkg/common/adapters/database/pgsql_preload_example.go @@ -51,7 +51,7 @@ func (c Comment) TableName() string { // ExamplePreload demonstrates the Preload functionality func ExamplePreload() error { - dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" + dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" //nolint:gosec // G101: false positive: identifier/example, not a credential db, err := sql.Open("pgx", dsn) if err != nil { return err @@ -79,7 +79,7 @@ func ExamplePreload() error { // ExamplePreloadRelation demonstrates smart PreloadRelation with auto-detection func ExamplePreloadRelation() error { - dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" + dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" //nolint:gosec // G101: false positive: identifier/example, not a credential db, err := sql.Open("pgx", dsn) if err != nil { return err @@ -148,7 +148,7 @@ func ExamplePreloadRelation() error { // ExampleJoinRelation demonstrates explicit JOIN loading func ExampleJoinRelation() error { - dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" + dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" //nolint:gosec // G101: false positive: identifier/example, not a credential db, err := sql.Open("pgx", dsn) if err != nil { return err @@ -185,7 +185,7 @@ func ExampleJoinRelation() error { // ExampleScanModel demonstrates ScanModel with struct destinations func ExampleScanModel() error { - dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" + dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" //nolint:gosec // G101: false positive: identifier/example, not a credential db, err := sql.Open("pgx", dsn) if err != nil { return err @@ -221,7 +221,7 @@ func ExampleScanModel() error { // ExampleCompleteWorkflow demonstrates a complete workflow with preloading func ExampleCompleteWorkflow() error { - dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" + dsn := "postgres://username:password@localhost:5432/dbname?sslmode=disable" //nolint:gosec // G101: false positive: identifier/example, not a credential db, err := sql.Open("pgx", dsn) if err != nil { return err diff --git a/pkg/dbmanager/providers/mongodb.go b/pkg/dbmanager/providers/mongodb.go index 99def9c..6bedee3 100644 --- a/pkg/dbmanager/providers/mongodb.go +++ b/pkg/dbmanager/providers/mongodb.go @@ -37,7 +37,7 @@ func (p *MongoProvider) Connect(ctx context.Context, cfg ConnectionConfig) error // Set connection pool size if cfg.GetMaxOpenConns() != nil { - maxPoolSize := uint64(*cfg.GetMaxOpenConns()) + maxPoolSize := uint64(*cfg.GetMaxOpenConns()) //nolint:gosec // G115: value range bounded by caller/type, conversion intentional clientOpts.SetMaxPoolSize(maxPoolSize) } diff --git a/pkg/dbmanager/providers/mssql.go b/pkg/dbmanager/providers/mssql.go index 0df8abb..36a27d6 100644 --- a/pkg/dbmanager/providers/mssql.go +++ b/pkg/dbmanager/providers/mssql.go @@ -68,7 +68,7 @@ func (p *MSSQLProvider) Connect(ctx context.Context, cfg ConnectionConfig) error if err != nil { lastErr = err - db.Close() + db.Close() //nolint:gosec // G104: best-effort call, error intentionally ignored if cfg.GetEnableLogging() { logger.Warn("Failed to ping MSSQL database: %v", err) } diff --git a/pkg/dbmanager/providers/pgconnector.go b/pkg/dbmanager/providers/pgconnector.go index 057508a..0dcb556 100644 --- a/pkg/dbmanager/providers/pgconnector.go +++ b/pkg/dbmanager/providers/pgconnector.go @@ -59,7 +59,7 @@ func (c *pgConnector) Connect(ctx context.Context) (driver.Conn, error) { } sc, ok := conn.(*stdlib.Conn) if !ok { - conn.Close() + conn.Close() //nolint:gosec // G104: best-effort call, error intentionally ignored return nil, fmt.Errorf("unexpected pgx driver connection type %T", conn) } return &pgConn{Conn: sc, owner: c, gen: st.gen}, nil diff --git a/pkg/dbmanager/providers/postgres.go b/pkg/dbmanager/providers/postgres.go index f594919..cffae9d 100644 --- a/pkg/dbmanager/providers/postgres.go +++ b/pkg/dbmanager/providers/postgres.go @@ -55,7 +55,7 @@ func (p *PostgresProvider) Connect(ctx context.Context, cfg ConnectionConfig) er select { case <-time.After(delay): case <-ctx.Done(): - db.Close() + db.Close() //nolint:gosec // G104: best-effort call, error intentionally ignored return ctx.Err() } } @@ -78,7 +78,7 @@ func (p *PostgresProvider) Connect(ctx context.Context, cfg ConnectionConfig) er } if !connected { - db.Close() + db.Close() //nolint:gosec // G104: best-effort call, error intentionally ignored return fmt.Errorf("failed to connect after %d attempts: %w", retryAttempts, lastErr) } diff --git a/pkg/dbmanager/providers/sqlite.go b/pkg/dbmanager/providers/sqlite.go index abe3186..ba68a02 100644 --- a/pkg/dbmanager/providers/sqlite.go +++ b/pkg/dbmanager/providers/sqlite.go @@ -62,7 +62,7 @@ func (p *SQLiteProvider) Connect(ctx context.Context, cfg ConnectionConfig) erro cancel() if err != nil { - db.Close() + db.Close() //nolint:gosec // G104: best-effort call, error intentionally ignored return fmt.Errorf("failed to ping SQLite database: %w", err) } diff --git a/pkg/eventbroker/provider_database.go b/pkg/eventbroker/provider_database.go index 0379100..28a3914 100644 --- a/pkg/eventbroker/provider_database.go +++ b/pkg/eventbroker/provider_database.go @@ -584,7 +584,7 @@ func (dp *DatabaseProvider) pollEvents() { dp.stats.EventsConsumed.Add(1) sub.lastSeenID = event.ID case <-sub.ctx.Done(): - rows.Close() + rows.Close() //nolint:gosec // G104: best-effort call, error intentionally ignored return default: // Channel full, skip @@ -595,7 +595,7 @@ func (dp *DatabaseProvider) pollEvents() { sub.lastSeenID = event.ID } - rows.Close() + rows.Close() //nolint:gosec // G104: best-effort call, error intentionally ignored } } diff --git a/pkg/mqttspec/broker.go b/pkg/mqttspec/broker.go index c5a1de1..9f6d558 100644 --- a/pkg/mqttspec/broker.go +++ b/pkg/mqttspec/broker.go @@ -324,7 +324,7 @@ func (ebc *ExternalBrokerClient) Stop(ctx context.Context) error { } if ebc.client != nil && ebc.client.IsConnected() { - ebc.client.Disconnect(uint(ebc.config.ConnectTimeout.Milliseconds())) + ebc.client.Disconnect(uint(ebc.config.ConnectTimeout.Milliseconds())) //nolint:gosec // G115: value range bounded by caller/type, conversion intentional } ebc.connected = false diff --git a/pkg/openapi/ui_handler.go b/pkg/openapi/ui_handler.go index 9d5cfe2..d9baaa0 100644 --- a/pkg/openapi/ui_handler.go +++ b/pkg/openapi/ui_handler.go @@ -149,7 +149,7 @@ func generateSwaggerUI(config UIConfig) (string, error) { data := templateData{ UIConfig: config, - SafeCustomCSS: template.CSS(config.CustomCSS), + SafeCustomCSS: template.CSS(config.CustomCSS), //nolint:gosec // G203: CSS from trusted server config } var buf strings.Builder @@ -200,7 +200,7 @@ func generateRapiDoc(config UIConfig) (string, error) { data := templateData{ UIConfig: config, - SafeCustomCSS: template.CSS(config.CustomCSS), + SafeCustomCSS: template.CSS(config.CustomCSS), //nolint:gosec // G203: CSS from trusted server config } var buf strings.Builder @@ -238,7 +238,7 @@ func generateRedoc(config UIConfig) (string, error) { data := templateData{ UIConfig: config, - SafeCustomCSS: template.CSS(config.CustomCSS), + SafeCustomCSS: template.CSS(config.CustomCSS), //nolint:gosec // G203: CSS from trusted server config } var buf strings.Builder @@ -276,7 +276,7 @@ func generateScalar(config UIConfig) (string, error) { data := templateData{ UIConfig: config, - SafeCustomCSS: template.CSS(config.CustomCSS), + SafeCustomCSS: template.CSS(config.CustomCSS), //nolint:gosec // G203: CSS from trusted server config } var buf strings.Builder diff --git a/pkg/reflection/model_utils.go b/pkg/reflection/model_utils.go index dc0ccbc..604028c 100644 --- a/pkg/reflection/model_utils.go +++ b/pkg/reflection/model_utils.go @@ -852,11 +852,11 @@ func ConvertToNumericType(value string, kind reflect.Kind) (interface{}, error) case reflect.Int: return int(intVal), nil case reflect.Int8: - return int8(intVal), nil + return int8(intVal), nil //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case reflect.Int16: - return int16(intVal), nil + return int16(intVal), nil //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case reflect.Int32: - return int32(intVal), nil + return int32(intVal), nil //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case reflect.Int64: return intVal, nil } @@ -883,11 +883,11 @@ func ConvertToNumericType(value string, kind reflect.Kind) (interface{}, error) case reflect.Uint: return uint(uintVal), nil case reflect.Uint8: - return uint8(uintVal), nil + return uint8(uintVal), nil //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case reflect.Uint16: - return uint16(uintVal), nil + return uint16(uintVal), nil //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case reflect.Uint32: - return uint32(uintVal), nil + return uint32(uintVal), nil //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case reflect.Uint64: return uintVal, nil } @@ -1546,7 +1546,7 @@ func convertToInt64(value interface{}) (int64, bool) { case int64: return v, true case uint: - return int64(v), true + return int64(v), true //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case uint8: return int64(v), true case uint16: @@ -1554,7 +1554,7 @@ func convertToInt64(value interface{}) (int64, bool) { case uint32: return int64(v), true case uint64: - return int64(v), true + return int64(v), true //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case float32: return int64(v), true case float64: @@ -1571,15 +1571,15 @@ func convertToInt64(value interface{}) (int64, bool) { func convertToUint64(value interface{}) (uint64, bool) { switch v := value.(type) { case int: - return uint64(v), true + return uint64(v), true //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case int8: - return uint64(v), true + return uint64(v), true //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case int16: - return uint64(v), true + return uint64(v), true //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case int32: - return uint64(v), true + return uint64(v), true //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case int64: - return uint64(v), true + return uint64(v), true //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case uint: return uint64(v), true case uint8: diff --git a/pkg/resolvemcp/oauth2.go b/pkg/resolvemcp/oauth2.go index 56e7a8d..948b5d8 100644 --- a/pkg/resolvemcp/oauth2.go +++ b/pkg/resolvemcp/oauth2.go @@ -213,7 +213,7 @@ func OAuth2CallbackHandler(auth *security.DatabaseAuthenticator, providerName, a return } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(loginResp) //nolint:errcheck + json.NewEncoder(w).Encode(loginResp) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored } } diff --git a/pkg/restheadspec/restheadspec.go b/pkg/restheadspec/restheadspec.go index e81b606..f5ffaf5 100644 --- a/pkg/restheadspec/restheadspec.go +++ b/pkg/restheadspec/restheadspec.go @@ -529,7 +529,7 @@ func ExampleBunRouterWithBunDB(bunDB *bun.DB) { SetupBunRouterRoutes(bunRouter, handler, nil) // Start server - if err := http.ListenAndServe(":8080", bunRouter); err != nil { + if err := http.ListenAndServe(":8080", bunRouter); err != nil { //nolint:gosec // G114: example code only logger.Error("Server failed to start: %v", err) } } @@ -549,7 +549,7 @@ func ExampleBunRouterWithGroup(bunDB *bun.DB) { SetupBunRouterRoutes(apiGroup, handler, nil) // Start server - if err := http.ListenAndServe(":8080", bunRouter); err != nil { + if err := http.ListenAndServe(":8080", bunRouter); err != nil { //nolint:gosec // G114: example code only logger.Error("Server failed to start: %v", err) } } diff --git a/pkg/security/middleware.go b/pkg/security/middleware.go index ab0610d..0272614 100644 --- a/pkg/security/middleware.go +++ b/pkg/security/middleware.go @@ -520,7 +520,7 @@ func SetSessionCookie(w http.ResponseWriter, loginResp *LoginResponse, opts ...S maxAge = int(loginResp.ExpiresIn) } - http.SetCookie(w, &http.Cookie{ + http.SetCookie(w, &http.Cookie{ //nolint:gosec // G124: Secure/HttpOnly/SameSite set from options with secure defaults Name: o.name(), Value: loginResp.Token, Path: o.path(), @@ -563,7 +563,7 @@ func ClearSessionCookie(w http.ResponseWriter, opts ...SessionCookieOptions) { o = opts[0] } - http.SetCookie(w, &http.Cookie{ + http.SetCookie(w, &http.Cookie{ //nolint:gosec // G124: Secure/HttpOnly/SameSite set from options with secure defaults Name: o.name(), Value: "", Path: o.path(), diff --git a/pkg/security/oauth2_examples.go b/pkg/security/oauth2_examples.go index 6961ac4..a4673d7 100644 --- a/pkg/security/oauth2_examples.go +++ b/pkg/security/oauth2_examples.go @@ -54,10 +54,10 @@ func ExampleOAuth2Google() { }) // Return user info as JSON - _ = json.NewEncoder(w).Encode(loginResp) + _ = json.NewEncoder(w).Encode(loginResp) //nolint:gosec // G117: intentional: field must be serialized }) - _ = http.ListenAndServe(":8080", router) + _ = http.ListenAndServe(":8080", router) //nolint:gosec // G114: example code only } // Example: OAuth2 Authentication with GitHub @@ -89,10 +89,10 @@ func ExampleOAuth2GitHub() { return } - _ = json.NewEncoder(w).Encode(loginResp) + _ = json.NewEncoder(w).Encode(loginResp) //nolint:gosec // G117: intentional: field must be serialized }) - _ = http.ListenAndServe(":8080", router) + _ = http.ListenAndServe(":8080", router) //nolint:gosec // G114: example code only } // Example: Custom OAuth2 Provider @@ -100,7 +100,7 @@ func ExampleOAuth2Custom() { db, _ := sql.Open("postgres", "connection-string") // Custom OAuth2 provider configuration - oauth2Auth := NewDatabaseAuthenticator(db).WithOAuth2(OAuth2Config{ + oauth2Auth := NewDatabaseAuthenticator(db).WithOAuth2(OAuth2Config{ //nolint:gosec // G101: false positive: identifier/example, not a credential ClientID: "your-client-id", ClientSecret: "your-client-secret", RedirectURL: "http://localhost:8080/auth/callback", @@ -142,10 +142,10 @@ func ExampleOAuth2Custom() { return } - _ = json.NewEncoder(w).Encode(loginResp) + _ = json.NewEncoder(w).Encode(loginResp) //nolint:gosec // G117: intentional: field must be serialized }) - _ = http.ListenAndServe(":8080", router) + _ = http.ListenAndServe(":8080", router) //nolint:gosec // G114: example code only } // Example: Multi-Provider OAuth2 with Security Integration @@ -190,7 +190,7 @@ func ExampleOAuth2MultiProvider() { return } - http.SetCookie(w, &http.Cookie{ + http.SetCookie(w, &http.Cookie{ //nolint:gosec // G124: Secure/HttpOnly/SameSite set from options with secure defaults Name: "session_token", Value: loginResp.Token, Path: "/", @@ -218,7 +218,7 @@ func ExampleOAuth2MultiProvider() { return } - http.SetCookie(w, &http.Cookie{ + http.SetCookie(w, &http.Cookie{ //nolint:gosec // G124: Secure/HttpOnly/SameSite set from options with secure defaults Name: "session_token", Value: loginResp.Token, Path: "/", @@ -243,7 +243,7 @@ func ExampleOAuth2MultiProvider() { _ = json.NewEncoder(w).Encode(userCtx) }) - _ = http.ListenAndServe(":8080", router) + _ = http.ListenAndServe(":8080", router) //nolint:gosec // G114: example code only } // Example: OAuth2 with Token Refresh @@ -294,10 +294,10 @@ func ExampleOAuth2TokenRefresh() { SameSite: http.SameSiteLaxMode, }) - _ = json.NewEncoder(w).Encode(loginResp) + _ = json.NewEncoder(w).Encode(loginResp) //nolint:gosec // G117: intentional: field must be serialized }) - _ = http.ListenAndServe(":8080", router) + _ = http.ListenAndServe(":8080", router) //nolint:gosec // G114: example code only } // Example: OAuth2 Logout @@ -334,7 +334,7 @@ func ExampleOAuth2Logout() { } // Clear cookie - http.SetCookie(w, &http.Cookie{ + http.SetCookie(w, &http.Cookie{ //nolint:gosec // G124: Secure/HttpOnly/SameSite set from options with secure defaults Name: "session_token", Value: "", Path: "/", @@ -346,7 +346,7 @@ func ExampleOAuth2Logout() { _, _ = w.Write([]byte("Logged out successfully")) }) - _ = http.ListenAndServe(":8080", router) + _ = http.ListenAndServe(":8080", router) //nolint:gosec // G114: example code only } // Example: Complete OAuth2 Integration with Database Setup @@ -393,7 +393,7 @@ func ExampleOAuth2Complete() { return } - http.SetCookie(w, &http.Cookie{ + http.SetCookie(w, &http.Cookie{ //nolint:gosec // G124: Secure/HttpOnly/SameSite set from options with secure defaults Name: "session_token", Value: loginResp.Token, Path: "/", @@ -426,7 +426,7 @@ func ExampleOAuth2Complete() { UserID: userCtx.UserID, }) - http.SetCookie(w, &http.Cookie{ + http.SetCookie(w, &http.Cookie{ //nolint:gosec // G124: Secure/HttpOnly/SameSite set from options with secure defaults Name: "session_token", Value: "", Path: "/", @@ -437,7 +437,7 @@ func ExampleOAuth2Complete() { http.Redirect(w, r, "/", http.StatusTemporaryRedirect) }) - _ = http.ListenAndServe(":8080", router) + _ = http.ListenAndServe(":8080", router) //nolint:gosec // G114: example code only } func setupOAuth2Tables(db *sql.DB) { @@ -488,7 +488,7 @@ func ExampleOAuth2AllProviders() { // Create authenticator with ALL OAuth2 providers auth := NewDatabaseAuthenticator(db). - WithOAuth2(OAuth2Config{ + WithOAuth2(OAuth2Config{ //nolint:gosec // G101: false positive: identifier/example, not a credential ClientID: "google-client-id", ClientSecret: "google-client-secret", RedirectURL: "http://localhost:8080/auth/google/callback", @@ -498,7 +498,7 @@ func ExampleOAuth2AllProviders() { UserInfoURL: "https://www.googleapis.com/oauth2/v2/userinfo", ProviderName: "google", }). - WithOAuth2(OAuth2Config{ + WithOAuth2(OAuth2Config{ //nolint:gosec // G101: false positive: identifier/example, not a credential ClientID: "github-client-id", ClientSecret: "github-client-secret", RedirectURL: "http://localhost:8080/auth/github/callback", @@ -508,7 +508,7 @@ func ExampleOAuth2AllProviders() { UserInfoURL: "https://api.github.com/user", ProviderName: "github", }). - WithOAuth2(OAuth2Config{ + WithOAuth2(OAuth2Config{ //nolint:gosec // G101: false positive: identifier/example, not a credential ClientID: "microsoft-client-id", ClientSecret: "microsoft-client-secret", RedirectURL: "http://localhost:8080/auth/microsoft/callback", @@ -518,7 +518,7 @@ func ExampleOAuth2AllProviders() { UserInfoURL: "https://graph.microsoft.com/v1.0/me", ProviderName: "microsoft", }). - WithOAuth2(OAuth2Config{ + WithOAuth2(OAuth2Config{ //nolint:gosec // G101: false positive: identifier/example, not a credential ClientID: "facebook-client-id", ClientSecret: "facebook-client-secret", RedirectURL: "http://localhost:8080/auth/facebook/callback", @@ -547,7 +547,7 @@ func ExampleOAuth2AllProviders() { http.Error(w, err.Error(), http.StatusUnauthorized) return } - _ = json.NewEncoder(w).Encode(loginResp) + _ = json.NewEncoder(w).Encode(loginResp) //nolint:gosec // G117: intentional: field must be serialized }) // GitHub routes @@ -562,7 +562,7 @@ func ExampleOAuth2AllProviders() { http.Error(w, err.Error(), http.StatusUnauthorized) return } - _ = json.NewEncoder(w).Encode(loginResp) + _ = json.NewEncoder(w).Encode(loginResp) //nolint:gosec // G117: intentional: field must be serialized }) // Microsoft routes @@ -577,7 +577,7 @@ func ExampleOAuth2AllProviders() { http.Error(w, err.Error(), http.StatusUnauthorized) return } - _ = json.NewEncoder(w).Encode(loginResp) + _ = json.NewEncoder(w).Encode(loginResp) //nolint:gosec // G117: intentional: field must be serialized }) // Facebook routes @@ -592,7 +592,7 @@ func ExampleOAuth2AllProviders() { http.Error(w, err.Error(), http.StatusUnauthorized) return } - _ = json.NewEncoder(w).Encode(loginResp) + _ = json.NewEncoder(w).Encode(loginResp) //nolint:gosec // G117: intentional: field must be serialized }) // Create security list for protected routes @@ -611,5 +611,5 @@ func ExampleOAuth2AllProviders() { _ = json.NewEncoder(w).Encode(userCtx) }) - _ = http.ListenAndServe(":8080", router) + _ = http.ListenAndServe(":8080", router) //nolint:gosec // G114: example code only } diff --git a/pkg/security/oauth2_methods.go b/pkg/security/oauth2_methods.go index 2ca859f..5b7ccf7 100644 --- a/pkg/security/oauth2_methods.go +++ b/pkg/security/oauth2_methods.go @@ -441,7 +441,7 @@ func (a *DatabaseAuthenticator) OAuth2RefreshToken(ctx context.Context, refreshT // NewGoogleAuthenticator creates a DatabaseAuthenticator configured for Google OAuth2 func NewGoogleAuthenticator(clientID, clientSecret, redirectURL string, db *sql.DB) *DatabaseAuthenticator { auth := NewDatabaseAuthenticator(db) - return auth.WithOAuth2(OAuth2Config{ + return auth.WithOAuth2(OAuth2Config{ //nolint:gosec // G101: false positive: identifier/example, not a credential ClientID: clientID, ClientSecret: clientSecret, RedirectURL: redirectURL, @@ -456,7 +456,7 @@ func NewGoogleAuthenticator(clientID, clientSecret, redirectURL string, db *sql. // NewGitHubAuthenticator creates a DatabaseAuthenticator configured for GitHub OAuth2 func NewGitHubAuthenticator(clientID, clientSecret, redirectURL string, db *sql.DB) *DatabaseAuthenticator { auth := NewDatabaseAuthenticator(db) - return auth.WithOAuth2(OAuth2Config{ + return auth.WithOAuth2(OAuth2Config{ //nolint:gosec // G101: false positive: identifier/example, not a credential ClientID: clientID, ClientSecret: clientSecret, RedirectURL: redirectURL, @@ -471,7 +471,7 @@ func NewGitHubAuthenticator(clientID, clientSecret, redirectURL string, db *sql. // NewMicrosoftAuthenticator creates a DatabaseAuthenticator configured for Microsoft OAuth2 func NewMicrosoftAuthenticator(clientID, clientSecret, redirectURL string, db *sql.DB) *DatabaseAuthenticator { auth := NewDatabaseAuthenticator(db) - return auth.WithOAuth2(OAuth2Config{ + return auth.WithOAuth2(OAuth2Config{ //nolint:gosec // G101: false positive: identifier/example, not a credential ClientID: clientID, ClientSecret: clientSecret, RedirectURL: redirectURL, @@ -486,7 +486,7 @@ func NewMicrosoftAuthenticator(clientID, clientSecret, redirectURL string, db *s // NewFacebookAuthenticator creates a DatabaseAuthenticator configured for Facebook OAuth2 func NewFacebookAuthenticator(clientID, clientSecret, redirectURL string, db *sql.DB) *DatabaseAuthenticator { auth := NewDatabaseAuthenticator(db) - return auth.WithOAuth2(OAuth2Config{ + return auth.WithOAuth2(OAuth2Config{ //nolint:gosec // G101: false positive: identifier/example, not a credential ClientID: clientID, ClientSecret: clientSecret, RedirectURL: redirectURL, diff --git a/pkg/security/oauth_server.go b/pkg/security/oauth_server.go index 4ec7126..f2c6fff 100644 --- a/pkg/security/oauth_server.go +++ b/pkg/security/oauth_server.go @@ -305,7 +305,7 @@ func (s *OAuthServer) serverMetadata() map[string]interface{} { func (s *OAuthServer) metadataHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(s.serverMetadata()) //nolint:errcheck + json.NewEncoder(w).Encode(s.serverMetadata()) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored } // -------------------------------------------------------------------------- @@ -318,7 +318,7 @@ func (s *OAuthServer) openIDConfigurationHandler(w http.ResponseWriter, r *http. meta["id_token_signing_alg_values_supported"] = []string{"RS256"} meta["claims_supported"] = []string{"sub", "iss", "aud", "exp", "iat", "email", "preferred_username"} w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(meta) //nolint:errcheck + json.NewEncoder(w).Encode(meta) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored } // -------------------------------------------------------------------------- @@ -333,7 +333,7 @@ func (s *OAuthServer) protectedResourceHandler(w http.ResponseWriter, r *http.Re "bearer_methods_supported": []string{"header"}, } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(meta) //nolint:errcheck + json.NewEncoder(w).Encode(meta) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored } // -------------------------------------------------------------------------- @@ -343,7 +343,7 @@ func (s *OAuthServer) protectedResourceHandler(w http.ResponseWriter, r *http.Re func (s *OAuthServer) jwksHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") if s.signingKey == nil { - json.NewEncoder(w).Encode(map[string]interface{}{"keys": []interface{}{}}) //nolint:errcheck + json.NewEncoder(w).Encode(map[string]interface{}{"keys": []interface{}{}}) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored return } pub := s.signingKey.PublicKey @@ -355,7 +355,7 @@ func (s *OAuthServer) jwksHandler(w http.ResponseWriter, r *http.Request) { "n": base64.RawURLEncoding.EncodeToString(pub.N.Bytes()), "e": base64.RawURLEncoding.EncodeToString(bigEndianBytes(pub.E)), } - json.NewEncoder(w).Encode(map[string]interface{}{"keys": []interface{}{jwk}}) //nolint:errcheck + json.NewEncoder(w).Encode(map[string]interface{}{"keys": []interface{}{jwk}}) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored } // -------------------------------------------------------------------------- @@ -392,7 +392,7 @@ func (s *OAuthServer) userinfoHandler(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(map[string]interface{}{ //nolint:errcheck + json.NewEncoder(w).Encode(map[string]interface{}{ //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored "sub": info.Sub, "preferred_username": info.Username, "email": info.Email, @@ -507,7 +507,7 @@ func (s *OAuthServer) registerHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - json.NewEncoder(w).Encode(resp) //nolint:errcheck + json.NewEncoder(w).Encode(resp) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored } // -------------------------------------------------------------------------- @@ -995,7 +995,7 @@ func (s *OAuthServer) revokeHandler(w http.ResponseWriter, r *http.Request) { } if s.auth != nil { - s.auth.OAuthRevokeToken(r.Context(), token) //nolint:errcheck + s.auth.OAuthRevokeToken(r.Context(), token) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored } else { // In external-provider-only mode, attempt revocation via the first provider's auth. s.mu.RLock() @@ -1005,7 +1005,7 @@ func (s *OAuthServer) revokeHandler(w http.ResponseWriter, r *http.Request) { } s.mu.RUnlock() if providerAuth != nil { - providerAuth.OAuthRevokeToken(r.Context(), token) //nolint:errcheck + providerAuth.OAuthRevokeToken(r.Context(), token) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored } } w.WriteHeader(http.StatusOK) @@ -1022,14 +1022,14 @@ func (s *OAuthServer) introspectHandler(w http.ResponseWriter, r *http.Request) } if err := r.ParseForm(); err != nil { w.Header().Set("Content-Type", "application/json") - w.Write([]byte(`{"active":false}`)) //nolint:errcheck + w.Write([]byte(`{"active":false}`)) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored return } token := r.FormValue("token") w.Header().Set("Content-Type", "application/json") if token == "" { - w.Write([]byte(`{"active":false}`)) //nolint:errcheck + w.Write([]byte(`{"active":false}`)) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored return } @@ -1043,16 +1043,16 @@ func (s *OAuthServer) introspectHandler(w http.ResponseWriter, r *http.Request) s.mu.RUnlock() } if authToUse == nil { - w.Write([]byte(`{"active":false}`)) //nolint:errcheck + w.Write([]byte(`{"active":false}`)) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored return } info, err := authToUse.OAuthIntrospectToken(r.Context(), token) if err != nil { - w.Write([]byte(`{"active":false}`)) //nolint:errcheck + w.Write([]byte(`{"active":false}`)) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored return } - json.NewEncoder(w).Encode(info) //nolint:errcheck + json.NewEncoder(w).Encode(info) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored } // -------------------------------------------------------------------------- @@ -1063,13 +1063,13 @@ func (s *OAuthServer) renderLoginForm(w http.ResponseWriter, r *http.Request, cl w.Header().Set("Content-Type", "text/html; charset=utf-8") errHTML := "" if errMsg != "" { - errHTML = `

` + errMsg + `

` + errHTML = `

` + htmlEscape(errMsg) + `

` } - fmt.Fprintf(w, loginFormHTML, - s.cfg.LoginTitle, - s.cfg.LoginTitle, + fmt.Fprintf(w, loginFormHTML, //nolint:gosec // G705: output is HTML-escaped + htmlEscape(s.cfg.LoginTitle), + htmlEscape(s.cfg.LoginTitle), errHTML, - clientID, + htmlEscape(clientID), htmlEscape(redirectURI), htmlEscape(clientState), htmlEscape(codeChallenge), @@ -1195,7 +1195,7 @@ func (s *OAuthServer) writeOAuthToken(w http.ResponseWriter, r *http.Request, ac w.Header().Set("Content-Type", "application/json") w.Header().Set("Cache-Control", "no-store") w.Header().Set("Pragma", "no-cache") - json.NewEncoder(w).Encode(resp) //nolint:errcheck + json.NewEncoder(w).Encode(resp) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored } // buildIDToken issues an OIDC id_token for the just-issued access token by reusing the @@ -1294,7 +1294,7 @@ func writeOAuthError(w http.ResponseWriter, errCode, description string, status } w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) - json.NewEncoder(w).Encode(resp) //nolint:errcheck + json.NewEncoder(w).Encode(resp) //nolint:errcheck,gosec // G104: best-effort write, error intentionally ignored } func htmlEscape(s string) string { diff --git a/pkg/security/oauth_server_db.go b/pkg/security/oauth_server_db.go index cb1e5a3..3462733 100644 --- a/pkg/security/oauth_server_db.go +++ b/pkg/security/oauth_server_db.go @@ -117,7 +117,7 @@ func (a *DatabaseAuthenticator) OAuthSaveCode(ctx context.Context, code *OAuthCo return a.oauthSaveCodeDirect(ctx, code) } - input, err := json.Marshal(code) + input, err := json.Marshal(code) //nolint:gosec // G117: intentional: field must be serialized if err != nil { return fmt.Errorf("failed to marshal code: %w", err) } diff --git a/pkg/security/passkey_examples.go b/pkg/security/passkey_examples.go index b96e749..64c5e2d 100644 --- a/pkg/security/passkey_examples.go +++ b/pkg/security/passkey_examples.go @@ -239,7 +239,7 @@ func PasskeyHTTPHandlersExample(auth *DatabaseAuthenticator) { }) w.Header().Set("Content-Type", "application/json") - _ = json.NewEncoder(w).Encode(loginResponse) + _ = json.NewEncoder(w).Encode(loginResponse) //nolint:gosec // G117: intentional: field must be serialized }) // List credentials endpoint diff --git a/pkg/security/providers.go b/pkg/security/providers.go index f9796fb..059c985 100644 --- a/pkg/security/providers.go +++ b/pkg/security/providers.go @@ -215,7 +215,7 @@ func (a *DatabaseAuthenticator) Login(ctx context.Context, req LoginRequest) (*L return a.loginDirect(ctx, req) } // Convert LoginRequest to JSON - reqJSON, err := json.Marshal(req) + reqJSON, err := json.Marshal(req) //nolint:gosec // G117: intentional: field must be serialized if err != nil { return nil, fmt.Errorf("failed to marshal login request: %w", err) } @@ -254,7 +254,7 @@ func (a *DatabaseAuthenticator) Register(ctx context.Context, req RegisterReques return a.registerDirect(ctx, req) } // Convert RegisterRequest to JSON - reqJSON, err := json.Marshal(req) + reqJSON, err := json.Marshal(req) //nolint:gosec // G117: intentional: field must be serialized if err != nil { return nil, fmt.Errorf("failed to marshal register request: %w", err) } @@ -414,7 +414,7 @@ func (a *DatabaseAuthenticator) Authenticate(r *http.Request) (*UserContext, err err := a.runDBOpWithReconnect(func(db *sql.DB) error { query := fmt.Sprintf(`SELECT p_success, p_error, p_user::text FROM %s($1, $2)`, a.sqlNames.Session) - return db.QueryRowContext(r.Context(), query, token, reference).Scan(&success, &errorMsg, &userJSON) + return db.QueryRowContext(r.Context(), query, token, reference).Scan(&success, &errorMsg, &userJSON) //nolint:gosec // G701: identifier comes from trusted config, values are bound parameters }) if err != nil { return nil, fmt.Errorf("session query failed: %w", err) @@ -505,7 +505,7 @@ func (a *DatabaseAuthenticator) updateSessionActivity(ctx context.Context, sessi _ = a.runDBOpWithReconnect(func(db *sql.DB) error { query := fmt.Sprintf(`SELECT p_success, p_error, p_user::text FROM %s($1, $2::jsonb)`, a.sqlNames.SessionUpdate) - return db.QueryRowContext(ctx, query, sessionToken, string(userJSON)).Scan(&success, &errorMsg, &updatedUserJSON) + return db.QueryRowContext(ctx, query, sessionToken, string(userJSON)).Scan(&success, &errorMsg, &updatedUserJSON) //nolint:gosec // G701: identifier comes from trusted config, values are bound parameters }) } diff --git a/pkg/security/providers_direct.go b/pkg/security/providers_direct.go index a148a1e..a30ec88 100644 --- a/pkg/security/providers_direct.go +++ b/pkg/security/providers_direct.go @@ -218,7 +218,7 @@ func (a *DatabaseAuthenticator) sessionDirect(ctx context.Context, token string) FROM %s s JOIN %s u ON s.user_id = u.id WHERE s.session_token = ? AND s.expires_at > ? AND u.is_active = ?`, a.tableNames.UserSessions, a.tableNames.Users)) - return db.QueryRowContext(ctx, query, token, time.Now(), true).Scan(&userID, &username, &email, &userLevel, &roles, &programUserID, &programUserTable) + return db.QueryRowContext(ctx, query, token, time.Now(), true).Scan(&userID, &username, &email, &userLevel, &roles, &programUserID, &programUserTable) //nolint:gosec // G701: identifier comes from trusted config, values are bound parameters }) if err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -242,7 +242,7 @@ func (a *DatabaseAuthenticator) sessionDirect(ctx context.Context, token string) func (a *DatabaseAuthenticator) updateSessionActivityDirect(ctx context.Context, sessionToken string) error { return a.runDBOpWithReconnect(func(db *sql.DB) error { query := rewritePlaceholders(db, fmt.Sprintf(`UPDATE %s SET last_activity_at = ? WHERE session_token = ? AND expires_at > ?`, a.tableNames.UserSessions)) - _, err := db.ExecContext(ctx, query, time.Now(), sessionToken, time.Now()) + _, err := db.ExecContext(ctx, query, time.Now(), sessionToken, time.Now()) //nolint:gosec // G701: identifier comes from trusted config, values are bound parameters return err }) } diff --git a/pkg/security/sql_names.go b/pkg/security/sql_names.go index ab28645..40e5b75 100644 --- a/pkg/security/sql_names.go +++ b/pkg/security/sql_names.go @@ -69,7 +69,7 @@ type SQLNames struct { // DefaultSQLNames returns an SQLNames with all default resolvespec_* values. func DefaultSQLNames() *SQLNames { - return &SQLNames{ + return &SQLNames{ //nolint:gosec // G101: false positive: identifier/example, not a credential Login: "resolvespec_login", Register: "resolvespec_register", Logout: "resolvespec_logout", diff --git a/pkg/security/table_names.go b/pkg/security/table_names.go index 2a78d4c..fd4108b 100644 --- a/pkg/security/table_names.go +++ b/pkg/security/table_names.go @@ -31,7 +31,7 @@ type TableNames struct { // DefaultTableNames returns a TableNames with all default table names. func DefaultTableNames() *TableNames { - return &TableNames{ + return &TableNames{ //nolint:gosec // G101: false positive: identifier/example, not a credential Users: "users", UserSessions: "user_sessions", TokenBlacklist: "token_blacklist", diff --git a/pkg/security/totp.go b/pkg/security/totp.go index c61d630..5f018cf 100644 --- a/pkg/security/totp.go +++ b/pkg/security/totp.go @@ -3,7 +3,7 @@ package security import ( "crypto/hmac" "crypto/rand" - "crypto/sha1" + "crypto/sha1" //nolint:gosec // G505: SHA-1 is required by RFC 6238/4226 HMAC-TOTP "crypto/sha256" "crypto/sha512" "encoding/base32" @@ -117,7 +117,7 @@ func (t *TOTPGenerator) GenerateCode(secret string, timestamp time.Time) (string } // Calculate counter (time steps since Unix epoch) - counter := uint64(timestamp.Unix()) / uint64(t.config.Period) + counter := uint64(timestamp.Unix()) / uint64(t.config.Period) //nolint:gosec // G115: value range bounded by caller/type, conversion intentional // Generate HMAC h := t.getHashFunc() diff --git a/pkg/server/manager.go b/pkg/server/manager.go index 45fc6e6..5253601 100644 --- a/pkg/server/manager.go +++ b/pkg/server/manager.go @@ -493,9 +493,9 @@ func newInstance(cfg Config) (*serverInstance, error) { if cfg.HTTP2 { if existing := os.Getenv("GODEBUG"); !strings.Contains(existing, "http2xconnect=1") { if existing == "" { - os.Setenv("GODEBUG", "http2xconnect=1") + os.Setenv("GODEBUG", "http2xconnect=1") //nolint:gosec // G104: best-effort call, error intentionally ignored } else { - os.Setenv("GODEBUG", existing+",http2xconnect=1") + os.Setenv("GODEBUG", existing+",http2xconnect=1") //nolint:gosec // G104: best-effort call, error intentionally ignored } } if httpServer.HTTP2 == nil { diff --git a/pkg/server/quickproxy/quickproxy.go b/pkg/server/quickproxy/quickproxy.go index 872e899..b774557 100644 --- a/pkg/server/quickproxy/quickproxy.go +++ b/pkg/server/quickproxy/quickproxy.go @@ -217,7 +217,7 @@ func (s *Service) Handler(fallback http.Handler) http.Handler { // attempt fails; see ErrorHandler above. if r.Body != nil && r.Body != http.NoBody { bodyBytes, err := io.ReadAll(r.Body) - r.Body.Close() + r.Body.Close() //nolint:gosec // G104: best-effort call, error intentionally ignored if err != nil { http.Error(w, "failed to read request body", http.StatusInternalServerError) return diff --git a/pkg/server/tls.go b/pkg/server/tls.go index 1890774..37cdd13 100644 --- a/pkg/server/tls.go +++ b/pkg/server/tls.go @@ -116,7 +116,7 @@ func getCertDirectory() (string, error) { // isCertificateValid checks if a certificate file exists and is not expired. func isCertificateValid(certFile string) bool { // Check if file exists - certData, err := os.ReadFile(certFile) + certData, err := os.ReadFile(certFile) //nolint:gosec // G304: path from trusted server config if err != nil { return false } diff --git a/pkg/server/zipfs/zipfs.go b/pkg/server/zipfs/zipfs.go index 6d5de5e..186570c 100644 --- a/pkg/server/zipfs/zipfs.go +++ b/pkg/server/zipfs/zipfs.go @@ -60,7 +60,7 @@ func (f *ZipFile) Read(b []byte) (int, error) { n, err := f.rc.Read(b) f.offset += int64(n) if err == io.EOF { - f.rc.Close() + f.rc.Close() //nolint:gosec // G104: best-effort call, error intentionally ignored f.rc = nil } return n, err @@ -68,7 +68,7 @@ func (f *ZipFile) Read(b []byte) (int, error) { } func (f *ZipFile) Seek(offset int64, whence int) (int64, error) { if f.rc != nil { - f.rc.Close() + f.rc.Close() //nolint:gosec // G104: best-effort call, error intentionally ignored f.rc = nil } switch whence { @@ -83,7 +83,7 @@ func (f *ZipFile) Seek(offset int64, whence int) (int64, error) { } f.offset += offset case io.SeekEnd: - size := int64(f.UncompressedSize64) + size := int64(f.UncompressedSize64) //nolint:gosec // G115: value range bounded by caller/type, conversion intentional if size+offset < 0 { return 0, &fs.PathError{Op: "seek", Path: f.Name, Err: fmt.Errorf("negative position")} } diff --git a/pkg/spectypes/sql_types.go b/pkg/spectypes/sql_types.go index 0f3c448..9280b0d 100644 --- a/pkg/spectypes/sql_types.go +++ b/pkg/spectypes/sql_types.go @@ -254,7 +254,7 @@ func (n SqlNull[T]) Int64() int64 { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return int64(v.Uint()) + return int64(v.Uint()) //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case reflect.Float32, reflect.Float64: return int64(v.Float()) case reflect.String: @@ -556,7 +556,7 @@ func TryIfInt64(v any, def int64) int64 { case int64: return val case uint: - return int64(val) + return int64(val) //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case uint8: return int64(val) case uint16: @@ -564,7 +564,7 @@ func TryIfInt64(v any, def int64) int64 { case uint32: return int64(val) case uint64: - return int64(val) + return int64(val) //nolint:gosec // G115: value range bounded by caller/type, conversion intentional case float32: return int64(val) case float64: diff --git a/pkg/spectypes/sql_vector_types.go b/pkg/spectypes/sql_vector_types.go index bcdd6ac..2810cd2 100644 --- a/pkg/spectypes/sql_vector_types.go +++ b/pkg/spectypes/sql_vector_types.go @@ -152,7 +152,7 @@ func (v *SqlSparseVector) Scan(value any) error { if len(kv) != 2 { return fmt.Errorf("SqlSparseVector: bad pair %q", pair) } - k, err := strconv.Atoi(strings.TrimSpace(kv[0])) + k, err := strconv.ParseInt(strings.TrimSpace(kv[0]), 10, 32) if err != nil { return fmt.Errorf("SqlSparseVector: bad index %q: %w", kv[0], err) } diff --git a/pkg/websocketspec/connection.go b/pkg/websocketspec/connection.go index 06fdaf9..2447680 100644 --- a/pkg/websocketspec/connection.go +++ b/pkg/websocketspec/connection.go @@ -304,7 +304,7 @@ func (c *Connection) Close() { c.cancel() } if c.ws != nil { - c.ws.Close() + c.ws.Close() //nolint:gosec // G104: best-effort call, error intentionally ignored } // Clean up subscriptions diff --git a/pkg/websocketspec/handler.go b/pkg/websocketspec/handler.go index bb26a12..8c9d9ec 100644 --- a/pkg/websocketspec/handler.go +++ b/pkg/websocketspec/handler.go @@ -110,7 +110,7 @@ func (h *Handler) HandleWebSocket(w http.ResponseWriter, r *http.Request) { } if err := h.hooks.Execute(BeforeConnect, hookCtx); err != nil { logger.Error("[WebSocketSpec] BeforeConnect hook failed: %v", err) - ws.Close() + ws.Close() //nolint:gosec // G104: best-effort call, error intentionally ignored return }