10 Tests, sécurité et qualité du code

Bugs, sécurité et performance

10.7 Détection de bugs avec Copilot 🐛

Définition

Copilot peut aider à identifier des bugs dans :

  • fonctions ;
  • services ;
  • tests ;
  • endpoints ;
  • scripts ;
  • configurations ;
  • logique métier ;
  • gestion d’erreur.

Exemple bug Python

Code volontairement bugué :

pyRisque à vérifier
def add_item(item, items=[]):
    items.append(item)
    return items

Prompt :

Texte
Review this function for bugs and explain the issue.

Copilot devrait signaler :

L’argument par défaut mutable [] est partagé entre les appels.

Correction :

pyCorrection proposée
def add_item(item, items=None):
    if items is None:
        items = []

    items.append(item)
    return items

Test :

pyTest proposé
def test_add_item_does_not_share_default_list():
    first = add_item("a")
    second = add_item("b")

    assert first == ["a"]
    assert second == ["b"]

Ce test échoue avec la version bugguée : les deux appels partagent la même liste, donc first vaut aussi ["a", "b"]. Il réussit avec la version corrigée. C’est un test de régression : il échoue avant la correction et réussit après.

Exemple bug JavaScript

Code volontairement bugué :

jsRisque à vérifier
function isAdult(age) {
  return age > 18;
}

Prompt :

Texte
Review this function for boundary issues.

Copilot peut signaler :

Si l’âge légal adulte est 18, la condition devrait probablement être age >= 18.

C’est une hypothèse à confirmer avec la règle métier : Copilot ne sait pas quel âge ton produit retient.

Correction :

jsCorrection proposée
function isAdult(age) {
  return age >= 18;
}

Test :

jsTest proposé
expect(isAdult(18)).toBe(true);

Exemple bug API

Code volontairement incomplet :

jsRisque à vérifier
app.get("/users/:id", async (req, res) => {
  const user = await userService.findById(req.params.id);
  res.json(user);
});

Problèmes possibles :

  • pas de gestion not found ;
  • pas de validation de l’ID ;
  • pas de gestion d’erreur ;
  • pas d’autorisation ;
  • risque d’exposition de champs sensibles.

Prompt :

Texte
Review this route for correctness, security, and missing error handling.
Suggest minimal fixes and tests.

Bon prompt bug detection

Texte
Analyze the selected code for bugs.

Focus on:
- boundary conditions
- null or undefined values
- error handling
- async behavior
- incorrect assumptions
- security-sensitive logic

Return:
- bug
- why it happens
- minimal fix
- test to prevent regression

Piège d’examen

Une explication de bug donnée par Copilot est une hypothèse, pas une preuve. Elle se confirme avec un test qui échoue avant la correction et réussit après, et avec la règle métier. Une explication assurée peut être fausse.

À retenir

Copilot est utile pour trouver des bugs probables, mais il faut confirmer avec des tests et une compréhension métier.

10.8 Suggestions de sécurité 🔐

Définition

Copilot peut aider à identifier et corriger des problèmes de sécurité dans le code.

Exemples :

  • injection SQL ;
  • XSS ;
  • auth manquante ;
  • autorisation manquante ;
  • secrets hardcodés ;
  • logs sensibles ;
  • permissions trop larges ;
  • validation insuffisante ;
  • mauvaise gestion d’erreur ;
  • dépendances obsolètes ;
  • hashing faible.

Pour le GH-300

Les exemples de cette section sont volontairement vulnérables. Ils ne servent pas à apprendre une attaque : le GH-300 ne te demande pas de connaître une faille par cœur. Il te demande comment utiliser Copilot pour repérer le problème, demander une alternative plus sûre, générer un test de sécurité et valider la correction proposée.

Exemple SQL injection

Code dangereux :

PythonRisque à vérifier
query = f"SELECT * FROM users WHERE email = '{email}'"

Prompt :

Texte
Review this database query for security issues and propose a safer implementation.

Correction :

PythonCorrection proposée
cursor.execute(
    "SELECT * FROM users WHERE email = %s",
    (email,)
)

Exemple authorization manquante

