Daniil Anfimov
53ec2daab2
- Add the .gitignore file - Add the LICENSE file - Adjust the README file - Remove utf encoding
301 lines
10 KiB
Markdown
301 lines
10 KiB
Markdown
# immudb_wrapper
|
|
|
|
The wrapper around the SDK client `immudb-py` from project Codenotary, which expands the functionality of the original client with additional functions.
|
|
|
|
## Table of Contents
|
|
|
|
- [Requirements](#requirements)
|
|
- [Installation](#installation)
|
|
- [Usage](#usage)
|
|
- [Contribution](#contribution)
|
|
|
|
## Requirements
|
|
|
|
- python >= 3.7
|
|
- immudb-py >= 1.4.0
|
|
- GitPython >= 3.1.20
|
|
|
|
## Installation
|
|
|
|
You can easily install `immudb_wrapper` into your environment with the following command:
|
|
|
|
```
|
|
pip install git+https://git.almalinux.org/danfimov/immudb_wrapper.git@<tag|branch>#egg=immudb_wrapper
|
|
```
|
|
|
|
To run the `immudb` instance locally, you can use the options from `immudb` [documentation](https://docs.immudb.io/master/running/download.html).
|
|
|
|
If you want to use the `immudb` in `docker-compose.yml`, you can add the following in your compose file:
|
|
|
|
```
|
|
immudb:
|
|
image: codenotary/immudb:latest
|
|
ports:
|
|
- 3322:3322
|
|
- 9497:9497
|
|
volumes:
|
|
- "../volumes/immudb/data:/var/lib/immudb"
|
|
- "../volumes/immudb/config:/etc/immudb"
|
|
- "../volumes/immudb/logs:/var/log/immudb"
|
|
```
|
|
|
|
## Usage
|
|
|
|
### Client initialization
|
|
|
|
```python3
|
|
client = ImmudbWrapper(
|
|
username="user",
|
|
password="password",
|
|
database="database",
|
|
)
|
|
```
|
|
|
|
### File notarization
|
|
|
|
This method calculates the file hash and file size and inserts them with the user's metadata (if provided), into the database.
|
|
|
|
```python3
|
|
response = client.notarize_file(
|
|
"./hello_world.sh",
|
|
user_metadata={
|
|
"foo": "bar",
|
|
},
|
|
)
|
|
print(response)
|
|
{
|
|
'id': 1,
|
|
'key': '4db5767d4bf4221a5656b163ef1bae833095255f80d1ad5be21dfef84caf4126',
|
|
'value': {
|
|
'Name': 'hello_world.sh',
|
|
'Kind': 'file',
|
|
'Size': '2.62 KB',
|
|
'Hash': '4db5767d4bf4221a5656b163ef1bae833095255f80d1ad5be21dfef84caf4126',
|
|
'Metadata': {
|
|
'sbom_api_ver': '0.2',
|
|
'foo': 'bar',
|
|
},
|
|
},
|
|
'timestamp': 1690794033,
|
|
'verified': True,
|
|
'refkey': None,
|
|
'revision': 1,
|
|
}
|
|
```
|
|
|
|
### Git repo notarization
|
|
|
|
This method extracts the git metadata from a provided git directory, calculates the hash of the extracted metadata and inserts that metadata with the user's metadata (if provided), into the database. Falls with a `InvalidGitRepositoryError` when accepting non-git directories.
|
|
|
|
```python3
|
|
response = client.notarize_git_repo(
|
|
"./immudb_wrapper/",
|
|
user_metadata={
|
|
"foo": "bar",
|
|
},
|
|
)
|
|
print(response)
|
|
{
|
|
'id': 2,
|
|
'key': 'a87f7a948900e04812c095fb457e994926fc28c2a789471521fcc076cc4d8658',
|
|
'value': {
|
|
'Name': 'git@git.almalinux.org:danfimov/immudb_wrapper.git@c093e0f',
|
|
'Kind': 'git',
|
|
'Size': '30.52 KB',
|
|
'Hash': 'a87f7a948900e04812c095fb457e994926fc28c2a789471521fcc076cc4d8658',
|
|
'Metadata': {
|
|
'git': {
|
|
'Author': {
|
|
'Email': 'anfimovdan@gmail.com',
|
|
'Name': 'Daniil Anfimov',
|
|
'When': '2023-07-22T12:53:22+0200',
|
|
},
|
|
'Commit': 'c093e0f468c2810f76d4c09c340c58380bd965b1',
|
|
'Committer': {
|
|
'Email': 'anfimovdan@gmail.com',
|
|
'Name': 'Daniil Anfimov',
|
|
'When': '2023-07-22T12:53:22+0200',
|
|
},
|
|
'Message': 'Initial commit\n',
|
|
'PGPSignature': '',
|
|
'Parents': [],
|
|
'Tree': '4526550b9c6b77e7e10f6e57dfecfe0504c5166f',
|
|
},
|
|
'sbom_api_ver': '0.2',
|
|
'foo': 'bar',
|
|
},
|
|
},
|
|
'timestamp': 1690794260,
|
|
'verified': True,
|
|
'refkey': None,
|
|
'revision': 1,
|
|
}
|
|
```
|
|
|
|
### Git repo authentication
|
|
|
|
This method extracts the git metadata from a provided git directory, calculates the hash of the extracted metadata, and looks up the metadata of that hash in the database. Returns a dict with an error if metadata doesn't exist in the database.
|
|
|
|
```python3
|
|
response = client.authenticate_git_repo("./immudb_wrapper/")
|
|
print(response)
|
|
{
|
|
'id': 2,
|
|
'key': 'a87f7a948900e04812c095fb457e994926fc28c2a789471521fcc076cc4d8658',
|
|
'value': {
|
|
'Name': 'git@git.almalinux.org:danfimov/immudb_wrapper.git@c093e0f',
|
|
'Kind': 'git',
|
|
'Size': '30.52 KB',
|
|
'Hash': 'a87f7a948900e04812c095fb457e994926fc28c2a789471521fcc076cc4d8658',
|
|
'Metadata': {
|
|
'git': {
|
|
'Author': {
|
|
'Email': 'anfimovdan@gmail.com',
|
|
'Name': 'Daniil Anfimov',
|
|
'When': '2023-07-22T12:53:22+0200',
|
|
},
|
|
'Commit': 'c093e0f468c2810f76d4c09c340c58380bd965b1',
|
|
'Committer': {
|
|
'Email': 'anfimovdan@gmail.com',
|
|
'Name': 'Daniil Anfimov',
|
|
'When': '2023-07-22T12:53:22+0200',
|
|
},
|
|
'Message': 'Initial commit\n',
|
|
'PGPSignature': '',
|
|
'Parents': [],
|
|
'Tree': '4526550b9c6b77e7e10f6e57dfecfe0504c5166f',
|
|
},
|
|
'sbom_api_ver': '0.2',
|
|
'foo': 'bar',
|
|
},
|
|
},
|
|
'timestamp': 1690794260,
|
|
'verified': True,
|
|
'refkey': None,
|
|
'revision': 1,
|
|
}
|
|
|
|
response = client.authenticate_git_repo("./immudb_wrapper_foobar/")
|
|
print(response)
|
|
{'error': 'Traceback (most recent call last):\n'
|
|
' File "/code/env/bin/immudb_wrapper.py", line 247, in '
|
|
'verified_get\n'
|
|
' self.verifiedGet(\n'
|
|
' File "/code/env/lib/python3.9/site-packages/immudb/client.py", '
|
|
'line 667, in verifiedGet\n'
|
|
' return verifiedGet.call(self._stub, self._rs, key, '
|
|
'verifying_key=self._vk, atRevision=atRevision)\n'
|
|
' File '
|
|
'"/code/env/lib/python3.9/site-packages/immudb/handler/verifiedGet.py", '
|
|
'line 30, in call\n'
|
|
' ventry = service.VerifiableGet(req)\n'
|
|
' File '
|
|
'"/code/env/lib64/python3.9/site-packages/grpc/_interceptor.py", '
|
|
'line 247, in __call__\n'
|
|
' response, ignored_call = self._with_call(request,\n'
|
|
' File '
|
|
'"/code/env/lib64/python3.9/site-packages/grpc/_interceptor.py", '
|
|
'line 290, in _with_call\n'
|
|
' return call.result(), call\n'
|
|
' File "/code/env/lib64/python3.9/site-packages/grpc/_channel.py", '
|
|
'line 379, in result\n'
|
|
' raise self\n'
|
|
' File '
|
|
'"/code/env/lib64/python3.9/site-packages/grpc/_interceptor.py", '
|
|
'line 274, in continuation\n'
|
|
' response, call = self._thunk(new_method).with_call(\n'
|
|
' File "/code/env/lib64/python3.9/site-packages/grpc/_channel.py", '
|
|
'line 1043, in with_call\n'
|
|
' return _end_unary_response_blocking(state, call, True, None)\n'
|
|
' File "/code/env/lib64/python3.9/site-packages/grpc/_channel.py", '
|
|
'line 910, in _end_unary_response_blocking\n'
|
|
' raise _InactiveRpcError(state) # pytype: '
|
|
'disable=not-instantiable\n'
|
|
'grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that '
|
|
'terminated with:\n'
|
|
'\tstatus = StatusCode.UNKNOWN\n'
|
|
'\tdetails = "tbtree: key not found"\n'
|
|
'\tdebug_error_string = "UNKNOWN:Error received from peer '
|
|
'ipv4:172.18.0.2:3322 {grpc_message:"tbtree: key not found", '
|
|
'grpc_status:2, '
|
|
'created_time:"2023-07-31T09:13:55.947555151+00:00"}"\n'
|
|
'>\n'}
|
|
```
|
|
|
|
### File authentication
|
|
|
|
This method calculates the file hash of the provided file and looks up the metadata of that hash in the database. Returns a dict with an error if metadata doesn't exist in the database.
|
|
|
|
```python3
|
|
response = client.authenticate_file("./hello_world.sh")
|
|
print(response)
|
|
{
|
|
'id': 1,
|
|
'key': '4db5767d4bf4221a5656b163ef1bae833095255f80d1ad5be21dfef84caf4126',
|
|
'value': {
|
|
'Name': 'hello_world.sh',
|
|
'Kind': 'file',
|
|
'Size': '2.62 KB',
|
|
'Hash': '4db5767d4bf4221a5656b163ef1bae833095255f80d1ad5be21dfef84caf4126',
|
|
'Metadata': {
|
|
'sbom_api_ver': '0.2',
|
|
'foo': 'bar',
|
|
},
|
|
},
|
|
'timestamp': 1690794033,
|
|
'verified': True,
|
|
'refkey': None,
|
|
'revision': 1,
|
|
}
|
|
|
|
response = client.authenticate_file("./hello_world1.sh")
|
|
print(response)
|
|
{'error': 'Traceback (most recent call last):\n'
|
|
' File "/code/env/bin/immudb_wrapper.py", line 247, in '
|
|
'verified_get\n'
|
|
' self.verifiedGet(\n'
|
|
' File "/code/env/lib/python3.9/site-packages/immudb/client.py", '
|
|
'line 667, in verifiedGet\n'
|
|
' return verifiedGet.call(self._stub, self._rs, key, '
|
|
'verifying_key=self._vk, atRevision=atRevision)\n'
|
|
' File '
|
|
'"/code/env/lib/python3.9/site-packages/immudb/handler/verifiedGet.py", '
|
|
'line 30, in call\n'
|
|
' ventry = service.VerifiableGet(req)\n'
|
|
' File '
|
|
'"/code/env/lib64/python3.9/site-packages/grpc/_interceptor.py", '
|
|
'line 247, in __call__\n'
|
|
' response, ignored_call = self._with_call(request,\n'
|
|
' File '
|
|
'"/code/env/lib64/python3.9/site-packages/grpc/_interceptor.py", '
|
|
'line 290, in _with_call\n'
|
|
' return call.result(), call\n'
|
|
' File "/code/env/lib64/python3.9/site-packages/grpc/_channel.py", '
|
|
'line 379, in result\n'
|
|
' raise self\n'
|
|
' File '
|
|
'"/code/env/lib64/python3.9/site-packages/grpc/_interceptor.py", '
|
|
'line 274, in continuation\n'
|
|
' response, call = self._thunk(new_method).with_call(\n'
|
|
' File "/code/env/lib64/python3.9/site-packages/grpc/_channel.py", '
|
|
'line 1043, in with_call\n'
|
|
' return _end_unary_response_blocking(state, call, True, None)\n'
|
|
' File "/code/env/lib64/python3.9/site-packages/grpc/_channel.py", '
|
|
'line 910, in _end_unary_response_blocking\n'
|
|
' raise _InactiveRpcError(state) # pytype: '
|
|
'disable=not-instantiable\n'
|
|
'grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that '
|
|
'terminated with:\n'
|
|
'\tstatus = StatusCode.UNKNOWN\n'
|
|
'\tdetails = "tbtree: key not found"\n'
|
|
'\tdebug_error_string = "UNKNOWN:Error received from peer '
|
|
'ipv4:172.18.0.2:3322 {grpc_message:"tbtree: key not found", '
|
|
'grpc_status:2, '
|
|
'created_time:"2023-07-31T09:13:55.947555151+00:00"}"\n'
|
|
'>\n'}
|
|
```
|
|
|
|
## Contribution
|
|
|
|
If you wish to contribute to `immudb_wrapper`, just create a fork and make a PR.
|