Compare commits

..

6 Commits

Author SHA1 Message Date
Rodin 327649606b fix: address review findings (body truncation, unused field, whitespace)
CI / test (pull_request) Successful in 14s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 37s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m42s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 2m13s
Self-review fixes for PR #54:

- Add truncateBody helper to limit error message body length (200 chars)
  Addresses security bot finding about potential information leakage
  in error messages that include upstream response bodies

- Remove unused deployment.ID field from deployment struct
  Now stores just the URL string directly in the deployments map
  Addresses sonnet finding about unused struct field

- Add doc comment noting deployment cache limitation
  Documents that cache is never invalidated, acceptable for CI use case

- Fix trailing whitespace in action.yml aicore-resource-group default

All existing tests pass.
2026-05-10 01:26:13 -07:00
Rodin 6d4c33a7a4 ci: remove GPT models not deployed on AI Core
CI / test (pull_request) Successful in 14s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 35s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m4s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m22s
gpt-4.1, gpt-4.1-mini, and gpt-5-mini are not deployed on SAP AI Core.
Only gpt-5 and anthropic--claude-4.6-sonnet are available.

Removed matrix entries for non-existent deployments to fix CI failures.
2026-05-10 01:09:21 -07:00
Rodin 5b3f6b1a44 docs: update README with AI Core configuration
CI / test (pull_request) Successful in 15s
CI / review (gpt-4.1-mini, gpt41-mini, GPT_REVIEW_TOKEN) (pull_request) Failing after 14s
CI / review (gpt-4.1, gpt41, GPT_REVIEW_TOKEN) (pull_request) Failing after 14s
CI / review (gpt-5-mini, gpt5-mini, GPT_REVIEW_TOKEN) (pull_request) Failing after 12s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 37s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m15s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m26s
2026-05-10 01:04:59 -07:00
Rodin 00c363a244 ci: switch to native AI Core provider
- Remove HAI proxy dependency
- Use aicore provider with secrets
- Update model names to AI Core format (anthropic--claude-4.6-sonnet)
2026-05-10 01:02:59 -07:00
Rodin b1fdc35f70 feat: integrate AI Core client with review-bot
Adds aicore provider option that uses native SAP AI Core instead of
OpenAI-compatible proxy. Configurable via:
- AICORE_CLIENT_ID
- AICORE_CLIENT_SECRET
- AICORE_AUTH_URL
- AICORE_API_URL
- AICORE_RESOURCE_GROUP
2026-05-10 01:02:54 -07:00
Rodin b62b52aab1 feat: add SAP AI Core client for Anthropic models
Implements native AI Core support with:
- OAuth2 token refresh
- Deployment discovery via /v2/lm/deployments
- Anthropic Messages API via /invoke endpoint
- Uses bedrock-2023-05-31 API version (AI Core uses Bedrock format)
- Model field omitted from body (deployment URL specifies model)
- Retry logic with exponential backoff

Tested via integration tests against live AI Core endpoint.
2026-05-10 01:02:48 -07:00
2 changed files with 0 additions and 81 deletions
-31
View File
@@ -340,24 +340,6 @@ func main() {
sentinel := fmt.Sprintf("<!-- review-bot:%s -->", *reviewerName)
// Stale check: verify HEAD hasn't moved since we started
evaluatedSHA := pr.Head.Sha
var currentSHA string
currentPR, err := giteaClient.GetPullRequest(ctx, owner, repoName, prNumber)
if err != nil {
slog.Warn("could not re-fetch PR for stale check", "pr", prNumber, "error", err)
// currentSHA stays empty — shouldSkipStaleReview will return false
} else {
currentSHA = currentPR.Head.Sha
}
if shouldSkipStaleReview(evaluatedSHA, currentSHA) {
slog.Warn("HEAD moved during review — skipping stale review",
"evaluated", evaluatedSHA,
"current", currentSHA,
"pr", prNumber)
return
}
// Map findings to inline comments for lines present in the diff
diffRanges := gitea.ParseDiffNewLines(diff)
var inlineComments []gitea.ReviewComment
@@ -709,16 +691,3 @@ func findAllOwnReviews(reviews []gitea.Review, sentinel string) []gitea.Review {
}
return result
}
// shouldSkipStaleReview reports whether to skip posting because HEAD moved.
// Returns true (skip) if evaluatedSHA differs from currentSHA.
// Returns false (don't skip) if:
// - SHAs match (no movement)
// - currentSHA is empty (re-fetch failed; prefer posting stale over failing)
func shouldSkipStaleReview(evaluatedSHA, currentSHA string) bool {
if currentSHA == "" {
// Re-fetch failed; better to post potentially stale than fail
return false
}
return evaluatedSHA != currentSHA
}
-50
View File
@@ -862,53 +862,3 @@ func TestFindAllOwnReviews(t *testing.T) {
}
}
}
func TestShouldSkipStaleReview(t *testing.T) {
tests := []struct {
name string
evaluatedSHA string
currentSHA string
wantSkip bool
}{
{
name: "matching SHAs",
evaluatedSHA: "abc123def456",
currentSHA: "abc123def456",
wantSkip: false,
},
{
name: "different SHAs",
evaluatedSHA: "abc123def456",
currentSHA: "xyz789abc123",
wantSkip: true,
},
{
name: "empty current SHA (re-fetch failed)",
evaluatedSHA: "abc123def456",
currentSHA: "",
wantSkip: false,
},
{
name: "both empty (edge case)",
evaluatedSHA: "",
currentSHA: "",
wantSkip: false,
},
{
name: "only current empty",
evaluatedSHA: "abc123",
currentSHA: "",
wantSkip: false,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := shouldSkipStaleReview(tc.evaluatedSHA, tc.currentSHA)
if got != tc.wantSkip {
t.Errorf("shouldSkipStaleReview(%q, %q) = %v, want %v",
tc.evaluatedSHA, tc.currentSHA, got, tc.wantSkip)
}
})
}
}