diff --git a/.github/workflows/chat-ci.yml b/.github/workflows/chat-ci.yml index 2b2401e89..8ca2673e9 100644 --- a/.github/workflows/chat-ci.yml +++ b/.github/workflows/chat-ci.yml @@ -31,6 +31,11 @@ jobs: - name: Lint with clippy run: cargo clippy --all-targets -- -D warnings + - name: Audit dependencies + uses: actions-rust-lang/audit@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + - name: Run tests run: cargo test --all diff --git a/.github/workflows/stream-ci.yml b/.github/workflows/stream-ci.yml index a8759e9c6..5e117affd 100644 --- a/.github/workflows/stream-ci.yml +++ b/.github/workflows/stream-ci.yml @@ -31,6 +31,11 @@ jobs: - name: Lint with clippy run: cargo clippy --all-targets -- -D warnings + - name: Audit dependencies + uses: actions-rust-lang/audit@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + - name: Run tests run: cargo test --all diff --git a/AUDIT_TECHNIQUE_INTEGRAL_2026_02_15.md b/AUDIT_TECHNIQUE_INTEGRAL_2026_02_15.md index 4f5aa4653..d419e8d1b 100644 --- a/AUDIT_TECHNIQUE_INTEGRAL_2026_02_15.md +++ b/AUDIT_TECHNIQUE_INTEGRAL_2026_02_15.md @@ -655,8 +655,8 @@ veza/ | 1.5 | ~~Corriger les `.unwrap()` critiques en Rust (paths de production)~~ | **M** | `veza-stream-server/src/`, `veza-chat-server/src/` | **✅ Fait** | | 1.6 | ~~Supprimer les secrets test hardcodés~~ | **S** | `veza-chat-server/src/config.rs:216`, `jwt_manager.rs:575` | **✅ Fait** | | 1.7 | ~~Ajouter protection contre bypass flags en production~~ | **S** | `veza-backend-api/internal/middleware/auth.go`, `csrf.go` | **✅ Fait** | -| 1.8 | Implémenter OAuth user lookup | **M** | `veza-backend-api/internal/database/database.go:559` | P1 | -| 1.9 | Ajouter `cargo audit` au CI | **S** | `.github/workflows/chat-ci.yml`, `stream-ci.yml` | P2 | +| 1.8 | ~~Implémenter OAuth user lookup~~ | **M** | `veza-backend-api/internal/database/database.go:559` | **✅ Fait** | +| 1.9 | ~~Ajouter `cargo audit` au CI~~ | **S** | `.github/workflows/chat-ci.yml`, `stream-ci.yml` | **✅ Fait** | ### Phase 2 — STABILISATION (4-6 semaines) diff --git a/veza-backend-api/internal/database/database.go b/veza-backend-api/internal/database/database.go index 2555dc3bd..1e8dce21c 100644 --- a/veza-backend-api/internal/database/database.go +++ b/veza-backend-api/internal/database/database.go @@ -554,10 +554,25 @@ func (d *Database) Stats() sql.DBStats { return d.DB.Stats() } -// GetUserByOAuthID récupère un utilisateur par son OAuth ID et provider +// GetUserByOAuthID récupère un utilisateur par son OAuth ID et provider (audit 1.8) func (d *Database) GetUserByOAuthID(oauthID, provider string) (*models.User, error) { - // TODO: Implémenter OAuth user lookup - return nil, fmt.Errorf("not implemented") + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + var user models.User + err := d.GormDB.WithContext(ctx).Raw(` + SELECT u.* FROM users u + INNER JOIN federated_identities fi ON fi.user_id = u.id + WHERE fi.provider = ? AND fi.provider_id = ? + LIMIT 1 + `, provider, oauthID).Scan(&user).Error + if err != nil { + return nil, err + } + if user.ID == uuid.Nil { + return nil, nil + } + return &user, nil } // CreateUser crée un nouvel utilisateur diff --git a/veza-backend-api/internal/services/oauth_service.go b/veza-backend-api/internal/services/oauth_service.go index 3fa46202d..edda973b5 100644 --- a/veza-backend-api/internal/services/oauth_service.go +++ b/veza-backend-api/internal/services/oauth_service.go @@ -241,8 +241,8 @@ func (os *OAuthService) HandleCallback(provider, code, state string) (*OAuthUser return nil, "", err } - // Check if user already exists (by provider account or email) - existingUser, err := os.getOrCreateUser(oauthUser) + // Check if user already exists (by provider account or email) — audit 1.8: OAuth ID lookup first + existingUser, err := os.getOrCreateUser(provider, oauthUser) if err != nil { return nil, "", err } @@ -394,11 +394,22 @@ func (os *OAuthService) getUserInfo(provider, accessToken string) (*OAuthUser, e return &oauthUser, nil } -// getOrCreateUser gets an existing user or creates a new one -func (os *OAuthService) getOrCreateUser(oauthUser *OAuthUser) (*OAuthUserInfo, error) { +// getOrCreateUser gets an existing user or creates a new one (audit 1.8: OAuth ID lookup first) +func (os *OAuthService) getOrCreateUser(provider string, oauthUser *OAuthUser) (*OAuthUserInfo, error) { ctx := context.Background() - // Try to find existing user by email + // Try OAuth ID lookup first to avoid duplicates when user changes email at provider + if oauthUser.ProviderID != "" { + dbUser, err := os.db.GetUserByOAuthID(oauthUser.ProviderID, provider) + if err != nil { + return nil, err + } + if dbUser != nil { + return &OAuthUserInfo{ID: dbUser.ID, Email: dbUser.Email, Username: dbUser.Username}, nil + } + } + + // Fallback: find existing user by email var user OAuthUserInfo err := os.db.QueryRowContext(ctx, ` SELECT id, email, username