fix(audit-1.8,1.9): implement OAuth user lookup, add cargo audit to CI

- 1.8: Implement GetUserByOAuthID in database.go via federated_identities join
- 1.8: Use OAuth ID lookup first in oauth_service getOrCreateUser
- 1.9: Add cargo audit step to chat-ci.yml and stream-ci.yml

Refs: AUDIT_TECHNIQUE_INTEGRAL_2026_02_15.md items 1.8, 1.9
This commit is contained in:
senke 2026-02-15 14:22:27 +01:00
parent 2e04d45a14
commit 03f626c9e8
5 changed files with 46 additions and 10 deletions

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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