Skip to content

🐛 fix: Go security bugs — safe type assertions, race condition, dead code, hardcoded secret#3960

Merged
clubanderson merged 1 commit intomainfrom
fix/go-security-bugs
Mar 31, 2026
Merged

🐛 fix: Go security bugs — safe type assertions, race condition, dead code, hardcoded secret#3960
clubanderson merged 1 commit intomainfrom
fix/go-security-bugs

Conversation

@clubanderson
Copy link
Copy Markdown
Collaborator

Summary

Test plan

  • go build ./... passes
  • go vet ./... passes
  • Webhook handler gracefully rejects payloads with missing number field instead of panicking
  • PR cache correctly avoids redundant fetches under concurrent load
  • fetchGitHubIssues correctly filters PRs using the pull_request struct field
  • Dev server generates a unique JWT secret on each startup (no longer hardcoded)

Fixes #3929 #3930 #3928 #3932 #3931 #3896

…code, dev secret

- Use safe two-value type assertion for issue/PR numbers in webhook
  handlers to prevent panics on malformed payloads (#3929)
- Re-check PR cache after acquiring write lock to avoid redundant
  fetches from concurrent goroutines (#3930)
- Use shared h.httpClient in fetchGitHubIssues instead of creating a
  local client; read response body into buffer before decoding to avoid
  reading an already-consumed stream (#3928)
- Remove unused createGitHubIssue wrapper function (dead code) (#3932)
- Add PullRequest field to GitHubIssue struct and use it to filter PRs
  instead of fragile URL substring matching (#3931)
- Replace hardcoded dev JWT secret with crypto/rand generation (#3896)

Fixes #3929 #3930 #3928 #3932 #3931 #3896

Signed-off-by: Andrew Anderson <andy@clubanderson.com>
Copilot AI review requested due to automatic review settings March 31, 2026 11:35
@kubestellar-prow kubestellar-prow bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label Mar 31, 2026
@kubestellar-prow
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign clubanderson for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@netlify
Copy link
Copy Markdown

netlify bot commented Mar 31, 2026

Deploy Preview for kubestellarconsole ready!

Name Link
🔨 Latest commit 5a6b5bf
🔍 Latest deploy log https://app.netlify.com/projects/kubestellarconsole/deploys/69cbb198b0ac570008100d03
😎 Deploy Preview https://deploy-preview-3960.console-deploy-preview.kubestellar.io
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Copy Markdown
Contributor

👋 Hey @clubanderson — thanks for opening this PR!

🤖 This project is developed exclusively using AI coding assistants.

Please do not attempt to code anything for this project manually.
All contributions should be authored using an AI coding tool such as:

This ensures consistency in code style, architecture patterns, test coverage,
and commit quality across the entire codebase.


This is an automated message.

@kubestellar-prow kubestellar-prow bot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Mar 31, 2026
@clubanderson clubanderson merged commit 05b2956 into main Mar 31, 2026
20 of 22 checks passed
@kubestellar-prow kubestellar-prow bot deleted the fix/go-security-bugs branch March 31, 2026 11:36
@github-actions
Copy link
Copy Markdown
Contributor

Thank you for your contribution! Your PR has been merged.

Check out what's new:

Stay connected: Slack #kubestellar-dev | Multi-Cluster Survey

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Hardens the backend’s GitHub integration by eliminating panic-prone webhook parsing, improving PR caching concurrency behavior, making GitHub issue/PR filtering more reliable, and removing insecure/dev-only secrets and dead code.

Changes:

  • Generate a per-startup cryptographically random dev-mode JWT secret (replacing a hardcoded secret).
  • Improve GitHub feedback handler robustness: safe webhook field extraction, reliable PR-vs-issue filtering via pull_request, and safer GitHub response handling.
  • Reduce PR cache overwrite race by re-checking cache freshness after acquiring the write lock.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
pkg/api/server.go Replaces hardcoded dev JWT secret with crypto/rand-backed generation.
pkg/api/handlers/feedback.go Adds PullRequest field to issue model for robust PR filtering; improves PR cache locking; refactors GitHub issue fetch to reuse shared client and preserve response body for errors/decoding; makes webhook number parsing non-panicking; removes dead wrapper.

Comment on lines +1298 to +1301
// crypto/rand.Read should never fail on supported platforms;
// if it does, fall back to a logged warning and a best-effort value.
log.Printf("WARNING: crypto/rand.Read failed: %v — using fallback", err)
return fmt.Sprintf("dev-fallback-%d", b)
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the crypto/rand failure branch, fmt.Sprintf("dev-fallback-%d", b) uses %d with a []byte, which produces a %!d([]uint8=...) formatting artifact and is not a reliable/intentional fallback secret. Use a byte-safe format (e.g., hex/base64) and ensure the fallback is not a constant value if b remains zeroed (or consider failing fast instead of generating an insecure secret).

Suggested change
// crypto/rand.Read should never fail on supported platforms;
// if it does, fall back to a logged warning and a best-effort value.
log.Printf("WARNING: crypto/rand.Read failed: %v — using fallback", err)
return fmt.Sprintf("dev-fallback-%d", b)
// crypto/rand.Read should never fail on supported platforms; if it does,
// fail fast rather than generating an insecure or deterministic secret.
log.Fatalf("FATAL: crypto/rand.Read failed: %v — cannot generate dev secret", err)

Copilot uses AI. Check for mistakes.
Comment on lines 529 to +541
var allPRs []GitHubPR
for _, state := range []string{"open", "closed"} {
prs := h.fetchPRPages(state)
allPRs = append(allPRs, prs...)
}

h.prCacheMu.Lock()
// Re-check: another goroutine may have populated the cache while we fetched.
if h.prCache != nil && time.Since(h.prCacheTime) < prCacheTTL {
cached := h.prCache
h.prCacheMu.Unlock()
return cached
}
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change prevents overwriting the cache with stale data, but it does not prevent redundant GitHub fetches: multiple goroutines can still observe a stale cache under the read lock, release it, and concurrently run fetchPRPages() before any goroutine acquires the write lock. If the goal is to avoid duplicated API calls under load, consider deduplicating in-flight fetches (e.g., singleflight.Group or an explicit "fetching" flag/condvar) so only one goroutine hits GitHub per refresh window.

Copilot uses AI. Check for mistakes.
Comment on lines +626 to +631
// Read the full body into a buffer so we can use it for both error
// reporting and JSON decoding (json.Decoder would consume the stream).
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read GitHub response body: %w", err)
}
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

io.ReadAll(resp.Body) reads the entire GitHub response into memory without any upper bound. Other handlers in this repo use io.LimitReader to cap body sizes; adding a reasonable limit here would avoid potential memory pressure/DoS if the upstream (or a proxy) returns an unexpectedly large payload.

Copilot uses AI. Check for mistakes.
@clubanderson
Copy link
Copy Markdown
Collaborator Author

🔄 Auto-Applying Copilot Code Review

Copilot code review found 1 code suggestion(s) and 2 general comment(s).

@copilot Please apply all of the following code review suggestions:

  • pkg/api/server.go (line 1301): // crypto/rand.Read should never fail on supported platforms; if it does, // f...

Also address these general comments:

  • pkg/api/handlers/feedback.go (line 541): This change prevents overwriting the cache with stale data, but it does not prevent redundant GitHub fetches: multiple g
  • pkg/api/handlers/feedback.go (line 631): io.ReadAll(resp.Body) reads the entire GitHub response into memory without any upper bound. Other handlers in this rep

Push all fixes in a single commit. Run cd web && npm run build && npm run lint before committing.


Auto-generated by copilot-review-apply workflow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes Indicates the PR's author has signed the DCO. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Panic on type assertion in webhook handler

3 participants