Skip to content

Conversation

@MichaelClifford
Copy link
Collaborator

No description provided.

@codecov
Copy link

codecov bot commented Dec 19, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions

This comment has been minimized.

@MichaelClifford MichaelClifford force-pushed the google-mcp-add-user-email branch from a4bb582 to b6d3857 Compare December 19, 2025 19:28
@github-actions
Copy link
Contributor

github-actions bot commented Dec 19, 2025

Claude Code Review

Summary

This PR adds user email support to the Google Workspace MCP integration by propagating the authenticated user's email through the backend → operator → runner pipeline. The email is extracted from the X-Forwarded-Email header, added to the session's userContext, and passed as the USER_GOOGLE_EMAIL environment variable to the Google Workspace MCP server.

Overall Assessment: Good implementation that follows established patterns, but has several critical security and error handling issues that must be addressed before merge.


Issues by Severity

🚫 Blocker Issues

1. Email Logging Violates Security Standards

  • Location: components/operator/internal/handlers/sessions.go:997
  • Issue: Email is logged in plaintext: log.Printf("Session %s initiated by user: %s (userId: %s, email: %s)")
  • Security Risk: PII (Personally Identifiable Information) exposure in logs
  • Standard Violated: CLAUDE.md security standards require redacting sensitive user data
  • Fix: Redact email in logs similar to token handling:
    log.Printf("Session %s initiated by user: %s (userId: %s, emailLen: %d)", name, userName, userID, len(userEmail))
  • Reference: CLAUDE.md line 436-439, security-standards.md lines 22-48

2. Missing Type Safety in Operator

  • Location: components/operator/internal/handlers/sessions.go:993-995
  • Issue: Direct type assertion without checking:
    if v, ok := userContext["email"].(string); ok {
        userEmail = strings.TrimSpace(v)
    }
  • Standard Violated: CLAUDE.md requires using unstructured.Nested* helpers
  • Risk: Will silently fail if field exists but is wrong type
  • Fix: Use type-safe access:
    if email, found, err := unstructured.NestedString(userContext, "email"); found && err == nil {
        userEmail = strings.TrimSpace(email)
    }
  • Reference: CLAUDE.md lines 441-445, k8s-client-usage.md

🔴 Critical Issues

3. Hardcoded Fallback Email in Production

  • Location: components/runners/claude-code-runner/adapter.py:89
  • Issue: Sets USER_GOOGLE_EMAIL=user@example.com as default
  • Risk:
    • Google MCP tools will attempt to use an invalid/example email
    • May cause authentication failures or unexpected behavior
    • No distinction between "email not provided" and "email is invalid"
  • Better Approach: Log a warning but don't set invalid default:
    if not os.getenv("USER_GOOGLE_EMAIL"):
        logger.warning("USER_GOOGLE_EMAIL not set - Google Workspace MCP may not function correctly")
    else:
        logger.info(f"USER_GOOGLE_EMAIL configured (len={len(os.getenv('USER_GOOGLE_EMAIL'))})")
  • Rationale: Fail fast with clear error rather than silent misconfiguration

4. Email Fallback Logic is Questionable

  • Location: components/backend/handlers/sessions.go:674-677
  • Issue: Falls back to userID if email not provided:
    if email == "" {
        email = uid
    }
  • Risk: userID may not be a valid email (could be LDAP DN, UUID, etc.)
  • Better Approach: Only fallback if userID looks like an email:
    if email == "" && strings.Contains(uid, "@") {
        email = uid
    }
  • Alternative: Don't set email at all if not provided (let it be empty)

🟡 Major Issues

5. Missing Test Coverage

  • Issue: No tests verify email propagation through the pipeline
  • Impact: Changes to middleware or session creation could break email flow
  • Recommendation: Add tests to components/backend/handlers/sessions_test.go:
    • Test email extraction from X-Forwarded-Email header
    • Test email fallback to userID
    • Test empty email handling
    • Test email added to userContext in CR

6. Inconsistent Error Handling in Python

  • Location: components/runners/claude-code-runner/adapter.py:87-92
  • Issue: Logs at INFO level for missing email (should be WARNING)
  • Pattern Violation: error-handling.md recommends appropriate log levels
  • Fix: Use logger.warning() for missing email since it may cause MCP failures

