From f6b71aad64d88d5182cecf3276a4caba1061abdd Mon Sep 17 00:00:00 2001 From: Dev10-sys Date: Thu, 1 Oct 2026 03:19:53 +0530 Subject: [PATCH] feat: add detection of Codebuff and Freebuff Closes #112 Signed-off-by: Dev10-sys --- detection/constants.go | 25 ++++++--- detection/toolmention/toolmention_test.go | 35 +++++++++++++ detection/trailer/trailer.go | 21 ++++++++ detection/trailer/trailer_test.go | 64 +++++++++++++++++++++++ 4 files changed, 139 insertions(+), 6 deletions(-) diff --git a/detection/constants.go b/detection/constants.go index 22d65fc..526183c 100644 --- a/detection/constants.go +++ b/detection/constants.go @@ -138,6 +138,8 @@ var SupportedToolsInMentions = []string{ "Salesforce Codegen", "CodeWhisperer", "OrbisAI Security", + "Codebuff", + "Freebuff", } // KnownAgentBranchPrefixes maps branch name prefixes used by AI coding CLIs/agents @@ -160,13 +162,15 @@ var KnownAgentBranchPrefixes = map[string]string{ // KnownCoAuthorEmails Known emails present with Co-Authored-By trailers var KnownCoAuthorEmails = map[string]string{ - "noreply@anthropic.com": "Claude Code", - "cursoragent@cursor.com": "Cursor", - "noreply@aider.chat": "Aider", - "copilot@github.com": "Copilot", - "noreply@continue.dev": "Continue.dev", - "noreply@windsurf.com": "Windsurf", + "noreply@anthropic.com": "Claude Code", + "cursoragent@cursor.com": "Cursor", + "noreply@aider.chat": "Aider", + "copilot@github.com": "Copilot", + "noreply@continue.dev": "Continue.dev", + "noreply@windsurf.com": "Windsurf", "openhands@all-hands.dev": "OpenHands", + "noreply@codebuff.com": "Codebuff", + "noreply@freebuff.com": "Freebuff", } // CoAuthorPattern Regex to look for Co-Authored-By trailer with name and email @@ -181,6 +185,15 @@ var AiderCommitPrefix = "aider:" // ClaudeAttributionText var ClaudeAttributionText = "Generated with Claude Code" +// CodebuffAttributionText commit message text added by Codebuff +var CodebuffAttributionText = "Generated with Codebuff" + +// FreebuffAttributionText commit message text added by Freebuff +var FreebuffAttributionText = "Generated with Freebuff" + +// FreebuffGeneratedWithPattern matches the Freebuff-style "Generated with: github.com//@" trailer +var FreebuffGeneratedWithPattern = regexp.MustCompile(`(?im)Generated with:\s+github\.com/[^/]+/[^@\s]*(?:codebuff|freebuff)[^@\s]*@[0-9a-f]+`) + // EntireIOTrailers List of EntireIO related trailers to check for var EntireIOTrailers = []string{ "Entire-Metadata", diff --git a/detection/toolmention/toolmention_test.go b/detection/toolmention/toolmention_test.go index f79508d..e8bfec7 100644 --- a/detection/toolmention/toolmention_test.go +++ b/detection/toolmention/toolmention_test.go @@ -268,6 +268,41 @@ func TestDetect(t *testing.T) { wantScore: 20, wantConfidence: detection.ConfidenceLow, }, + { + name: "Codebuff mention", + input: detection.Input{Text: "Code in this PR was generated with Codebuff"}, + wantTools: []string{"Codebuff"}, + wantScore: 20, + wantConfidence: detection.ConfidenceLow, + }, + { + name: "Freebuff mention", + input: detection.Input{Text: "Written using Freebuff AI agent"}, + wantTools: []string{"Freebuff"}, + wantScore: 20, + wantConfidence: detection.ConfidenceLow, + }, + { + name: "Codebuff and Freebuff mention in commit message", + input: detection.Input{CommitMessage: "feat: implemented with Codebuff and Freebuff"}, + wantTools: []string{"Codebuff", "Freebuff"}, + wantScore: 20, + wantConfidence: detection.ConfidenceLow, + }, + { + name: "Codebuff and Freebuff case insensitive", + input: detection.Input{Text: "tested with CODEBUFF and freebuff"}, + wantTools: []string{"Codebuff", "Freebuff"}, + wantScore: 20, + wantConfidence: detection.ConfidenceLow, + }, + { + name: "Codebuff and Freebuff word boundary prevents partial match", + input: detection.Input{Text: "the codebuffering system and freebuffer cache"}, + wantTools: nil, + wantScore: 20, + wantConfidence: detection.ConfidenceLow, + }, { name: "Yi AI", input: detection.Input{Text: "Test cases generated with Yi AI"}, diff --git a/detection/trailer/trailer.go b/detection/trailer/trailer.go index 20fd183..5fc8bf3 100644 --- a/detection/trailer/trailer.go +++ b/detection/trailer/trailer.go @@ -108,6 +108,27 @@ var commitMessagePatterns = []struct { }, name: "OrbisAI Security", }, + { + check: func(msg string) (float64, bool) { + if strings.Contains(msg, detection.CodebuffAttributionText) { + return detection.TrailerMatchBaseScore, true + } + return detection.TrailerNotMatchedScore, false + }, + name: "Codebuff", + }, + { + check: func(msg string) (float64, bool) { + if strings.Contains(msg, detection.FreebuffAttributionText) { + return detection.TrailerMatchBaseScore, true + } + if detection.FreebuffGeneratedWithPattern.MatchString(msg) { + return detection.TrailerMatchBaseScore, true + } + return detection.TrailerNotMatchedScore, false + }, + name: "Freebuff", + }, } type Detector struct { diff --git a/detection/trailer/trailer_test.go b/detection/trailer/trailer_test.go index e6f57de..eec33b2 100644 --- a/detection/trailer/trailer_test.go +++ b/detection/trailer/trailer_test.go @@ -592,6 +592,70 @@ Signed-off-by: some human wantScore: nil, wantConfidence: nil, }, + { + name: "codebuff: Generated with Codebuff in commit message", + message: "fix: update handler\n\n🤖 Generated with Codebuff", + wantTools: []string{"Codebuff"}, + wantModels: []string{""}, + wantScore: []float64{35}, + wantConfidence: []detection.Confidence{detection.ConfidenceMedium}, + }, + { + name: "codebuff: Generated with Codebuff (no emoji) in commit message", + message: "feat: add feature\n\nGenerated with Codebuff", + wantTools: []string{"Codebuff"}, + wantModels: []string{""}, + wantScore: []float64{35}, + wantConfidence: []detection.Confidence{detection.ConfidenceMedium}, + }, + { + name: "codebuff: Co-Authored-By trailer with Codebuff email", + message: "fix: update handler\n\nCo-Authored-By: Codebuff ", + wantTools: []string{"Codebuff"}, + wantModels: []string{""}, + wantScore: []float64{75}, + wantConfidence: []detection.Confidence{detection.ConfidenceHigh}, + }, + { + name: "freebuff: Generated with Freebuff in commit message", + message: "fix: update handler\n\n🤖 Generated with Freebuff", + wantTools: []string{"Freebuff"}, + wantModels: []string{""}, + wantScore: []float64{35}, + wantConfidence: []detection.Confidence{detection.ConfidenceMedium}, + }, + { + name: "freebuff: Generated with github.com URL with freebuff in repo name", + message: "feat: add feature\n\nGenerated with: github.com/LCHEROURI/cook-with-freebuff@08624f0b1b", + wantTools: []string{"Freebuff"}, + wantModels: []string{""}, + wantScore: []float64{35}, + wantConfidence: []detection.Confidence{detection.ConfidenceMedium}, + }, + { + name: "freebuff: Generated with github.com URL with codebuff in repo name", + message: "feat: add feature\n\nGenerated with: github.com/LCHEROURI/cook-with-codebuff@08624f0b1b", + wantTools: []string{"Freebuff"}, + wantModels: []string{""}, + wantScore: []float64{35}, + wantConfidence: []detection.Confidence{detection.ConfidenceMedium}, + }, + { + name: "freebuff: Co-Authored-By trailer with Freebuff email", + message: "fix: update handler\n\nCo-Authored-By: Freebuff ", + wantTools: []string{"Freebuff"}, + wantModels: []string{""}, + wantScore: []float64{75}, + wantConfidence: []detection.Confidence{detection.ConfidenceHigh}, + }, + { + name: "freebuff: unrelated repo URL does not match Generated with pattern", + message: "check out https://github.com/example/freebuff for docs", + wantTools: nil, + wantModels: nil, + wantScore: nil, + wantConfidence: nil, + }, { name: "aider in middle of message not prefix", message: "fix the aider: integration test",