Skip to content

Potential fix for code scanning alert no. 5: Clear-text storage of sensitive information#1

Draft
freedomsha wants to merge 1 commit intomasterfrom
alert-autofix-5
Draft

Potential fix for code scanning alert no. 5: Clear-text storage of sensitive information#1
freedomsha wants to merge 1 commit intomasterfrom
alert-autofix-5

Conversation

@freedomsha
Copy link
Owner

Potential fix for https://github.com/freedomsha/taskcoach/security/code-scanning/5

The best way to fix the problem is to avoid storing the password in .pypirc in clear text entirely. Modern versions of setuptools and twine allow for authentication using environment variables, keyrings, or token-based mechanisms (API tokens). Therefore:

  • General approach: Do not write the password into .pypirc. Instead, use environment variables or a keyring to pass credentials securely, if possible.
  • Detailed fix:
    • Remove the line that writes the password to .pypirc: pypirc.write('password=%s\n' % password).
    • Preferably, update code to use twine for uploads, which never requires writing passwords to disk and supports secure authentication methods. If this is not possible, instruct users to use API tokens or set credentials via environment variables (TWINE_USERNAME, TWINE_PASSWORD).
    • If file-based credentials must be used, encrypt the file's contents using a secure cryptography library (e.g., cryptography.fernet) before writing.
    • At a minimum for legacy compatibility: replace the real password with a placeholder (and update documentation to guide secure authentication for PyPI).

File to change: taskcoach/release.py
Lines to change: Remove or replace the line writing the password to .pypirc (line 539).

Requirements:

  • If removing password write, update the usage to provide credentials via secure means (document/comment the change).
  • If encryption is chosen, add import for cryptography and method to encrypt/decrypt password before writing/using.
  • Since we only see the relevant snippet, the minimum viable fix is to avoid writing the password line.

Suggested fixes powered by Copilot Autofix. Review carefully before merging.

…nsitive information

The best way to fix the problem is to avoid storing the password in .pypirc in clear text entirely. Modern versions of setuptools and twine allow for authentication using environment variables, keyrings, or token-based mechanisms (API tokens). Therefore:

    General approach: Do not write the password into .pypirc. Instead, use environment variables or a keyring to pass credentials securely, if possible.
    Detailed fix:
        Remove the line that writes the password to .pypirc: pypirc.write('password=%s\n' % password).
        Preferably, update code to use twine for uploads, which never requires writing passwords to disk and supports secure authentication methods. If this is not possible, instruct users to use API tokens or set credentials via environment variables (TWINE_USERNAME, TWINE_PASSWORD).
        If file-based credentials must be used, encrypt the file's contents using a secure cryptography library (e.g., cryptography.fernet) before writing.
        At a minimum for legacy compatibility: replace the real password with a placeholder (and update documentation to guide secure authentication for PyPI).

File to change: taskcoach/release.py
Lines to change: Remove or replace the line writing the password to .pypirc (line 539).

Requirements:

    If removing password write, update the usage to provide credentials via secure means (document/comment the change).
    If encryption is chosen, add import for cryptography and method to encrypt/decrypt password before writing/using.
    Since we only see the relevant snippet, the minimum viable fix is to avoid writing the password line.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
freedomsha added a commit that referenced this pull request Oct 31, 2025
J'ai converti listctrl.py en tkinter en utilisant la logique de itemctrl.py déjà adaptée.
La conversion est complexe car wx.ListCtrl est une classe avec des fonctionnalités avancées (colonnes, sélection, affichage virtuel) qui n'ont pas d'équivalent direct dans tkinter.

Pour cette conversion, j'ai utilisé ttk.Treeview, qui est le widget le plus proche de wx.ListCtrl et wx.TreeListCtrl.
J'ai également créé une nouvelle classe VirtualListCtrl pour encapsuler la logique de gestion des colonnes, de la sélection et du test d'accès (HitTest).

Voici le code converti, en supposant que itemctrl.py se trouve dans le même dossier ou est importable.

J'ai converti listctrl.py pour qu'il fonctionne avec Tkinter.
Voici les points clés de la conversion :

    Widget de base : Le wx.ListCtrl a été remplacé par ttk.Treeview,
                     qui est le widget le plus flexible
                     pour afficher des données en colonnes dans Tkinter.

    Fonctionnalités héritées : J'ai fait en sorte que VirtualListCtrl
                               hérite de la classe TaskList de itemctrl.py,
                               ce qui permet de réutiliser toute la logique
                               de gestion des colonnes et des menus contextuels
                               que nous avons déjà convertie.

    Gestion des événements : Les événements wxPython (wx.EVT_...) ont été remplacés
                             par des liaisons Tkinter (<Button-1>, <Double-Button-1>).

    Méthodes d'aide : Les méthodes wxPython comme curselection(), select(),
                      et clear_selection() ont été réimplémentées
                      pour utiliser les méthodes de ttk.Treeview
                      et correspondre au comportement attendu.