Code volontairement non sécurisé :

jsRisque à vérifier
app.get("/admin/users", async (req, res) => {
  const users = await userService.getAllUsers();
  res.json(users);
});

Prompt :

Texte
Review this Express route for authentication and authorization issues.

Copilot devrait signaler :

Texte
La route expose probablement tous les utilisateurs sans vérifier que le requester est admin.

Correction conceptuelle :

jsCorrection proposée
app.get("/admin/users", authenticate, requireRole("admin"), async (req, res) => {
  const users = await userService.getAllUsers();
  res.json(users);
});

Exemple secrets

Mauvais code :

jsRisque à vérifier
const apiKey = "prod_123456789";

Prompt :

Texte
Review this code for secret management issues.

Correction :

jsCorrection proposée
const apiKey = process.env.API_KEY;

if (!apiKey) {
  throw new Error("API_KEY is required");
}

Si la clé a déjà été poussée dans un dépôt partagé, la retirer du code ne suffit pas : elle doit être renouvelée.

Exemple logs sensibles

Code volontairement non sécurisé :

jsRisque à vérifier
logger.info("User login failed", {
  email,
  password
});

Correction :

jsCorrection proposée
logger.info("User login failed", {
  email
});

Ne jamais logger :

  • mots de passe ;
  • tokens ;
  • clés API ;
  • secrets ;
  • données personnelles sensibles.

Bon prompt sécurité

Texte
Review the selected code for security issues.

Focus on:
- authentication
- authorization
- input validation
- injection
- secrets
- sensitive logging
- error messages
- least privilege

Return:
- issue
- severity
- explanation
- recommended fix
- test to prevent regression

Valider la correction proposée

Une correction de sécurité proposée par Copilot se valide comme n’importe quelle suggestion :

  • relire la modification (le diff) et comprendre ce qui change ;
  • relancer les tests existants et ajouter un test de non-régression sécurité ;
  • vérifier que le comportement attendu est préservé ;
  • laisser les outils du dépôt confirmer (analyse statique, détection de secrets, analyse des dépendances) ;
  • demander une relecture humaine pour les zones sensibles.

Piège d’examen

Copilot peut aider, mais il ne remplace pas :

  • SAST ;
  • secret scanning ;
  • dependency scanning ;
  • pentest ;
  • threat modeling ;
  • review sécurité ;
  • règles internes.

À retenir

Copilot peut proposer des améliorations sécurité, mais les décisions sécurité doivent être validées avec des outils et humains compétents.

10.9 Optimisations de performance ⚡

Définition

L’optimisation de performance consiste à améliorer :

  • temps de réponse ;
  • consommation CPU ;
  • mémoire ;
  • appels réseau ;
  • requêtes DB ;
  • temps de build ;
  • complexité algorithmique ;
  • coût cloud.

Copilot peut aider à identifier des opportunités, mais il faut mesurer avant/après.

Exemple simple

Code :

Python
def find_user(users, email):
    for user in users:
        if user["email"] == email:
            return user
    return None

Si cette recherche est faite souvent sur une grande liste, Copilot peut proposer un index :

Python
def build_user_index(users):
    return {user["email"]: user for user in users}

def find_user(user_index, email):
    return user_index.get(email)

Mais ce n’est utile que si :

  • la liste est grande ;
  • les recherches sont fréquentes ;
  • le coût mémoire est acceptable ;
  • les données ne changent pas trop souvent.

Exemple DB

Code conceptuel :

ts
const users = await userRepository.findAll();

for (const user of users) {
  user.orders = await orderRepository.findByUserId(user.id);
}

Problème probable :

Texte
N+1 queries

Prompt :

Texte
Review this code for performance issues.
Focus on database query patterns and suggest a safer optimization.

Copilot peut proposer :

Texte
Fetch orders for all users in a single query and group them by userId.

Exemple amélioration :

tsCorrection proposée
const users = await userRepository.findAll();
const userIds = users.map(user => user.id);

const orders = await orderRepository.findByUserIds(userIds);
const ordersByUserId = groupBy(orders, order => order.userId);

