Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing various security issues and updating null_types to handle over… #407

Merged
merged 2 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 7 additions & 11 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
build_and_tests:
docker:
# specify the version
- image: cimg/go:1.21.6
- image: cimg/go:1.22.8
- image: cimg/postgres:14.10
environment:
POSTGRES_USER: jet
Expand Down Expand Up @@ -128,17 +128,13 @@ jobs:

# to create test results report
- run:
name: Install go-junit-report
command: go install github.com/jstemmer/go-junit-report@latest

name: Install gotestsum
command: go install gotest.tools/gotestsum@latest
- run: mkdir -p $TEST_RESULTS

# this will run all tests and exclude test files from code coverage report
- run: |
go test -v ./... \
-covermode=atomic \
-coverpkg=github.com/go-jet/jet/v2/postgres/...,github.com/go-jet/jet/v2/mysql/...,github.com/go-jet/jet/v2/sqlite/...,github.com/go-jet/jet/v2/qrm/...,github.com/go-jet/jet/v2/generator/...,github.com/go-jet/jet/v2/internal/... \
-coverprofile=cover.out 2>&1 | go-junit-report > $TEST_RESULTS/results.xml
- run:
name: Running tests
command: gotestsum --junitfile $TEST_RESULTS/report.xml --format testname -- -coverprofile=cover.out -covermode=atomic -coverpkg=github.com/go-jet/jet/v2/postgres/...,github.com/go-jet/jet/v2/mysql/...,github.com/go-jet/jet/v2/sqlite/...,github.com/go-jet/jet/v2/qrm/...,github.com/go-jet/jet/v2/generator/...,github.com/go-jet/jet/v2/internal/... ./...

# run mariaDB and cockroachdb tests. No need to collect coverage, because coverage is already included with mysql and postgres tests
- run: MY_SQL_SOURCE=MariaDB go test -v ./tests/mysql/
Expand All @@ -163,4 +159,4 @@ workflows:
version: 2
build_and_test:
jobs:
- build_and_tests
- build_and_tests
45 changes: 45 additions & 0 deletions .github/workflows/code_scanner.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Code Scanners
on:
push:
branches:
- master
pull_request:
branches:
- master

permissions:
contents: read

env:
go_version: "1.22.8"


jobs:
security_scanning:
runs-on: ubuntu-latest
steps:
- name: Checkout Source
uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.go_version }}
cache: true
- name: Setup Tools
run: |
go install github.com/securego/gosec/v2/cmd/gosec@latest
- name: Running Scan
run: gosec --exclude=G402,G304 ./...
lint_scanner:
runs-on: ubuntu-latest
steps:
- name: Checkout Source
uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.go_version }}
cache: true
- name: Setup Tools
run: |
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
- name: Running Scan
run: golangci-lint run --timeout=30m ./...
19 changes: 19 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
run:
# The default concurrency value is the number of available CPU.
concurrency: 4
# Timeout for analysis, e.g. 30s, 5m.
# Default: 1m
timeout: 30m
# Exit code when at least one issue was found.
# Default: 1
issues-exit-code: 2
# Include test files or not.
# Default: true
tests: false