Le code inclut une section de test pour vous montrer comment utiliser le nouveau widget et interagir avec lui.

Voici les étapes à suivre pour compléter la conversion :
1. Comprendre la structure de listctrl.py et itemctrl.py   :

listctrl.py hérite de itemctrl.CtrlWithItemsMixin, itemctrl.CtrlWithColumnsMixin,
itemctrl.CtrlWithToolTipMixin et wx.ListCtrl .
Il utilise un wx.ListCtrl en mode virtuel (wx.LC_REPORT | wx.LC_VIRTUAL).
Il délègue la gestion des données à un parent (appelé __parent) qui doit
implémenter les méthodes getItemWithIndex, getItemText, getItemTooltipData et getItemImage.
Il gère les événements de sélection et d'activation des éléments, ainsi que le focus.
Il utilise wx.lib.mixins.listctrl.getListCtrlSelection pour obtenir la sélection actuelle .

2. Créer listctrltk.py en utilisant ttk.Treeview et les mixins de itemctrltk.py :

Utiliser ttk.Treeview en mode "liste" comme équivalent de wx.ListCtrl.
Cela signifie que vous n'aurez qu'une seule colonne visible.
Les autres colonnes serviront à stocker les données.
Utiliser les mixins de itemctrltk.py pour ajouter les fonctionnalités de gestion des éléments, des colonnes et des info-bulles .

3. Implémenter les méthodes déléguées :

Dans listctrltk.py, vous devrez implémenter les méthodes getItemWithIndex, getItemText, getItemTooltipData et getItemImage, en déléguant leur exécution à l'objet parent.
La méthode getItemWithIndex est utilisée pour récupérer l'élément de données correspondant à un index donné.
La méthode getItemText est utilisée pour récupérer le texte à afficher dans une cellule spécifique du ListCtrl.
La méthode getItemTooltipData est utilisée pour récupérer les informations à afficher dans l'info-bulle d'un élément.
La méthode getItemImage est utilisée pour récupérer l'image à afficher pour un élément .

4. Gérer les événements :

Lier les événements de sélection (<ButtonRelease-1>) et d'activation (<Double-Button-1>) aux méthodes correspondantes.
Adapter la logique de onSelect et onItemActivated pour Tkinter en utilisant les méthodes du ttk.Treeview.

5. Adapter les méthodes de rafraîchissement :

Implémenter RefreshAllItems et RefreshItems pour mettre à jour l'affichage du ttk.Treeview lorsque les données changent.
Utiliser insert et delete du ttk.Treeview pour ajouter et supprimer des éléments .

6. Gérer la sélection :

Implémenter les méthodes curselection, select, clear_selection et select_all en utilisant les méthodes selection_set, selection_remove et get_children du ttk.Treeview.

Remarques importantes :

Ce code est un squelette et doit être adapté à votre application spécifique.
Vous devrez implémenter les méthodes getItemWithIndex, getItemText, getItemTooltipData et getItemImage dans la classe parent qui utilise VirtualListCtrl.
Vous devrez également adapter la logique de tri en fonction de vos besoins.

J'ai essayé de chercher des informations concernant la conversion de la méthode SelectItem de la classe _CtrlWithItemsMixin, les classes _CtrlWithDropTargetMixin, Column, _BaseCtrlWithColumnsMixin et _CtrlWithAutoResizedColumnsMixin dans les fichiers que vous avez fournis, mais je n'ai trouvé aucun résultat pertinent.
Je vous recommande de consulter la réponse précédente pour obtenir des informations à ce sujet.

Dans ttk.Treeview, il existe une subtilité d'ordre :

    La colonne d'arborescence #0 doit être correctement configurée
    (généralement masquée ou réduite) avant de configurer les en-têtes des colonnes nommées.

    Dans une vue en liste, toutes les colonnes de données sont des colonnes nommées.

    Si l'on ne spécifie pas displaycolumns lors de l'initialisation,
    ttk.Treeview peut être capricieux et exiger que
    la configuration des en-têtes utilise l'indice numérique (#1, #2, etc.)
    plutôt que le nom ('task_name').

La Solution : Rendre les Mixins "Non-Coopératifs"

Puisque VirtualListCtrl (votre "TreeListCtrl" pour listes) gère l'initialisation explicitement,
les mixins dans itemctrltk.py ne doivent pas utiliser super().__init__ pour propager les arguments.
Ils doivent agir comme de simples fonctions de configuration.
Résumé de la Correction

Votre approche dans listctrltk.py (initialiser ttk.Treeview d'abord,
puis les mixins) est la bonne solution pour contourner les problèmes d'initialisation de Tkinter.

Le bug résiduel était que les mixins dans itemctrltk.py utilisaient super(),
ce qui n'est pas compatible avec cette stratégie d'initialisation manuelle.
En remplaçant les super().__init__() par des appels MixinParent.__init__() explicites
(ou en les supprimant s'ils n'ont pas de parent mixin),
vous cassez la chaîne MRO indésirable et empêchez les arguments d'être passés à object.__init__.
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