7. No Validation of Email Format

  • Issue: Email is accepted and propagated without validation
  • Risk: Invalid email could cause downstream failures in Google MCP
  • Recommendation: Add basic email validation in backend:
    import "net/mail"
    
    if email != "" {
        if _, err := mail.ParseAddress(email); err != nil {
            log.Printf("Warning: invalid email format for user %s", uid)
            email = "" // Clear invalid email
        }
    }

🔵 Minor Issues

8. Documentation Missing

  • Issue: No comments explaining why email is needed for Google MCP
  • Location: components/backend/handlers/sessions.go:667, .mcp.json:26
  • Recommendation: Add comments:
    // Extract email from authenticated user for Google Workspace MCP integration
    // Google Drive/Calendar/Gmail tools require user email for scoped access
    email := ""

9. Type Definition Could Be More Specific

  • Location: components/backend/types/common.go:15
  • Issue: Email field uses omitempty but no validation tag
  • Suggestion: Add validation tag for better type safety:
    Email string `json:"email,omitempty" validate:"omitempty,email"`

10. Environment Variable Not Documented

  • Issue: USER_GOOGLE_EMAIL is not documented in component READMEs
  • Impact: Operators won't know this env var exists or how it's populated
  • Recommendation: Document in components/runners/claude-code-runner/README.md

Positive Highlights

Follows Established Patterns: Email extraction mirrors existing userName and userID patterns
Consistent Pipeline: Properly flows through backend → CR → operator → runner
Proper Field Marking: Email correctly marked as optional (omitempty) in type definition
Non-Breaking Change: Additive change that doesn't break existing functionality
Logging for Observability: Operator logs include email for debugging (needs PII fix)
MCP Configuration: Correctly wires environment variable to Google Workspace MCP


Recommendations

