# Barème **Points minimum:** -1 **Points maximum:** 10 Chaque question à choix multiple offre 1 point par bonne case cochée mais 0 points si une mauvaise case a été cochée. Les points négatifs sont additionnés après ce calcul. Le total de point offert par une question ne dépasse jamais son maximum disponible. # Docker Vous êtes en charge de l'infrastructure serveur d'une API Python. Malin comme vous êtes, vous utilisez Docker pour gérer cette infrastructure. Le code source de l'API vit dans un unique fichier `main.py` qui est containerisé à l'aide d'un Dockerfile et d'un docker-compose. L'ensemble de ce code est versionné sur GitHub de manière publique. La structure de fichier est comme suit: ``` API/ ├─ src/ │ ├─ main.py ├─ Dockerfile ├─ docker-compose.yaml ├─ .gitignore ``` ### Exercice 1 #### 1 point Les développeur.euse.s de l'API viennent vous voir en disant qu'iels aimeraient bien changer leur version de Python actuelle (3.7) à la version 3.10. Quel(s) fichier(s) devez-vous éditer afin de satisfaire leur besoin ? - [ ] main.py - [x] Dockerfile - [ ] docker-compose.yaml - [ ] .gitignore ### Exercice 2 #### 1 point max. La nouvelle version de l'API doit pouvoir être testée sur l'infrastructure sans intérferer avec l'API en production. Vous devez donc mettre en place un nouveau container pour l'API de test qui s'accède par un port différent que celui utilisé pour l'API en production. Le port mapping de l'API de production est `8000:8000` et le nom de l'image est `api-image`. Quel(s) fichier(s) éditez vous ? - [ ] main.py - [ ] Dockerfile - [x] docker-compose.yaml - [ ] .gitignore - [x] Je n'édite aucun fichier et utilise à la place la ligne de commande suivante: `docker run -p 8001:8000 api-image` ### Exercice 3 #### 2 points max. Afin d'éviter de polluer la base de donnée de production avec les tests, vous avez décidé de créer un nouveau container pour la base de donnée. Ce container doit être similaire en tout point à la production avec les conditions suivantes: - Cette nouvelle base de donnée ne doit en aucun cas interférer avec la production. - Les données qui y sont stockées doivent être détruites entre chaque lancement de test pour assurer leur bon fonctionnement. - L'API de test s'y connecte via le port 9876. Sachant que: - Les containers sont détruits et recréés entre chaque test. - Le container de production est décrit de la manière suivante: ```yaml services:   prod-db:     image: postgres:16     ports:       - 5432:5432     environment:       - POSTGRES_USER=postgres       - POSTGRES_PASSWORD=verysecurepassword       - POSTGRES_DB=yougotthis     volumes:       - prod-db-data:/var/lib/postgresql/data volumes:   prod-db-data: ``` Vous décidez de dupliquer la configuration ci-dessus pour créer le nouveau container de la base de donnée de test que vous appellez `test-db`. Quelles étapes devez-vous effectuer pour que le nouveau container respecte les conditions ci-dessus ? - [ ] Vous changez la version de l'image pour `postgres:latest` - [ ] Vous changez le port mapping pour `9876:9876` - [x] Vous changez le port mapping pour `9876:5432` - [ ] Vous supprimez les variables d'environnement - [ ] Vous changez le volume mapping du container pour `./src/:/var/lib/postgresql/data` - [ ] Vous changez le volume mapping du container pour `test-db-data:/var/lib/postgresql/data` et ajoutez `test-db-data` dans la définition des volumes en bas du fichier - [x] Vous supprimez le volume mapping du container - [ ] Vous supprimer la définition du volume `prod-db-data` en bas du fichier- _-1 point si coché_ ### Exercice 4 #### 2 point max. Le responsable sécurité est venu vous voir pour vous demander d'arrêter de mettre en clair des informations sensibles dans vos fichiers et de les mettre dans un fichier `.env`, ou quelque chose du genre. Vous n'avez pas écouté jusqu'au bout mais vous avez hoché la tête donc vous êtes légalement obligé de faire quelque chose. Vous créez donc un fichier `.env` à la racine de votre projet qui ressemble à ça: ``` DB_USER=postgres DB_PASSWORD=verysecurepassword DB_NAME=yougotthis ``` La structure de fichier est à présent comme suit: ``` API/ ├─ src/ │ ├─ main.py ├─ Dockerfile ├─ docker-compose.yaml ├─ .env ├─ .gitignore ``` Quel(s) autre(s) fichier(s) devez-vous modifier pour éviter de revoir le responsable sécurité prochainement ? - [ ] main.py - [ ] Dockerfile - [x] docker-compose.yaml - [x] .gitignore # Backend La faille de sécurité a malheureusement pu être exploitée par un hacker du nom de `@jayjay15` le jeudi 17 avril 2025. Apparemment, le hacker aurait rempli la base de donnée de clowns. Les développer.euse.s de l'API sont en panique parce que les serveurs de ChatGPT sont surchargés, vous êtes le dernier espoir de l'entreprise pour sauver ce qui lui reste de données. L'entreprise utilise l'ORM Peewee pour contrôler sa base de donnée et le model qui nous intéresse est défini comme suit: ```python from datetime import date class User(Model): name = CharField() # Nom d'utilisateur date_created = DateField() # Date de création du compte ``` On vous demande donc le code Python nécessaire pour effectuer les actions suivantes. ### Exercice 5 #### 1 point max. Vous devez `print` toutes les instances de `User` dont le nom est égal à "clown". **Réponse** ```python for user in User.select().where(User.name == "clown"): print(user) ``` ### Exercice 6 #### 1 point max. On a de bonne raison de penser que l'utilisateur a créé un compte dans la base de donnée juste avant l'attaque. Il faudrait récupérer le `User` dont la date de création du compte correspond à la date de l'attaque afin de pouvoir le retrouver. **Option 1** ```python hacker = User.get(User.date_created=date(2025, 4, 17)) ``` **Option 2** ```python hacker = User.select().where(User.date_created=date(2025, 4, 17)).get() ``` ### Exercice 7 #### 2 point max. Vous devez à présent supprimer toutes les instances de `User` dont le nom est égal à "clown". Bonus si vous le faites en une seule ligne. **Option 1** - _1 point_ ```python for user in User.select().where(User.name == "clown"): user.delete_instance() ``` **Option 2** - _2 points_ ```python [user.delete_instance() for user in User.select().where(User.name == "clown")] ``` **Option 3** - _2 points_ ```python User.delete().where(User.name == "clown") ```