issues:
exclude-dirs:
- tests
exclude-files:
- "_test.go"
- "testutils.go"
2 changes: 1 addition & 1 deletion examples/quick-start/quick-start.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func main() {
func jsonSave(path string, v interface{}) {
jsonText, _ := json.MarshalIndent(v, "", "\t")

err := os.WriteFile(path, jsonText, 0644)
err := os.WriteFile(path, jsonText, 0600)

panicOnError(err)
}
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ go 1.18

require (
github.com/go-sql-driver/mysql v1.8.1
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.6.0
github.com/jackc/pgconn v1.14.3
github.com/jackc/pgtype v1.14.3
github.com/jackc/pgx/v4 v4.18.3
github.com/lib/pq v1.10.9
github.com/mattn/go-sqlite3 v1.14.17
)

require (
safaci2000 marked this conversation as resolved.
Show resolved Hide resolved
github.com/google/go-cmp v0.6.0
github.com/jackc/pgtype v1.14.3
github.com/jackc/pgx/v4 v4.18.3
github.com/pkg/profile v1.7.0
github.com/shopspring/decimal v1.4.0
github.com/stretchr/testify v1.9.0
Expand Down
2 changes: 1 addition & 1 deletion internal/jet/statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func duration(f func()) time.Duration {

f()

return time.Now().Sub(start)
return time.Since(start)
}

// ExpressionStatement interfacess
Expand Down
7 changes: 4 additions & 3 deletions internal/testutils/test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,12 @@ func AssertJSON(t *testing.T, data interface{}, expectedJSON string) {
}

// SaveJSONFile saves v as json at testRelativePath
// nolint:unused
func SaveJSONFile(v interface{}, testRelativePath string) {
jsonText, _ := json.MarshalIndent(v, "", "\t")

filePath := getFullPath(testRelativePath)
err := os.WriteFile(filePath, jsonText, 0644)
err := os.WriteFile(filePath, jsonText, 0600)

throw.OnError(err)
}
Expand All @@ -116,7 +117,7 @@ func SaveJSONFile(v interface{}, testRelativePath string) {
func AssertJSONFile(t *testing.T, data interface{}, testRelativePath string) {

filePath := getFullPath(testRelativePath)
fileJSONData, err := os.ReadFile(filePath)
fileJSONData, err := os.ReadFile(filePath) // #nosec G304
require.NoError(t, err)

if runtime.GOOS == "windows" {
Expand Down Expand Up @@ -243,7 +244,7 @@ func AssertQueryPanicErr(t *testing.T, stmt jet.Statement, db qrm.DB, dest inter

// AssertFileContent check if file content at filePath contains expectedContent text.
func AssertFileContent(t *testing.T, filePath string, expectedContent string) {
enumFileData, err := os.ReadFile(filePath)
enumFileData, err := os.ReadFile(filePath) // #nosec G304

require.NoError(t, err)

Expand Down
10 changes: 7 additions & 3 deletions internal/utils/filesys/filesys.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package filesys

import (
"errors"
"fmt"
"go/format"
"os"
Expand All @@ -16,7 +17,7 @@ func FormatAndSaveGoFile(dirPath, fileName string, text []byte) error {
newGoFilePath += ".go"
}

file, err := os.Create(newGoFilePath)
file, err := os.Create(newGoFilePath) // #nosec 304

if err != nil {
return err
Expand All @@ -28,7 +29,10 @@ func FormatAndSaveGoFile(dirPath, fileName string, text []byte) error {

// if there is a format error we will write unformulated text for debug purposes
if err != nil {
file.Write(text)
_, writeErr := file.Write(text)
if writeErr != nil {
return errors.Join(writeErr, fmt.Errorf("failed to format '%s', check '%s' for syntax errors: %w", fileName, newGoFilePath, err))
}
return fmt.Errorf("failed to format '%s', check '%s' for syntax errors: %w", fileName, newGoFilePath, err)
}

Expand All @@ -43,7 +47,7 @@ func FormatAndSaveGoFile(dirPath, fileName string, text []byte) error {
// EnsureDirPathExist ensures dir path exists. If path does not exist, creates new path.
func EnsureDirPathExist(dirPath string) error {
if _, err := os.Stat(dirPath); os.IsNotExist(err) {
err := os.MkdirAll(dirPath, os.ModePerm)
err := os.MkdirAll(dirPath, 0o750)

if err != nil {
return fmt.Errorf("can't create directory - %s: %w", dirPath, err)
Expand Down
38 changes: 19 additions & 19 deletions mysql/interval.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,25 @@ type unitType string
// List of interval unit types for MySQL
const (
MICROSECOND unitType = "MICROSECOND"
SECOND = "SECOND"
MINUTE = "MINUTE"
HOUR = "HOUR"
DAY = "DAY"
WEEK = "WEEK"
MONTH = "MONTH"
QUARTER = "QUARTER"
YEAR = "YEAR"
SECOND_MICROSECOND = "SECOND_MICROSECOND"
MINUTE_MICROSECOND = "MINUTE_MICROSECOND"
MINUTE_SECOND = "MINUTE_SECOND"
HOUR_MICROSECOND = "HOUR_MICROSECOND"
HOUR_SECOND = "HOUR_SECOND"
HOUR_MINUTE = "HOUR_MINUTE"
DAY_MICROSECOND = "DAY_MICROSECOND"
DAY_SECOND = "DAY_SECOND"
DAY_MINUTE = "DAY_MINUTE"
DAY_HOUR = "DAY_HOUR"
YEAR_MONTH = "YEAR_MONTH"
SECOND unitType = "SECOND"
MINUTE unitType = "MINUTE"
HOUR unitType = "HOUR"
DAY unitType = "DAY"
WEEK unitType = "WEEK"
MONTH unitType = "MONTH"
QUARTER unitType = "QUARTER"
YEAR unitType = "YEAR"
SECOND_MICROSECOND unitType = "SECOND_MICROSECOND"
MINUTE_MICROSECOND unitType = "MINUTE_MICROSECOND"
MINUTE_SECOND unitType = "MINUTE_SECOND"
HOUR_MICROSECOND unitType = "HOUR_MICROSECOND"
HOUR_SECOND unitType = "HOUR_SECOND"
HOUR_MINUTE unitType = "HOUR_MINUTE"
DAY_MICROSECOND unitType = "DAY_MICROSECOND"
DAY_SECOND unitType = "DAY_SECOND"
DAY_MINUTE unitType = "DAY_MINUTE"
DAY_HOUR unitType = "DAY_HOUR"
YEAR_MONTH unitType = "YEAR_MONTH"
)

// Interval is representation of MySQL interval
Expand Down
37 changes: 28 additions & 9 deletions qrm/internal/null_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import (
"time"
)

var (
castOverFlowError = fmt.Errorf("cannot cast a negative value to an unsigned value, buffer overflow error")
)

// NullBool struct
type NullBool struct {
sql.NullBool
Expand Down Expand Up @@ -119,30 +123,45 @@ func (n *NullUInt64) Scan(value interface{}) error {
n.Valid = false
return nil
case int64:
if v < 0 {
return castOverFlowError
}
n.UInt64, n.Valid = uint64(v), true
return nil
case uint64:
n.UInt64, n.Valid = v, true
return nil
case int32:
if v < 0 {
return castOverFlowError
}
n.UInt64, n.Valid = uint64(v), true
return nil
case uint32:
case int16:
if v < 0 {
return castOverFlowError
}
n.UInt64, n.Valid = uint64(v), true
return nil
case int16:
case int8:
if v < 0 {
return castOverFlowError
}
n.UInt64, n.Valid = uint64(v), true
return nil
case uint16:
case int:
if v < 0 {
return castOverFlowError
}
n.UInt64, n.Valid = uint64(v), true
return nil
case int8:
case uint64:
n.UInt64, n.Valid = v, true
return nil
case uint32:
n.UInt64, n.Valid = uint64(v), true
return nil
case uint8:
case uint16:
n.UInt64, n.Valid = uint64(v), true
return nil
case int:
case uint8:
n.UInt64, n.Valid = uint64(v), true
return nil
case uint:
Expand Down
36 changes: 36 additions & 0 deletions qrm/internal/null_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package internal

import (
"fmt"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
"time"
Expand Down Expand Up @@ -62,11 +63,21 @@ func TestNullUInt64(t *testing.T) {
value, _ := nullUInt64.Value()
require.Equal(t, value, uint64(11))

require.NoError(t, nullUInt64.Scan(uint64(11)))
require.Equal(t, nullUInt64.Valid, true)
value, _ = nullUInt64.Value()
require.Equal(t, value, uint64(11))

require.NoError(t, nullUInt64.Scan(int32(32)))
require.Equal(t, nullUInt64.Valid, true)
value, _ = nullUInt64.Value()
require.Equal(t, value, uint64(32))

require.NoError(t, nullUInt64.Scan(uint32(32)))
require.Equal(t, nullUInt64.Valid, true)
value, _ = nullUInt64.Value()
require.Equal(t, value, uint64(32))

require.NoError(t, nullUInt64.Scan(int16(20)))
require.Equal(t, nullUInt64.Valid, true)
value, _ = nullUInt64.Value()
Expand All @@ -88,4 +99,29 @@ func TestNullUInt64(t *testing.T) {
require.Equal(t, value, uint64(30))

require.Error(t, nullUInt64.Scan("text"), "can't scan int32 from text")

//Validate negative use cases
err := nullUInt64.Scan(int64(-5))
assert.NotNil(t, err)
assert.Error(t, err, castOverFlowError)

//Validate negative use cases
err = nullUInt64.Scan(-5)
assert.NotNil(t, err)
assert.Error(t, err, castOverFlowError)

//Validate negative use cases
err = nullUInt64.Scan(int32(-5))
assert.NotNil(t, err)
assert.Error(t, err, castOverFlowError)

//Validate negative use cases
err = nullUInt64.Scan(int16(-5))
assert.NotNil(t, err)
assert.Error(t, err, castOverFlowError)

//Validate negative use cases
err = nullUInt64.Scan(int8(-5))
assert.NotNil(t, err)
assert.Error(t, err, castOverFlowError)
}
Loading
Loading