Comment protéger ma base de code Python afin que les invités ne puissent pas voir certains modules mais que cela fonctionne toujours?

StackOverflow https://stackoverflow.com/questions/1443146

Question

Nous commençons un nouveau projet en Python avec quelques algorithmes propriétaires et des éléments logiques sensibles que nous aimerions garder confidentiels. Nous aurons également quelques étrangers (certains membres du public) travaillant sur le code. Nous ne pouvons pas permettre aux étrangers d’accéder aux petits morceaux de code privés, mais nous aimerions qu’une version publique fonctionne assez bien pour eux.

Dites que notre projet, Foo, possède un module, barre , avec une fonction, get_sauce () . Ce qui se passe réellement dans get_sauce () est secret, mais nous souhaitons qu'une version publique de get_sauce () renvoie un résultat acceptable, bien que incorrect.

Nous utilisons également notre propre serveur Subversion, ce qui nous permet de contrôler totalement qui peut accéder à quoi.

Liens symboliques

Ma première pensée a été de créer un lien symbolique - & nbsp; Au lieu de bar.py , fournissez bar_public.py à tout le monde et bar_private.py à interne développeurs seulement. Malheureusement, créer des liens symboliques est un travail manuel fastidieux, surtout quand il y aura vraiment environ deux douzaines de ces modules privés.

Plus important encore, cela rend la gestion du fichier authz Subversion difficile, car pour chaque module que nous voulons protéger, une exception doit être ajoutée sur le serveur. Quelqu'un pourrait oublier de le faire et vérifier accidentellement des secrets ... Ensuite, le module est dans le référentiel et nous devons reconstruire le référentiel sans lui, en espérant qu'un tiers ne l'ait pas téléchargé entre-temps.

Référentiels multiples

L’idée suivante était d’avoir deux référentiels:

private
└── trunk/
    ├── __init__.py
    └── foo/
        ├── __init__.py
        └── bar.py
public
└── trunk/
    ├── __init__.py
    └── foo/
        ├── __init__.py
        ├── bar.py
        ├── baz.py
        └── quux.py

L'idée est que seuls les développeurs internes pourront extraire à la fois private / et public / . Les développeurs internes définiront leur PYTHONPATH = privé / trunk: public / trunk , mais tout le monde ne fera que définir PYTHONPATH = public / trunk . Ensuite, les initiés et les étrangers peuvent depuis la barre d’importation foo et obtenir le bon module, non?

Essayons ceci:

% PYTHONPATH=private/trunk:public/trunk python
Python 2.5.1
Type "help", "copyright", "credits" or "license" for more information.
>>> import foo.bar
>>> foo.bar.sauce()
'a private bar'
>>> import foo.quux
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named quux

Je ne suis pas un expert de Python, mais il semble que Python se soit déjà décidé sur le module foo et sur les recherches relatives à celui-ci:

>>> foo
<module 'foo' from '/path/to/private/trunk/foo/__init__.py'>

Ne même pas supprimer foo aide:

>>> import sys
>>> del foo
>>> del sys.modules['foo']
>>> import foo.quux
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named quux

Pouvez-vous me fournir une meilleure solution ou suggestion?

Était-ce utile?

La solution

Dans la méthode __ init __ du package toto , vous pouvez modifier __ chemin __ pour lui faire rechercher ses modules dans d'autres répertoires.

Créez donc un répertoire appelé secret et placez-le dans votre référentiel privé Subversion. Dans secret , insérez votre bar.py propriétaire. Dans le __ init __. Py du paquet public foo , insérez quelque chose comme:

__path__.insert(0,'secret')

Cela signifiera que pour les utilisateurs qui possèdent le référentiel privé et donc le répertoire secret , ils obtiendront le propriétaire bar.py sous la forme foo.bar as secret est le premier répertoire du chemin de recherche. Pour les autres utilisateurs, Python ne trouvera pas secret et se présentera comme le prochain répertoire de __ chemin __ et chargera donc le normal.bar.py à partir de foo .

Cela ressemblera donc à quelque chose comme ça:

   private
    └── trunk/
        └── secret/
            └── bar.py
    public
    └── trunk/
        ├── __init__.py
        └── foo/
            ├── __init__.py
            ├── bar.py
            ├── baz.py
            └── quux.py

Autres conseils

Utilisez une sorte de système de plug-in, et gardez vos plug-ins pour vous, mais disposez également de plug-ins disponibles au public, livrés avec le code ouvert.

Les systèmes de plugins abondent. Vous pouvez facilement faire des morts simples vous-même. Si vous voulez quelque chose de plus avancé, je préfère l’architecture des composants Zope, mais il existe également des options telles que setuptools entry_points, etc.

Lequel utiliser dans votre cas serait une bonne deuxième question.

Voici une solution alternative que j'ai remarquée lors de la lecture de la documentation de Flask :

  

flaskext / __ init __. py

     

Ce fichier n'a pour but que de marquer le package en tant que package d'espace de noms. Cela est nécessaire pour que plusieurs modules de différents packages PyPI puissent résider dans le même package Python:

__import__('pkg_resources').declare_namespace(__name__)
     

Si vous voulez savoir exactement ce qui se passe là-bas, consultez les documents de distribution ou setuptools qui expliquent comment cela fonctionne.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top