Skip to content

Add request validation for ListBranches and ListCommits endpoints#297

Open
hanzjk wants to merge 1 commit intowso2:mainfrom
hanzjk:validations
Open

Add request validation for ListBranches and ListCommits endpoints#297
hanzjk wants to merge 1 commit intowso2:mainfrom
hanzjk:validations

Conversation

@hanzjk
Copy link
Contributor

@hanzjk hanzjk commented Feb 5, 2026

Purpose

Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc.

Resolves #257

Goals

Describe the solutions that this feature/fix will introduce to resolve the problems described above

Approach

Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here.

User stories

Summary of user stories addressed by this change>

Release note

Brief description of the new feature or bug fix as it will appear in the release notes

Documentation

Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter �N/A� plus brief explanation of why there�s no doc impact

Training

Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable

Certification

Type �Sent� when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type �N/A� and explain why.

Marketing

Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable

Automation tests

  • Unit tests

    Code coverage information

  • Integration tests

    Details about the test cases and coverage

Security checks

Samples

Provide high-level details about the samples related to this feature

Related PRs

List any other related PRs

Migrations (if applicable)

Describe migration steps and platforms on which migration has been tested

Test environment

List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested

Learning

Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem.

Summary by CodeRabbit

  • Refactor
    • Unified request validation logic for repository and commit listing endpoints, ensuring consistent error handling across the service
    • Enhanced validation constraints for GitHub identifiers and branch names, including checks for invalid characters and path traversal patterns
    • Improved validation error messages to provide clearer guidance for invalid request parameters

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 5, 2026

📝 Walkthrough

Walkthrough

Request validation logic for git API endpoints (ListBranches and ListCommits) was refactored to use centralized validator functions instead of inline per-field checks. New validation functions were introduced in utils to enforce safety constraints on identifiers, branch names, and request parameters.

Changes

