Handling Python dependencies
The Python dependencies are not a part of the basic Python program and are instead loaded during runtime. Therefore, the application measurement, when loaded, does not cover these dependencies.
Anjuna provides the user a way to identify these dependencies.
A Python application can have two types of dependencies - static dependencies and dependencies that are computed during execution.
A static dependency is one that appears in the code as follows:
import mariadb
Here the code says that it depends on the MariaDB module.
A dependency that is computed during execution is one that is realized during runtime.
The following example is from the file onnx/symbolic_registry.py
from the PyTorch module:
for opset_version in _onnx_stable_opsets + [_onnx_main_opset]:
module =
importlib.import_module("torch.onnx.symbolic_opset{}".format(opset_version))
_symbolic_versions[opset_version] = module
You want to identify these two types of dependencies and then store their data in the manifest file of the enclave.
Identifying Python static dependencies
The static dependencies can be identified by the Anjuna manifest compiler. The compiler will add all of the static dependencies and their measurements to the manifest file.
This is done by including the tag python_config
in the
manifest template.
For the basic analyzer, include an empty python_config
tag in the template, i.e.,
add the following line to the template:
python_config: {}
This allows anjuna-compile-manifest to automatically invoke the Python analyzer to include the Python dependencies in the application manifest from the manifest template.
If you change your code or change your dependencies,
you should re-run the anjuna-compile-manifest
(or remove the python*.manifest.sgx
file and
re-run anjuna-sgxrun).
Identifying Python dependencies that are computed during execution
The dependencies that are computed during execution can be identified when running the
application in the enclave.
For any dependency that is not a part of the manifest,
or its measurements are different, a proper message will be printed to stderr
.
Dependencies that are not a part of the manifest
When in non-strict mode, any dependency that is missing from the manifest file will be printed to
stderr
in the following format:
Module: <module_name> not in config
In the non-strict mode, the module will be allowed to be imported.
When in strict mode,
the module will not be allowed to be imported for any dependency that is missing from the manifest
file and as a result triggers a ModuleNotFoundError
by the Python engine.
To solve the problem of the missing dependency,
you will need to add the modules to the
manifest template file.
For example, if the modules torch.onnx.symbolic_opset7
and torch.onnx.symbolic_opset8
are computed during execution,
you should add a python_modules
tag into your manifest template,
under the python_config
tag with the field name
and the value <module_name>
for each missing
dependency.
In the above example, you will have the following tag in the manifest template:
python_config:
python_modules:
- name: torch.onnx.symbolic_opset7
- name: torch.onnx.symbolic_opset8
Dependencies with a different measurement
When in non-strict mode,
any dependency whose measurement differs from the one identified by the analyzer will be printed
to stderr
in the following format:
Module: <module_name> has improper hash value Expected: <expected_module_measurement> Found: <actual_module_measurement>
In the non-strict mode, the module will be allowed to be imported.
When in strict mode,
any dependency that has a different hash prevents the module from getting imported and as a result
triggers a ModuleNotFoundError
by the Python engine.
To solve the problem of a measurement that differs, determine if the module is indeed the correct module. If you trust the module with the new measurement, delete the manifest file and recompile it from the template (anjuna-compile-manifest or anjuna-sgxrun).