Priority 1 (Must Fix Before Merge)

  1. Fix email logging - Redact PII in operator logs (Blocker Outcome: Reduce Refinement Time with agent System #1)
  2. Use type-safe access - Replace type assertion with unstructured.NestedString (Blocker Epic: RAT Architecture & Design #2)
  3. Remove hardcoded fallback - Don't set invalid default email (Critical Epic: Data Source Integration #3)

Priority 2 (Should Fix Before Merge)

  1. Improve email fallback - Only use userID if it contains @ (Critical Epic: AI Agent Development #4)
  2. Add test coverage - Test email propagation (Major Epic: Jira Integration & Workflow #5)
  3. Validate email format - Use net/mail.ParseAddress (Major Test: Automation Workflow Validation #7)

Priority 3 (Nice to Have)

  1. Add documentation - Comment why email is needed (Minor Test: Updated Workflow Validation #8)
  2. Document env var - Update runner README (Minor Bump actions/checkout from 4 to 5 #10)
  3. Fix log levels - Use WARNING for missing email (Major Epic: Testing & Validation #6)

Security Checklist Review

Based on .claude/context/security-standards.md:

  • PII in logs: Email logged in plaintext (line 997)
  • Input validation: Email extracted from trusted header
  • Token handling: No token exposure issues
  • ⚠️ Type safety: Direct type assertion used (should use helpers)
  • RBAC: No RBAC bypass concerns
  • Container security: No container security changes

Code Quality Checklist

Based on CLAUDE.md backend standards:

  • Authentication: Uses existing user context
  • Error handling: Follows error patterns (needs improvement)
  • Token security: Email is PII and should be redacted in logs
  • ⚠️ Type safety: Needs unstructured.Nested* helpers
  • Package organization: Changes in appropriate files
  • Tests: No test coverage added
  • Code formatting: Go code properly formatted

Files Changed Analysis

  1. components/backend/handlers/sessions.go (14 additions)

    • ✅ Extracts email from Gin context
    • ⚠️ Fallback logic could be improved
    • ✅ Adds email to userContext
  2. components/backend/types/common.go (1 addition)

    • ✅ Adds Email field to UserContext
    • ✅ Properly marked as optional
  3. components/operator/internal/handlers/sessions.go (9 additions, 1 deletion)

    • ❌ Email logged in plaintext (PII violation)
    • ❌ Direct type assertion instead of type-safe helper
    • ✅ Passes email as environment variable
  4. components/runners/claude-code-runner/.mcp.json (2 additions, 1 deletion)

    • ✅ Wires env var to Google Workspace MCP
  5. components/runners/claude-code-runner/adapter.py (7 additions)

    • ❌ Hardcoded fallback to invalid email
    • ⚠️ INFO log level should be WARNING

Suggested Fixes

Fix 1: Redact Email in Logs (Blocker)

- log.Printf("Session %s initiated by user: %s (userId: %s, email: %s)", name, userName, userID, userEmail)
+ log.Printf("Session %s initiated by user: %s (userId: %s, emailSet: %v)", name, userName, userID, userEmail != "")

Fix 2: Type-Safe Access (Blocker)

- if v, ok := userContext["email"].(string); ok {
-     userEmail = strings.TrimSpace(v)
- }
+ if email, found, err := unstructured.NestedString(spec, "userContext", "email"); found && err == nil {
+     userEmail = strings.TrimSpace(email)
+ }

Fix 3: Remove Invalid Default (Critical)

- if not os.getenv("USER_GOOGLE_EMAIL"):
-     os.environ["USER_GOOGLE_EMAIL"] = "user@example.com"
-     logger.info("USER_GOOGLE_EMAIL not set, using default: user@example.com")
- else:
-     logger.info(f"USER_GOOGLE_EMAIL set to: {os.getenv('USER_GOOGLE_EMAIL')}")
+ if not os.getenv("USER_GOOGLE_EMAIL"):
+     logger.warning("USER_GOOGLE_EMAIL not set - Google Workspace MCP may not function correctly")
+ else:
+     logger.info(f"USER_GOOGLE_EMAIL configured (length: {len(os.getenv('USER_GOOGLE_EMAIL'))})")

Fix 4: Improve Email Fallback (Critical)

- if email == "" {
-     email = uid
- }
+ if email == "" && strings.Contains(uid, "@") {
+     email = uid
+     log.Printf("Using userID as email for user %s", uid)
+ }

Recommendation: Address blocker issues #1 and #2, and critical issue #3 before merging. The other issues can be addressed in follow-up PRs, but would strengthen the implementation if fixed now.


🔍 View AI decision process (logs available for 90 days)

📋 View memory system files loaded (click to expand)

What Amber Loaded for Code Review

Amber automatically loaded these repository standards from the memory system:

  1. CLAUDE.md - Master project instructions, development standards
  2. backend-development.md - Go backend, K8s integration patterns
  3. frontend-development.md - NextJS, Shadcn UI, React Query patterns
  4. security-standards.md - Auth, RBAC, token handling
  5. k8s-client-usage.md - User token vs service account patterns
  6. error-handling.md - Consistent error patterns
  7. react-query-usage.md - Data fetching patterns

Impact: This review used your repository's specific code quality standards, security patterns, and best practices from the memory system (PRs #359, #360) - not just generic code review guidelines.

@MichaelClifford MichaelClifford force-pushed the google-mcp-add-user-email branch from b6d3857 to 70d694c Compare December 19, 2025 19:53
@github-actions
Copy link
Contributor

github-actions bot commented Dec 19, 2025

Claude Code Review

Summary

This PR adds user email propagation through the entire vTeam stack to enable Google Workspace MCP integration. The implementation extracts email from X-Forwarded-Email header, stores it in the AgenticSession userContext, and passes it to the Claude Code runner as USER_GOOGLE_EMAIL environment variable.

Overall Assessment: ✅ APPROVED WITH MINOR RECOMMENDATIONS

The implementation follows established patterns from CLAUDE.md and context files. Security and architectural standards are maintained. Minor improvements recommended for robustness.


Issues by Severity

🚫 Blocker Issues

None - PR is ready to merge.


🔴 Critical Issues

None


🟡 Major Issues

1. Email Logging in Operator May Contain PII

Location: components/operator/internal/handlers/sessions.go:997

log.Printf("Session %s initiated by user: %s (userId: %s, email: %s)", name, userName, userID, userEmail)

Issue: Logging user email addresses may violate privacy policies or data protection regulations (GDPR, CCPA). While useful for debugging, emails are PII that should be handled carefully.

Recommendation:

  • Either remove email from the log message
  • Or redact/hash it for privacy: log.Printf("Session %s initiated by user: %s (userId: %s, emailLen: %d)", name, userName, userID, len(userEmail))
  • Consider using structured logging with a privacy-aware log processor

Justification: Backend already redacts tokens (server/server.go:22-34). Email PII should follow similar privacy standards.


2. Missing Email Validation

Location: components/backend/handlers/sessions.go:668-677

if v, ok := c.Get("userEmail"); ok {
    if s, ok2 := v.(string); ok2 {
        email = strings.TrimSpace(s)
    }
}

Issue: Email extracted from X-Forwarded-Email header is not validated. Malformed or malicious email values could be passed through to Google MCP.

Recommendation: Add basic email validation

if v, ok := c.Get("userEmail"); ok {
    if s, ok2 := v.(string); ok2 {
        email = strings.TrimSpace(s)
        // Basic email validation
        if email != "" && !isValidEmail(email) {
            log.Printf("Warning: Invalid email format from X-Forwarded-Email: %s", email)
            email = "" // Clear invalid email
        }
    }
}

Add helper function:

func isValidEmail(email string) bool {
    // Basic RFC 5322 validation
    const emailRegex = `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
    matched, _ := regexp.MatchString(emailRegex, email)
    return matched
}

Justification: Input validation is a security best practice (security-standards.md). Even trusted headers should be validated.


🔵 Minor Issues

1. Type Definition Could Be More Precise

Location: components/backend/types/common.go:15

Email string `json:"email,omitempty"`

Observation: Field is defined as omitempty but backend code always sets a value (fallback to userID). The field will never be empty in practice.

Recommendation: Either:

  • Remove omitempty tag since email is always populated
  • Or make the fallback behavior explicit in comments
Email string `json:"email"` // Always populated; falls back to userId if X-Forwarded-Email not present

2. Environment Variable Documentation Missing

Location: components/operator/internal/handlers/sessions.go:1136

Issue: New USER_GOOGLE_EMAIL environment variable is not documented in:

  • Component README
  • CLAUDE.md environment variable reference
  • Deployment documentation

Recommendation: Add documentation in components/runners/claude-code-runner/README.md:

### Environment Variables

- `USER_GOOGLE_EMAIL`: User's email address for Google Workspace MCP operations (defaults to user@example.com if not set)

3. Consistency: Email Fallback Pattern

Observation:

  • Backend falls back to userId if email is missing (sessions.go:674-677)
  • Operator falls back to "user@example.com" if email is missing (sessions.go:1116-1119)
  • Adapter also sets "user@example.com" default (adapter.py:88)

Recommendation: Document this fallback strategy in code comments to explain why different defaults exist:

// Fallback to userID if no explicit email (userID is often the email in OAuth/OIDC)
// This provides a best-effort email for upstream identity propagation
if email == "" {
    email = uid
}
// Determine Google email: use userEmail from session context if available
// Otherwise default to placeholder (Google MCP will require valid email for actual operations)
googleEmail := "user@example.com"
if userEmail != "" {
    googleEmail = userEmail
}

Positive Highlights

Excellent Pattern Adherence

  1. Type-Safe Context Extraction (backend/sessions.go:669-672)

    • Proper two-step type assertion with ok checks
    • Follows k8s-client-usage.md patterns
  2. Security: No Token/Email Leaks (mostly)

    • Email is not logged in backend handlers
    • Environment variables properly scoped to Job pods
    • Follows established token redaction patterns
  3. Graceful Fallback Handling

    • Backend fallback: email = uid (sensible default)
    • Operator fallback: user@example.com (safe default)
    • Adapter fallback: documented and logged
  4. Consistent Architecture

  5. MCP Integration Standards

    • Properly passes environment variable to .mcp.json
    • Follows established pattern from GOOGLE_OAUTH_CLIENT_ID/SECRET
  6. Clean Code

    • Proper use of strings.TrimSpace
    • Type-safe unstructured access in operator
    • No panic() or unsafe type assertions

Recommendations

High Priority

  1. 🟡 Add email validation in backend handler (see Major Issue Epic: RAT Architecture & Design #2)
  2. 🟡 Redact or remove email from operator log (see Major Issue Outcome: Reduce Refinement Time with agent System #1)

Medium Priority

  1. 🔵 Document USER_GOOGLE_EMAIL in runner README
  2. 🔵 Clarify omitempty tag in UserContext type

Low Priority

  1. 🔵 Add inline comments explaining fallback strategy differences

Pre-Commit Checklist Status

Based on CLAUDE.md standards:

Backend Checklist

  • Authentication: N/A (no client changes)
  • Authorization: N/A (no RBAC changes)
  • Error Handling: All errors logged with context
  • ⚠️ Token Security: Email in logs needs review (operator)
  • Type Safety: Used proper two-step assertions
  • Resource Cleanup: N/A (no resource changes)
  • Status Updates: N/A (no status changes)
  • Tests: No test updates (acceptable for additive change)
  • Logging: Structured logs with context
  • Code Quality: Linting status unknown (run locally)

Run Before Merge

cd components/backend && gofmt -l . && go vet ./... && golangci-lint run
cd components/operator && gofmt -l . && go vet ./... && golangci-lint run

Final Recommendation

APPROVE - Merge after addressing email logging (Major Issue #1) and email validation (Major Issue #2)

The PR successfully extends user context propagation to support Google Workspace MCP integration. The implementation is architecturally sound and follows established patterns. The recommended changes enhance security and robustness but are not blockers for merge.

Suggested merge timeline: After addressing the 2 major issues (estimated: 15 minutes of changes).


🔍 View AI decision process (logs available for 90 days)

📋 View memory system files loaded (click to expand)

What Amber Loaded for Code Review

Amber automatically loaded these repository standards from the memory system:

  1. CLAUDE.md - Master project instructions, development standards
  2. backend-development.md - Go backend, K8s integration patterns
  3. frontend-development.md - NextJS, Shadcn UI, React Query patterns
  4. security-standards.md - Auth, RBAC, token handling
  5. k8s-client-usage.md - User token vs service account patterns
  6. error-handling.md - Consistent error patterns
  7. react-query-usage.md - Data fetching patterns

Impact: This review used your repository's specific code quality standards, security patterns, and best practices from the memory system (PRs #359, #360) - not just generic code review guidelines.

Signed-off-by: Michael Clifford <mcliffor@redhat.com>
@MichaelClifford MichaelClifford force-pushed the google-mcp-add-user-email branch from 70d694c to 627a91d Compare December 19, 2025 22:01
@github-actions
Copy link
Contributor

github-actions bot commented Dec 19, 2025

Claude Code Review

Summary

This PR adds user email support to the Google MCP (Model Context Protocol) integration. It extracts user email from Google OAuth responses and propagates it through the system (backend → operator → runner) to enable Google Workspace MCP tools that require user email for delegation.

Overall Assessment: Good implementation with solid security practices. There are a few critical security issues and several improvements needed before merge.


Issues by Severity

🚫 Blocker Issues

1. Security: Email logged in plaintext (oauth.go:309)

log.Printf("Fetched user email from Google OAuth: %s", userEmail)
  • Issue: User email is PII (Personally Identifiable Information) and should not be logged in plaintext
  • Fix: Redact or hash the email in logs, or remove the log statement entirely
  • Standard: See security-standards.md section on token/PII redaction

2. Security: Email logged in plaintext (oauth.go:787, 804)

log.Printf("✓ Updated OAuth credentials Secret %s/%s (email: %s)", projectName, secretName, userEmail)
log.Printf("✓ Created OAuth credentials Secret %s/%s (email: %s)", projectName, secretName, userEmail)
  • Issue: Same PII logging issue
  • Fix: Remove email from log messages or use len(userEmail) pattern
  • Example: log.Printf("✓ Created OAuth credentials Secret %s/%s (email: %d chars)", projectName, secretName, len(userEmail))

3. Security: Email logged in plaintext (operator/sessions.go:997, 1127, 1133)

log.Printf("Session %s initiated by user: %s (userId: %s, email: %s)", name, userName, userID, userEmail)
log.Printf("Using Google email from OAuth secret for session %s: %s", name, googleEmail)
log.Printf("Using Google email from session userContext for session %s: %s", name, googleEmail)
  • Issue: Multiple instances of email logging
  • Fix: Redact or remove email from all log statements

🔴 Critical Issues

1. Error Handling: Non-fatal error treated as warning (oauth.go:305-310)

if err != nil {
    log.Printf("Warning: Failed to fetch user email from Google: %v", err)
} else {
    userEmail = email
    log.Printf("Fetched user email from Google OAuth: %s", userEmail)
}
  • Issue: The code continues with empty userEmail on error, but downstream code in operator expects a valid email
  • Risk: If Google API fails, Google Workspace MCP will use "user@example.com" default, which may not be the expected behavior
  • Recommendation: Document this fallback behavior or add observability metric for tracking email fetch failures

2. Type Safety: Missing error check (adapter.py:1564)

email = secret_email_path.read_text().strip()
if email and email != "user@example.com":
    # ...
  • Issue: read_text() can raise IOError, PermissionError, etc., but code is not in try/except block for the read operation itself
  • Current: Only outer function is wrapped in try/except
  • Recommendation: While acceptable, consider more granular error handling for the file read vs. JSON parsing

3. Documentation: Missing docstring context (oauth.go:413-418)

// GoogleUserInfo represents the minimal user info response from Google (email only)
type GoogleUserInfo struct {
    Email         string `json:"email"`
    VerifiedEmail bool   `json:"verified_email"`
}
  • Issue: Struct has VerifiedEmail field but it's never checked or used
  • Recommendation: Either use verified_email to validate email is verified, or remove the field if not needed
  • Security consideration: Should we reject unverified emails?

🟡 Major Issues

1. Code Pattern: Inconsistent email extraction logic (sessions.go:667-677)

// Extract email from authenticated user
email := ""
if v, ok := c.Get("userEmail"); ok {
    if s, ok2 := v.(string); ok2 {
        email = strings.TrimSpace(s)
    }
}
// Fallback to userID if no explicit email (userID is often the email)
if email == "" {
    email = uid
}
  • Issue: Assumes uid is a valid email format, but uid could be a username, GUID, or other identifier
  • Recommendation: Add email format validation or document this assumption clearly
  • Pattern from CLAUDE.md: Input validation should check format constraints

2. Complexity: Three-tier email priority logic (operator/sessions.go:1114-1136)
The email priority logic is correct but complex:

  1. OAuth secret user_email field
  2. Session userContext email
  3. Default "user@example.com"
  • Issue: This logic is duplicated in adapter.py with slightly different behavior
  • Recommendation: Consider documenting this priority in a comment or ADR
  • Alternative: Could this be simplified by always requiring email in userContext?

3. Race Condition Risk: Secret read without retry (operator/sessions.go:1123)

if oauthSecret, err := config.K8sClient.CoreV1().Secrets(sessionNamespace).Get(context.TODO(), googleOAuthSecretName, v1.GetOptions{}); err == nil {
  • Issue: OAuth flow may complete after Job creation starts, causing email to not be available at Job creation time
  • Current mitigation: Runner has refresh_google_credentials() which handles this
  • Recommendation: Document this timing dependency in a comment

🔵 Minor Issues

1. Naming: Variable shadowing (oauth.go:305)

email, err := fetchGoogleUserEmail(c.Request.Context(), tokenData.AccessToken)
if err != nil {
    log.Printf("Warning: Failed to fetch user email from Google: %v", err)
} else {
    userEmail = email
  • Issue: email variable shadows potential outer scope, then assigned to userEmail
  • Recommendation: Use userEmail directly: userEmail, err := fetchGoogleUserEmail(...)

2. Code Style: Context usage (oauth.go:421)

req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://www.googleapis.com/oauth2/v2/userinfo", nil)
  • Good: Uses context correctly
  • Minor: Consider adding timeout to context (already has HTTP client timeout, so acceptable as-is)

3. Testing: Missing test coverage

  • Issue: No tests for fetchGoogleUserEmail, email extraction logic, or fallback behavior
  • Recommendation: Add unit tests for:
    • fetchGoogleUserEmail success/failure cases
    • Email extraction from session creation
    • Email priority logic in operator
    • Email update in adapter.py

4. Documentation: Missing comments for new behavior

  • File: .mcp.json
  • Issue: New USER_GOOGLE_EMAIL env var not documented
  • Recommendation: Add comment explaining this is for Google Workspace delegation

Positive Highlights

Excellent error handling in fetchGoogleUserEmail

  • Proper context usage
  • HTTP timeout set
  • Body drained with defer resp.Body.Close()
  • Non-2xx status codes handled correctly

Good defensive coding in adapter.py

  • Checks for existing credentials before updating
  • Handles missing/malformed JSON gracefully
  • Proper file modification time comparison for credential refresh

Proper type safety

  • Uses type assertions with ok checks consistently
  • unstructured.NestedMap used correctly in operator

Security: OAuth secret properly mounted

  • Credentials stored in Kubernetes Secret (not logs or env vars)
  • Secret ownership via OwnerReferences ensures cleanup

Good separation of concerns

  • Backend handles OAuth token exchange
  • Operator manages Job creation with email config
  • Runner handles credential refresh and environment updates

Recommendations

Prioritized Action Items

Must Fix (Blockers):

  1. ❌ Remove all plaintext email logging (7 instances total)
    • oauth.go:309, 787, 804
    • operator/sessions.go:997, 1127, 1133
    • Use: log.Printf("Email configured (len=%d)", len(email)) or remove entirely

Should Fix (Critical):
2. ⚠️ Decide on VerifiedEmail field usage

  • Either check verified_email == true before accepting email
  • Or remove the unused field from GoogleUserInfo
  1. ⚠️ Add email format validation in sessions.go:676
    • Don't blindly use uid as email fallback
    • Validate format or document assumption

Nice to Have (Major):
4. 📝 Document email priority logic in code comments
5. 🧪 Add test coverage for new email extraction logic
6. 📝 Add comment explaining OAuth timing and credential refresh flow

Code Quality Improvements

// oauth.go:305 - Fix variable shadowing
userEmail, err := fetchGoogleUserEmail(c.Request.Context(), tokenData.AccessToken)
if err != nil {
    log.Printf("Warning: Failed to fetch Google user email: %v", err)
    userEmail = "" // Explicitly clear on error
}

// oauth.go:434 - Consider validating verified_email
if userInfo.Email == "" {
    return "", fmt.Errorf("no email in user info response")
}
if !userInfo.VerifiedEmail {
    return "", fmt.Errorf("email not verified by Google")
}

Security Checklist Results

Based on security-standards.md:

  • Authentication: Uses user token properly (not part of this PR)
  • Authorization: No RBAC changes (not applicable)
  • Secrets & Tokens: Email (PII) logged in plaintext - MUST FIX
  • ⚠️ Input Validation: Email format not validated - SHOULD FIX
  • Container Security: No SecurityContext changes (not applicable)

Conclusion

This is a well-structured PR that follows the project's architectural patterns. The main concerns are:

  1. PII logging (blocker - must fix before merge)
  2. Input validation for email format
  3. Test coverage for new logic

Once the logging issues are resolved, this PR will be ready to merge. The implementation correctly propagates user email through the system and handles the OAuth timing dependencies appropriately.


🔍 View AI decision process (logs available for 90 days)

📋 View memory system files loaded (click to expand)

What Amber Loaded for Code Review

Amber automatically loaded these repository standards from the memory system:

  1. CLAUDE.md - Master project instructions, development standards
  2. backend-development.md - Go backend, K8s integration patterns
  3. frontend-development.md - NextJS, Shadcn UI, React Query patterns
  4. security-standards.md - Auth, RBAC, token handling
  5. k8s-client-usage.md - User token vs service account patterns
  6. error-handling.md - Consistent error patterns
  7. react-query-usage.md - Data fetching patterns

Impact: This review used your repository's specific code quality standards, security patterns, and best practices from the memory system (PRs #359, #360) - not just generic code review guidelines.

@MichaelClifford MichaelClifford changed the title add user email to google mcp WIP: add user email to google mcp Dec 19, 2025
@MichaelClifford MichaelClifford marked this pull request as draft December 19, 2025 22:17
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.

1 participant