Cohort / File(s) Summary
Controller Refactoring
agent-manager-service/controllers/repository_controller.go
Replaced inline validation for ListBranches and ListCommits methods with calls to new centralized validation functions (ValidateListBranchesRequest and ValidateListCommitsRequest). Removed individual required-field error branches for owner/repository identifiers.
Validation Functions
agent-manager-service/utils/utils.go
Added public validators ValidateListBranchesRequest and ValidateListCommitsRequest, plus private helpers isValidGitHubIdentifier and isValidGitHubBranch. Validators enforce character restrictions, prevent path traversal patterns, validate optional fields (branch, path, author), and check time field consistency (Since/Until ordering and future-time constraints).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Validation rules, so tidy and clean,
No path traversal sneaking in between!
Centralized checks, a rabbit's delight,
Git repos guarded with all of their might!
Safety and order, hopping just right! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is mostly incomplete. Only the Purpose section is partially filled with a linked issue reference; Goals, Approach, User Stories, Release notes, and other required sections are left as template placeholders. Complete the PR description by filling in Goals, Approach, Release notes, and other key sections to explain the implementation details and impact of the validation changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding request validation for two specific endpoints (ListBranches and ListCommits).
Linked Issues check ✅ Passed The PR successfully implements request validation for the ListBranches and ListCommits endpoints as required by issue #257, adding centralized validation functions with comprehensive field checks.
Out of Scope Changes check ✅ Passed All changes are focused on implementing request validation for ListBranches and ListCommits endpoints, which directly addresses the linked issue requirement. No out-of-scope changes detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@agent-manager-service/utils/utils.go`:
- Around line 647-681: The validation trims payload.Branch, payload.Path, and
payload.Author (see payload.Branch, payload.Path, payload.Author and
isValidGitHubBranch) but never updates the original fields, so whitespace-padded
values can pass validation yet be forwarded; fix by either rejecting values that
differ after trimming or normalizing by writing the trimmed strings back into
payload (e.g., set payload.Branch = &branchVal, payload.Path = &pathVal,
payload.Author = &authorVal) after successful validation so downstream code
receives the normalized values.
- Around line 583-599: The isValidGitHubBranch function uses an overly strict
allowlist regex which excludes valid characters like '@' and '+'; update
isValidGitHubBranch to switch from the current allowlist (validPattern) to an
invalidlist approach: reject branches containing forbidden characters (~ ^ : ? *
[ \ control chars space), structural violations like "..", "@{", a single "@"
token, trailing "/" or ".lock", or ending with a dot; keep the empty-string
check and use targeted string checks/regexes to detect those forbidden patterns
rather than the current `^[a-zA-Z0-9._/-]+$` pattern so valid refs such as
dependabot scoped names pass.

Comment on lines +583 to +599
// isValidGitHubBranch validates that a branch name contains only safe characters
func isValidGitHubBranch(branch string) bool {
if branch == "" {
return false
}
// Branch names can contain alphanumeric, hyphens, underscores, periods, and forward slashes
// But reject path traversal patterns
validPattern := regexp.MustCompile(`^[a-zA-Z0-9._/-]+$`)
if !validPattern.MatchString(branch) {
return false
}
// Reject path traversal patterns
if strings.Contains(branch, "..") {
return false
}
return true
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

git check-ref-format valid characters allowed disallowed branch names rules

💡 Result:

git check-ref-format refname rules (what branch/tag ref names may contain)

Git treats refnames like refs/heads/<name> (branches) and refs/tags/<name> (tags). A refname is invalid if it violates any of these rules:

  1. / is allowed for hierarchy, but no path component may start with . or end with .lock.
  2. Must contain at least one / (e.g., heads/foo) unless you pass --allow-onelevel.
  3. Must not contain .. anywhere.
  4. Must not contain ASCII control chars, space, or any of: ~ ^ :.
  5. Must not contain: ? * [ (except with --refspec-pattern, which allows a single *).
  6. Must not begin or end with /, and must not contain // (unless you use --normalize to collapse/clean slashes).
  7. Must not end with .
  8. Must not contain the sequence @{
  9. Must not be exactly @
  10. Must not contain backslash \ [1]

Branch-name-specific note (--branch)

git check-ref-format --branch <name> can be stricter than validating refs/heads/<name> directly; for example, a name starting with - is rejected as a branch name even though - can be valid inside a ref component. [1][2]

Quick practical “safe” character set (recommended, not required by Git): letters, digits, ., -, _, /. [3]

Sources: man page rules: [1]; Git docs on --branch being stricter: [2]; GitHub guidance on safe characters: [3].


🌐 Web query:

git branch name @ plus sign characters allowed valid refs

💡 Result:

In Git, branch names are refnames (typically under refs/heads/), so they follow the refname rules.

+ (plus sign)

+ is allowed in ref/branch names because it’s not in Git’s list of forbidden characters/sequences for refnames. Forbidden include: space, ~, ^, :, ?, *, [, \, ASCII control chars; plus a few structural rules like no .., no ending in .lock, etc. [1]

@ (at sign)

@ is mostly allowed, with key exceptions:

  • A refname cannot contain the sequence @{ (because @{...} is used for reflog syntax like HEAD@{1}). [1]
  • A refname cannot be exactly the single character @ (because @ is a special shorthand for HEAD). [1]

Quick validation

Use:

  • git check-ref-format refs/heads/<name> (validates as a refname), or
  • git check-ref-format --branch <name> (validates as a branch name; can be a bit stricter). [1]

Source: Git documentation for git-check-ref-format. [1]

Sources

[1] git-check-ref-format documentation (git-scm.com) (git-scm.com)

Citations:


🏁 Script executed:

cd agent-manager-service && find . -name "*.go" -type f | head -20

Repository: wso2/agent-manager

Length of output: 730


🏁 Script executed:

find . -path "*/utils/utils.go" -type f

Repository: wso2/agent-manager

Length of output: 100


🏁 Script executed:

sed -n '583,599p' ./agent-manager-service/utils/utils.go

Repository: wso2/agent-manager

Length of output: 581


🏁 Script executed:

cat > /tmp/test_branch_validation.go << 'EOF'
package main

import (
	"fmt"
	"regexp"
)

func isValidGitHubBranch(branch string) bool {
	if branch == "" {
		return false
	}
	validPattern := regexp.MustCompile(`^[a-zA-Z0-9._/-]+$`)
	if !validPattern.MatchString(branch) {
		return false
	}
	if contains(branch, "..") {
		return false
	}
	return true
}

func contains(s, substr string) bool {
	for i := 0; i < len(s)-len(substr)+1; i++ {
		if s[i:i+len(substr)] == substr {
			return true
		}
	}
	return false
}

func main() {
	testCases := []struct {
		branch   string
		expected bool
	}{
		{"main", true},
		{"develop", true},
		{"feature/add-feature", true},
		{"bugfix_with_underscore", true},
		{"v1.0.0", true},
		{"dependabot/npm_and_yarn/@scope/pkg-name", false}, // contains @
		{"feat/+issue-123", false}, // contains +
		{"release@v1", false}, // contains @
		{"feat+plus", false}, // contains +
		{"feature/..", false}, // contains ..
		{"feature/something..else", false}, // contains ..
	}

	for _, tc := range testCases {
		result := isValidGitHubBranch(tc.branch)
		status := "✓"
		if result != tc.expected {
			status = "✗"
		}
		fmt.Printf("%s isValidGitHubBranch(%q) = %v (expected %v)\n", status, tc.branch, result, tc.expected)
	}
}
EOF
go run /tmp/test_branch_validation.go

Repository: wso2/agent-manager

Length of output: 776


Branch regex too restrictive; valid Git branch names will be rejected.

The allowlist pattern ^[a-zA-Z0-9._/-]+$ excludes characters that Git permits in refs, specifically @ and +. This causes rejection of valid branch names such as dependabot/npm_and_yarn/@scope/pkg-name (used by Dependabot for scoped packages) and branches with + prefixes.

According to git check-ref-format rules, both @ and + are allowed (with the exception that @{ sequences and the single character @ are forbidden). Use an invalidlist approach targeting only truly forbidden characters (~, ^, :, ?, *, [, \, control chars, space) and structural violations (.., @{, ending with / or .lock) instead of restricting to a narrow allowlist.

🤖 Prompt for AI Agents
In `@agent-manager-service/utils/utils.go` around lines 583 - 599, The
isValidGitHubBranch function uses an overly strict allowlist regex which
excludes valid characters like '@' and '+'; update isValidGitHubBranch to switch
from the current allowlist (validPattern) to an invalidlist approach: reject
branches containing forbidden characters (~ ^ : ? * [ \ control chars space),
structural violations like "..", "@{", a single "@" token, trailing "/" or
".lock", or ending with a dot; keep the empty-string check and use targeted
string checks/regexes to detect those forbidden patterns rather than the current
`^[a-zA-Z0-9._/-]+$` pattern so valid refs such as dependabot scoped names pass.

Comment on lines +647 to +681
// Validate optional branch field if provided
if payload.Branch != nil {
branchVal := strings.TrimSpace(*payload.Branch)
if branchVal == "" {
return fmt.Errorf("branch cannot be empty or whitespace")
}
if !isValidGitHubBranch(branchVal) {
return fmt.Errorf("branch contains invalid characters or path traversal patterns")
}
}

// Validate optional path field if provided
if payload.Path != nil {
pathVal := strings.TrimSpace(*payload.Path)
if pathVal == "" {
return fmt.Errorf("path cannot be empty or whitespace")
}
// Path can contain slashes, but reject path traversal patterns
if strings.Contains(pathVal, "..") {
return fmt.Errorf("path contains path traversal patterns")
}
}

// Validate optional author field if provided
if payload.Author != nil {
authorVal := strings.TrimSpace(*payload.Author)
if authorVal == "" {
return fmt.Errorf("author cannot be empty or whitespace")
}
// Author can be a username or email, so allow @ and . characters
// But still reject path traversal patterns
if strings.Contains(authorVal, "..") || strings.Contains(authorVal, "/") {
return fmt.Errorf("author contains invalid characters or path traversal patterns")
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Trimmed values are validated but not normalized/rejected.
Branch, Path, and Author are trimmed for validation only, but the original (possibly whitespace-padded) values are still forwarded to the service. That can pass validation yet fail downstream. Either reject leading/trailing whitespace or normalize by writing the trimmed values back.

✅ Option: reject or normalize whitespace-padded values
 	if payload.Branch != nil {
 		branchVal := strings.TrimSpace(*payload.Branch)
 		if branchVal == "" {
 			return fmt.Errorf("branch cannot be empty or whitespace")
 		}
+		if branchVal != *payload.Branch {
+			return fmt.Errorf("branch cannot contain leading or trailing whitespace")
+		}
 		if !isValidGitHubBranch(branchVal) {
 			return fmt.Errorf("branch contains invalid characters or path traversal patterns")
 		}
+		*payload.Branch = branchVal
 	}

 	if payload.Path != nil {
 		pathVal := strings.TrimSpace(*payload.Path)
 		if pathVal == "" {
 			return fmt.Errorf("path cannot be empty or whitespace")
 		}
+		if pathVal != *payload.Path {
+			return fmt.Errorf("path cannot contain leading or trailing whitespace")
+		}
 		if strings.Contains(pathVal, "..") {
 			return fmt.Errorf("path contains path traversal patterns")
 		}
+		*payload.Path = pathVal
 	}

 	if payload.Author != nil {
 		authorVal := strings.TrimSpace(*payload.Author)
 		if authorVal == "" {
 			return fmt.Errorf("author cannot be empty or whitespace")
 		}
+		if authorVal != *payload.Author {
+			return fmt.Errorf("author cannot contain leading or trailing whitespace")
+		}
 		if strings.Contains(authorVal, "..") || strings.Contains(authorVal, "/") {
 			return fmt.Errorf("author contains invalid characters or path traversal patterns")
 		}
+		*payload.Author = authorVal
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Validate optional branch field if provided
if payload.Branch != nil {
branchVal := strings.TrimSpace(*payload.Branch)
if branchVal == "" {
return fmt.Errorf("branch cannot be empty or whitespace")
}
if !isValidGitHubBranch(branchVal) {
return fmt.Errorf("branch contains invalid characters or path traversal patterns")
}
}
// Validate optional path field if provided
if payload.Path != nil {
pathVal := strings.TrimSpace(*payload.Path)
if pathVal == "" {
return fmt.Errorf("path cannot be empty or whitespace")
}
// Path can contain slashes, but reject path traversal patterns
if strings.Contains(pathVal, "..") {
return fmt.Errorf("path contains path traversal patterns")
}
}
// Validate optional author field if provided
if payload.Author != nil {
authorVal := strings.TrimSpace(*payload.Author)
if authorVal == "" {
return fmt.Errorf("author cannot be empty or whitespace")
}
// Author can be a username or email, so allow @ and . characters
// But still reject path traversal patterns
if strings.Contains(authorVal, "..") || strings.Contains(authorVal, "/") {
return fmt.Errorf("author contains invalid characters or path traversal patterns")
}
}
// Validate optional branch field if provided
if payload.Branch != nil {
branchVal := strings.TrimSpace(*payload.Branch)
if branchVal == "" {
return fmt.Errorf("branch cannot be empty or whitespace")
}
if branchVal != *payload.Branch {
return fmt.Errorf("branch cannot contain leading or trailing whitespace")
}
if !isValidGitHubBranch(branchVal) {
return fmt.Errorf("branch contains invalid characters or path traversal patterns")
}
*payload.Branch = branchVal
}
// Validate optional path field if provided
if payload.Path != nil {
pathVal := strings.TrimSpace(*payload.Path)
if pathVal == "" {
return fmt.Errorf("path cannot be empty or whitespace")
}
if pathVal != *payload.Path {
return fmt.Errorf("path cannot contain leading or trailing whitespace")
}
// Path can contain slashes, but reject path traversal patterns
if strings.Contains(pathVal, "..") {
return fmt.Errorf("path contains path traversal patterns")
}
*payload.Path = pathVal
}
// Validate optional author field if provided
if payload.Author != nil {
authorVal := strings.TrimSpace(*payload.Author)
if authorVal == "" {
return fmt.Errorf("author cannot be empty or whitespace")
}
if authorVal != *payload.Author {
return fmt.Errorf("author cannot contain leading or trailing whitespace")
}
// Author can be a username or email, so allow @ and . characters
// But still reject path traversal patterns
if strings.Contains(authorVal, "..") || strings.Contains(authorVal, "/") {
return fmt.Errorf("author contains invalid characters or path traversal patterns")
}
*payload.Author = authorVal
}
🤖 Prompt for AI Agents
In `@agent-manager-service/utils/utils.go` around lines 647 - 681, The validation
trims payload.Branch, payload.Path, and payload.Author (see payload.Branch,
payload.Path, payload.Author and isValidGitHubBranch) but never updates the
original fields, so whitespace-padded values can pass validation yet be
forwarded; fix by either rejecting values that differ after trimming or
normalizing by writing the trimmed strings back into payload (e.g., set
payload.Branch = &branchVal, payload.Path = &pathVal, payload.Author =
&authorVal) after successful validation so downstream code receives the
normalized values.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add request body/param validation for git based apis

1 participant