Как мне защитить мою кодовую базу Python, чтобы гости не могли видеть определенные модули, но она все еще работает? - PullRequest
3 голосов
/ 18 сентября 2009

Мы начинаем новый проект в Python с несколькими запатентованными алгоритмами и чувствительными кусочками логики, которые мы хотели бы сохранить в секрете. У нас также будет несколько аутсайдеров (избранных представителей общественности), работающих над кодом. Мы не можем предоставить посторонним доступ к небольшим частным частям кода, но нам бы хотелось, чтобы общедоступная версия работала достаточно хорошо для них.

Скажем, что в нашем проекте Foo есть модуль bar с одной функцией get_sauce(). То, что действительно происходит в get_sauce(), является секретным, но мы хотим, чтобы общедоступная версия get_sauce() возвращала приемлемый, хотя и неверный, результат.

У нас также есть собственный сервер Subversion, поэтому мы полностью контролируем, кто и к чему имеет доступ.

Symlinks

Моей первой мыслью была символическая ссылка - вместо bar.py, предоставьте bar_public.py всем и bar_private.py только внутренним разработчикам. К сожалению, создание символических ссылок - это утомительная ручная работа, особенно если в действительности будет около двух десятков таких частных модулей.

Что еще более важно, это затрудняет управление файлом authz Subversion, поскольку для каждого модуля, который мы хотим защитить, на сервере должно быть добавлено исключение. Кто-то может забыть сделать это и случайно проверить секреты ... Тогда модуль находится в репо, и мы должны перестроить репозиторий без него и надеяться, что посторонний не загрузит его в это время.

Несколько хранилищ

Следующая мысль состояла в том, чтобы иметь два хранилища:

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

Идея состоит в том, что только внутренние разработчики смогут проверять как private/, так и public/. Внутренние разработчики установят свои PYTHONPATH=private/trunk:public/trunk, но все остальные просто установят PYTHONPATH=public/trunk. Тогда и инсайдеры, и аутсайдеры могут from foo import bar и получить нужный модуль, верно?

Давайте попробуем это:

% 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

Я не эксперт по Python, но похоже, что Python уже решил о модуле foo и ищет по этому поводу:

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

Даже удаление foo помогает:

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

Можете ли вы дать мне лучшее решение или предложение?

Ответы [ 3 ]

3 голосов
/ 18 сентября 2009

В методе __init__ пакета foo вы можете изменить __path__, чтобы он искал свои модули в других каталогах.

Создайте каталог с именем secret и поместите его в свой личный репозиторий Subversion. В secret поместите свой проприетарный bar.py. В __init__.py общедоступного пакета foo вставьте что-то вроде:

__path__.insert(0,'secret')

Это будет означать для пользователей, которые имеют частный репозиторий, и поэтому в каталоге secret они получат проприетарный bar.py, так как foo.bar, поскольку secret является первым каталогом в пути поиска. Для других пользователей Python не найдет secret и будет выглядеть как следующий каталог в __path__, поэтому будет загружать обычный bar.py из foo.

Так это будет выглядеть примерно так:

   private
    └── trunk/
        └── secret/
            └── bar.py
    public
    └── trunk/
        ├── __init__.py
        └── foo/
            ├── __init__.py
            ├── bar.py
            ├── baz.py
            └── quux.py
2 голосов
/ 18 сентября 2009

Используйте какую-то систему плагинов и держите свои плагины при себе, но также есть общедоступные плагины, которые поставляются с открытым кодом.

Системы плагинов имеются в большом количестве. Вы можете легко сделать из них простых. Если вы хотите что-то более продвинутое, я предпочитаю архитектуру компонентов Zope, но есть также такие опции, как setuptools entry_points и т. Д.

Какой из них использовать в вашем случае будет хорошим вторым вопросом.

0 голосов
/ 07 июля 2010

Вот альтернативное решение, которое я заметил при чтении документов для Flask :

flaskext/__init__.py

Единственная цель этого файла - пометить пакет как пакет пространства имен. Это необходимо для того, чтобы несколько модулей из разных пакетов PyPI могли находиться в одном пакете Python:

__import__('pkg_resources').declare_namespace(__name__)

Если вы хотите точно знать, что там происходит, обратитесь к документации по дистрибутиву или setuptools, в которой объясняется, как это работает.

...