return users.map(user => ({
  ...user,
  orders: ordersByUserId[user.id] ?? []
}));

Prompt performance

Texte
Analyze this code for performance issues.

Focus on:
- algorithmic complexity
- repeated database queries
- unnecessary network calls
- memory usage
- caching opportunities
- trade-offs

Suggest optimizations and explain risks.
Do not change behavior.

Piège d’examen

Optimiser sans mesurer est un piège classique : Copilot peut proposer une optimisation plausible sans garantir qu’elle améliore quoi que ce soit.

Mauvais réflexe :

Texte
Optimize everything.

Meilleur réflexe :

Texte
Identify likely bottlenecks and suggest measurable optimizations.

Bonnes pratiques

Toujours :

  • mesurer avant/après (Copilot peut aider à proposer un test de performance ou une mesure) ;
  • préserver le comportement ;
  • ajouter des tests ;
  • vérifier les effets de bord ;
  • éviter le cache dangereux ;
  • surveiller la cohérence des données.

À retenir

Copilot peut suggérer des optimisations, mais les performances doivent être mesurées.

10.10 Cas d’examen : tester, sécuriser ou refactorer ? 🧪🔐🛠️

Cette section est très importante.

L’examen peut présenter une situation et demander la meilleure action.

Tableau de décision rapide

SituationMeilleure action
Fonction isolée sans testsGénérer des tests unitaires
Endpoint complet à vérifierGénérer des tests d’intégration
Comportement aux limites inconnuIdentifier edge cases
Tests trop faiblesAméliorer les assertions
Dépendance externe lente ou coûteuseUtiliser mocks/stubs
Couverture faibleAjouter tests pour branches manquantes
Bug récurrentGénérer test de régression + correction
Route sans authSécuriser avant refactor
Code vulnérable SQL injectionCorriger sécurité immédiatement
Code illisible mais fonctionnelRefactorer avec tests
Code legacy critique sans testsComprendre + ajouter tests avant refactor
Performance suspecteIdentifier bottleneck + mesurer

Cas 1 — Fonction sans tests

Scénario :

Une fonction critique calcule les remises, mais aucun test n’existe.

Bonne réponse :

Texte
Utiliser Copilot pour générer des tests unitaires couvrant cas normaux, limites et erreurs.

Cas 2 — API avec dépendances

Scénario :

Une API crée un utilisateur via controller, service et repository.

Bonne réponse :

Texte
Utiliser Copilot pour générer des tests d’intégration.

Cas 3 — Service externe

Scénario :

Un service appelle une API de paiement externe.

Bonne réponse :

Texte
Utiliser des mocks pour simuler succès, refus, timeout et erreur réseau.

Cas 4 — Bug de production

Scénario :

Un bug se produit quand la liste d’items est vide.

Bonne réponse :

Texte
Demander à Copilot de créer un test de régression pour ce cas, puis corriger le bug.

Cas 5 — SQL injection

Scénario :

Copilot détecte une requête SQL construite par concaténation de string.

Bonne réponse :

Texte
Corriger avec des requêtes paramétrées et ajouter un test sécurité si possible.

Cas 6 — Code legacy critique

Scénario :

Une équipe veut refactorer un vieux module de paiement sans tests.

Bonne réponse :

Texte
Les tests d’abord : des tests de caractérisation avant tout refactoring, comme en 9.6.

Cas 7 — Performance

Scénario :

Une page est lente à cause de nombreuses requêtes DB répétées.

Bonne réponse :

Texte
Demander à Copilot d’identifier les patterns N+1, proposer une optimisation mesurable, puis tester et mesurer.

À retenir pour le GH-300

  • Une explication de bug ou une optimisation proposée par Copilot est une hypothèse : on la confirme par un test de régression ou par une mesure avant et après.
  • Pour la sécurité, on demande une alternative plus sûre et un test, puis on valide la correction (diff, tests, outils, relecture) : Copilot ne remplace ni les outils ni la review.
  • Avant de refactorer du code vulnérable ou une route non protégée, on le sécurise d’abord.
  • Une optimisation est un compromis : Copilot ne garantit aucun gain, on préserve le comportement et on mesure.