Skip to content

Commit c0ee67f

Browse files
Patel230Race Tester
andauthored
fix: production hardening (tok 0.1.0 CHANGELOG, trace panic, pin gosec/govulncheck, gosec enforcing)
* fix: production hardening (tok 0.1.0 CHANGELOG, trace panic, pin gosec/govulncheck, gosec enforcing) * fix: gosec G204/G202 issues - validateGitRef and nosec annotations --------- Co-authored-by: Race Tester <race@test.com>
1 parent 2f2d408 commit c0ee67f

4 files changed

Lines changed: 51 additions & 3 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,11 @@ jobs:
143143
run: git clone --depth=1 https://github.com/GrayCodeAI/hawk.git ../hawk
144144
- name: govulncheck
145145
run: |
146-
go install golang.org/x/vuln/cmd/govulncheck@latest
146+
go install golang.org/x/vuln/cmd/govulncheck@v1.1.4
147147
govulncheck ./...
148148
- name: gosec (advisory)
149-
continue-on-error: true
150149
run: |
151-
go install github.com/securego/gosec/v2/cmd/gosec@latest
150+
go install github.com/securego/gosec/v2/cmd/gosec@v2.22.4
152151
gosec -exclude=G104,G301,G302,G304,G306 ./...
153152
154153
# -------------------------------------------------------------------------

incremental.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,20 @@ func gitRoot(ctx context.Context) (string, error) {
230230
return strings.TrimSpace(string(out)), nil
231231
}
232232

233+
// validateGitRef ensures a git ref contains no dangerous characters.
234+
func validateGitRef(ref string) error {
235+
if ref == "" {
236+
return fmt.Errorf("empty git ref")
237+
}
238+
if ref[0] == '-' {
239+
return fmt.Errorf("git ref %q starts with dash", ref)
240+
}
241+
if strings.ContainsAny(ref, ";&|$`(){}[]<>!#*?\n\r\x00\\ ") {
242+
return fmt.Errorf("git ref %q contains forbidden characters", ref)
243+
}
244+
return nil
245+
}
246+
233247
// gitDiffRange runs `git diff base...head` with a context timeout.
234248
func gitDiffRange(ctx context.Context, base, head string) (string, error) {
235249
// Default 30s timeout if context has no deadline
@@ -239,13 +253,22 @@ func gitDiffRange(ctx context.Context, base, head string) (string, error) {
239253
defer cancel()
240254
}
241255

256+
if err := validateGitRef(base); err != nil {
257+
return "", fmt.Errorf("invalid base ref: %w", err)
258+
}
259+
if err := validateGitRef(head); err != nil {
260+
return "", fmt.Errorf("invalid head ref: %w", err)
261+
}
262+
242263
// Try three-dot syntax first (merge-base diff)
264+
// #nosec G204 — base and head validated by validateGitRef above
243265
out, err := exec.CommandContext(ctx, "git", "diff", base+"..."+head).Output()
244266
if err == nil {
245267
return string(out), nil
246268
}
247269

248270
// Fall back to two-dot syntax
271+
// #nosec G204 — base and head validated by validateGitRef above
249272
out, err = exec.CommandContext(ctx, "git", "diff", base, head).Output()
250273
if err != nil {
251274
return "", fmt.Errorf("git diff %s %s failed: %w", base, head, err)

internal/context/git.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,13 @@ func FormatContext(contexts []FileContext) string {
7575

7676
// DiffBase returns the diff of the current branch against a base branch.
7777
func DiffBase(base string) (string, error) {
78+
if err := validateGitRef(base); err != nil {
79+
return "", err
80+
}
81+
// #nosec G204 — base validated by validateGitRef
7882
out, err := exec.Command("git", "diff", base+"...HEAD").Output()
7983
if err != nil {
84+
// #nosec G204 — base validated by validateGitRef
8085
out2, err2 := exec.Command("git", "diff", base).Output()
8186
if err2 != nil {
8287
return "", fmt.Errorf("git diff failed: %w", err)
@@ -88,6 +93,10 @@ func DiffBase(base string) (string, error) {
8893

8994
// ChangedFiles returns the list of files changed relative to a base.
9095
func ChangedFiles(base string) ([]string, error) {
96+
if err := validateGitRef(base); err != nil {
97+
return nil, err
98+
}
99+
// #nosec G204 — base validated by validateGitRef
91100
out, err := exec.Command("git", "diff", "--name-only", base+"...HEAD").Output()
92101
if err != nil {
93102
return nil, fmt.Errorf("git diff --name-only failed: %w", err)
@@ -111,6 +120,7 @@ func Blame(file string, startLine, endLine int) (string, error) {
111120
"--", file,
112121
}
113122

123+
// #nosec G204 — file validated by validateFilePath above, startLine/endLine are ints
114124
out, err := exec.Command("git", args...).Output()
115125
if err != nil {
116126
return "", fmt.Errorf("git blame failed: %w", err)
@@ -119,6 +129,20 @@ func Blame(file string, startLine, endLine int) (string, error) {
119129
return parseBlameAuthors(string(out)), nil
120130
}
121131

132+
// validateGitRef ensures a git ref (branch, tag, SHA) contains no dangerous characters.
133+
func validateGitRef(ref string) error {
134+
if ref == "" {
135+
return fmt.Errorf("empty git ref")
136+
}
137+
if ref[0] == '-' {
138+
return fmt.Errorf("git ref %q starts with dash", ref)
139+
}
140+
if strings.ContainsAny(ref, ";&|$`(){}[]<>!#*?\n\r\x00\\ ") {
141+
return fmt.Errorf("git ref %q contains forbidden characters", ref)
142+
}
143+
return nil
144+
}
145+
122146
// validateFilePath ensures a file path does not traverse outside the working directory.
123147
func validateFilePath(file string) error {
124148
if file == "" {
@@ -146,6 +170,7 @@ func recentCommits(file string, n int) ([]string, error) {
146170
if err := validateFilePath(file); err != nil {
147171
return nil, fmt.Errorf("recentCommits: invalid path: %w", err)
148172
}
173+
// #nosec G204 — file validated by validateFilePath above
149174
out, err := exec.Command("git", "log", "--oneline", "-n", strconv.Itoa(n), "--", file).Output()
150175
if err != nil {
151176
return nil, err

testdata/crossfunc/vuln.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func handler(w http.ResponseWriter, r *http.Request) {
3333
// runQuery builds a SQL statement from the tainted parameter (sink in a
3434
// different function than the source).
3535
func runQuery(q string) {
36+
// #nosec G202 — intentional test data for taint analysis
3637
query := "SELECT * FROM users WHERE name = '" + q + "'"
3738
_, _ = db.Query(query)
3839
}

0 commit comments

Comments
 (0)