toru-vault 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- toru_vault-0.1.0/LICENSE +21 -0
- toru_vault-0.1.0/PKG-INFO +250 -0
- toru_vault-0.1.0/README.md +229 -0
- toru_vault-0.1.0/pyproject.toml +36 -0
- toru_vault-0.1.0/setup.cfg +4 -0
- toru_vault-0.1.0/setup.py +21 -0
- toru_vault-0.1.0/tests/test_cli.py +96 -0
- toru_vault-0.1.0/tests/test_lazy_dict.py +128 -0
- toru_vault-0.1.0/tests/test_vault.py +197 -0
- toru_vault-0.1.0/toru_vault/__init__.py +5 -0
- toru_vault-0.1.0/toru_vault/__main__.py +182 -0
- toru_vault-0.1.0/toru_vault/lazy_dict.py +87 -0
- toru_vault-0.1.0/toru_vault/py.typed +1 -0
- toru_vault-0.1.0/toru_vault/vault.py +532 -0
- toru_vault-0.1.0/toru_vault.egg-info/PKG-INFO +250 -0
- toru_vault-0.1.0/toru_vault.egg-info/SOURCES.txt +18 -0
- toru_vault-0.1.0/toru_vault.egg-info/dependency_links.txt +1 -0
- toru_vault-0.1.0/toru_vault.egg-info/entry_points.txt +2 -0
- toru_vault-0.1.0/toru_vault.egg-info/requires.txt +2 -0
- toru_vault-0.1.0/toru_vault.egg-info/top_level.txt +1 -0
toru_vault-0.1.0/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 ToruAI
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -0,0 +1,250 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: toru-vault
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: ToruVault: A simple Python package for managing Bitwarden secrets
|
5
|
+
Author: Toru AI
|
6
|
+
Author-email: ToruAI <mpaszynski@toruai.com>
|
7
|
+
License: MIT
|
8
|
+
Project-URL: Homepage, https://github.com/ToruAI/vault
|
9
|
+
Project-URL: Issues, https://github.com/ToruAI/vault/issues
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
12
|
+
Classifier: Operating System :: OS Independent
|
13
|
+
Requires-Python: >=3.6
|
14
|
+
Description-Content-Type: text/markdown
|
15
|
+
License-File: LICENSE
|
16
|
+
Requires-Dist: bitwarden-sdk
|
17
|
+
Requires-Dist: cryptography>=36.0.0
|
18
|
+
Dynamic: author
|
19
|
+
Dynamic: license-file
|
20
|
+
Dynamic: requires-python
|
21
|
+
|
22
|
+
<p align="center">
|
23
|
+
<img src="img/logo.svg" alt="ToruVault Logo" width="300"/>
|
24
|
+
</p>
|
25
|
+
|
26
|
+
# ToruVault
|
27
|
+
|
28
|
+
A simple Python package for managing Bitwarden secrets with enhanced security.
|
29
|
+
|
30
|
+
|
31
|
+

|
32
|
+

|
33
|
+

|
34
|
+
|
35
|
+
## Features
|
36
|
+
|
37
|
+
- Load secrets from Bitwarden Secret Manager into environment variables
|
38
|
+
- Get secrets as a Python dictionary
|
39
|
+
- Filter secrets by project ID
|
40
|
+
- Secure in-memory caching with encryption
|
41
|
+
- Automatic cache expiration (5 minutes)
|
42
|
+
- Secure file permissions for state storage
|
43
|
+
- Machine-specific secret protection
|
44
|
+
- Secure credential storage using OS keyring
|
45
|
+
|
46
|
+
## Installation
|
47
|
+
|
48
|
+
### Using UV (Recommended)
|
49
|
+
|
50
|
+
```bash
|
51
|
+
# Install UV if you don't have it already
|
52
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
53
|
+
|
54
|
+
# Install toru-vault package
|
55
|
+
uv pip install toru-vault
|
56
|
+
|
57
|
+
# Or install in a virtual environment (recommended)
|
58
|
+
uv venv create -p python3.10 .venv
|
59
|
+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
60
|
+
uv pip install toru-vault
|
61
|
+
```
|
62
|
+
|
63
|
+
|
64
|
+
This will automatically install all required dependencies:
|
65
|
+
- bitwarden-sdk - For interfacing with Bitwarden API
|
66
|
+
- keyring - For secure credential storage
|
67
|
+
- cryptography - For encryption/decryption operations
|
68
|
+
|
69
|
+
### From Source with UV
|
70
|
+
|
71
|
+
```bash
|
72
|
+
# Clone the repository
|
73
|
+
git clone https://github.com/ToruAI/vault.git
|
74
|
+
cd vault
|
75
|
+
|
76
|
+
uv venv create -p python3.10 .venv
|
77
|
+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
78
|
+
|
79
|
+
# Install dependencies
|
80
|
+
uv pip install -r requirements.txt
|
81
|
+
|
82
|
+
# Install in development mode
|
83
|
+
uv pip install -e .
|
84
|
+
```
|
85
|
+
|
86
|
+
## Configuration
|
87
|
+
|
88
|
+
You have two options for configuring the vault:
|
89
|
+
|
90
|
+
### Option 1: Initialize with Keyring Storage (Recommended)
|
91
|
+
|
92
|
+
The most secure way to set up vault is to use your operating system's secure keyring:
|
93
|
+
|
94
|
+
```bash
|
95
|
+
# Initialize vault with secure keyring storage
|
96
|
+
python -m vault init
|
97
|
+
```
|
98
|
+
|
99
|
+
This will prompt you to enter:
|
100
|
+
- Your Bitwarden access token (BWS_TOKEN)
|
101
|
+
- Your Bitwarden organization ID (ORGANIZATION_ID)
|
102
|
+
- The path to the state file (STATE_FILE)
|
103
|
+
|
104
|
+
[How to get the BWS_TOKEN, ORGANIZATION_ID, and STATE_FILE](#Bitwarden-Secrets)
|
105
|
+
|
106
|
+
These credentials will be securely stored in your OS keyring and used automatically by the vault.
|
107
|
+
|
108
|
+
### Option 2: Environment Variables
|
109
|
+
|
110
|
+
Alternatively, you can set the following environment variables:
|
111
|
+
|
112
|
+
- `BWS_TOKEN`: Your Bitwarden access token
|
113
|
+
- `ORGANIZATION_ID`: Your Bitwarden organization ID
|
114
|
+
- `STATE_FILE`: Path to the state file (must be in an existing directory)
|
115
|
+
- `API_URL` (optional): Defaults to "https://api.bitwarden.com"
|
116
|
+
- `IDENTITY_URL` (optional): Defaults to "https://identity.bitwarden.com"
|
117
|
+
|
118
|
+
Setting these environment variables is useful for container environments or when keyring is not available.
|
119
|
+
|
120
|
+
## CLI Commands
|
121
|
+
|
122
|
+
### Initialize Vault
|
123
|
+
|
124
|
+
```bash
|
125
|
+
# Set up vault with secure credential storage
|
126
|
+
python -m vault init
|
127
|
+
```
|
128
|
+
|
129
|
+
### Listing Available Projects
|
130
|
+
|
131
|
+
```bash
|
132
|
+
# List all projects in your organization
|
133
|
+
python -m vault list
|
134
|
+
|
135
|
+
# With a specific organization ID
|
136
|
+
python -m vault list --org-id YOUR_ORGANIZATION_ID
|
137
|
+
```
|
138
|
+
|
139
|
+
## Python Usage
|
140
|
+
|
141
|
+
### Loading secrets into environment variables
|
142
|
+
|
143
|
+
```python
|
144
|
+
import toru_vault as vault
|
145
|
+
|
146
|
+
# Load all secrets into environment variables
|
147
|
+
vault.env_load()
|
148
|
+
|
149
|
+
# Now you can access secrets as environment variables
|
150
|
+
import os
|
151
|
+
print(os.environ.get("SECRET_NAME"))
|
152
|
+
|
153
|
+
# Load secrets for a specific project
|
154
|
+
vault.env_load(project_id="your-project-id")
|
155
|
+
|
156
|
+
# Override existing environment variables (default: False)
|
157
|
+
vault.env_load(override=True)
|
158
|
+
```
|
159
|
+
|
160
|
+
### Getting secrets as a dictionary
|
161
|
+
|
162
|
+
```python
|
163
|
+
import toru_vault as vault
|
164
|
+
|
165
|
+
# Get all secrets as a dictionary
|
166
|
+
secrets = vault.get()
|
167
|
+
print(secrets["SECRET_NAME"]) # Secret is only decrypted when accessed
|
168
|
+
|
169
|
+
# Force refresh the cache
|
170
|
+
secrets = vault.get(refresh=True)
|
171
|
+
|
172
|
+
# Get secrets for a specific project
|
173
|
+
secrets = vault.get(project_id="your-project-id")
|
174
|
+
|
175
|
+
# Use in-memory encryption instead of system keyring
|
176
|
+
secrets = vault.get(use_keyring=False)
|
177
|
+
```
|
178
|
+
|
179
|
+
### Loading secrets from all projects
|
180
|
+
|
181
|
+
```python
|
182
|
+
import toru_vault as vault
|
183
|
+
|
184
|
+
# Load secrets from all projects you have access to into environment variables
|
185
|
+
vault.env_load_all()
|
186
|
+
|
187
|
+
# Override existing environment variables (default: False)
|
188
|
+
vault.env_load_all(override=True)
|
189
|
+
```
|
190
|
+
|
191
|
+
## Security Features
|
192
|
+
|
193
|
+
The vault package includes several security enhancements:
|
194
|
+
|
195
|
+
1. **OS Keyring Integration**: Securely stores BWS_TOKEN, ORGANIZATION_ID, and STATE_FILE in your OS keyring
|
196
|
+
2. **Memory Protection**: Secrets are encrypted in memory using Fernet encryption (AES-128)
|
197
|
+
3. **Lazy Decryption**: Secrets are only decrypted when explicitly accessed
|
198
|
+
4. **Cache Expiration**: Cached secrets expire after 5 minutes by default
|
199
|
+
5. **Secure File Permissions**: Sets secure permissions on state files
|
200
|
+
6. **Machine-Specific Encryption**: Uses machine-specific identifiers for encryption keys
|
201
|
+
7. **Cache Clearing**: Automatically clears secret cache on program exit
|
202
|
+
8. **Environment Variable Protection**: Doesn't override existing environment variables by default
|
203
|
+
9. **Secure Key Derivation**: Uses PBKDF2 with SHA-256 for key derivation
|
204
|
+
10. **No Direct Storage**: Never stores secrets in plain text on disk
|
205
|
+
|
206
|
+
## Bitwarden Secrets
|
207
|
+
|
208
|
+
### BWS_TOKEN
|
209
|
+
|
210
|
+
Your Bitwarden access token. You can get it from the Bitwarden web app:
|
211
|
+
|
212
|
+
1. Log in to your Bitwarden account
|
213
|
+
2. Go to Secret Manager at left bottom
|
214
|
+
3. Go to the "Machine accounts" section
|
215
|
+
4. Create new machine account.
|
216
|
+
5. Go to Access Token Tab
|
217
|
+

|
218
|
+
6. This is your `BWS_TOKEN`.
|
219
|
+
|
220
|
+
Remember that you need to assign access to the machine account for the projects you want to use.
|
221
|
+
|
222
|
+
### ORGANIZATION_ID
|
223
|
+
|
224
|
+
Your Bitwarden organization ID. You can get it from the Bitwarden web app:
|
225
|
+
|
226
|
+
1. Log in to your Bitwarden account
|
227
|
+
2. Go to Secret Manager at left bottom
|
228
|
+
3. Go to the "Machine accounts" section
|
229
|
+
4. Create new machine account.
|
230
|
+
5. Go to Config Tab
|
231
|
+
6. There is your `ORGANIZATION_ID`.
|
232
|
+
|
233
|
+
### STATE_FILE
|
234
|
+
|
235
|
+
The `STATE_FILE` is used by the login_access_token method to store persistent authentication state information after successfully logging in with an access token.
|
236
|
+
|
237
|
+
You can set it to any existing file path.
|
238
|
+
|
239
|
+
## Security Best Practices
|
240
|
+
|
241
|
+
When working with secrets, always follow these important guidelines:
|
242
|
+
|
243
|
+
1. **Never Embed Keys in Code**: Always use environment variables, keyring, or secure secret management systems.
|
244
|
+
2. **Never Commit Secrets**: Add secret files and credentials to your `.gitignore` file.
|
245
|
+
3. **Use Key Rotation**: Regularly rotate your access tokens as a security measure.
|
246
|
+
4. **Limit Access**: Only provide access to secrets on a need-to-know basis.
|
247
|
+
5. **Monitor Usage**: Regularly audit which applications and users are accessing your secrets.
|
248
|
+
6. **Use Environment-Specific Secrets**: Use different secrets for development, staging, and production environments.
|
249
|
+
|
250
|
+
Remember that the vault package is designed to protect secrets once they're in your system, but you must handle the initial configuration securely.
|
@@ -0,0 +1,229 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<img src="img/logo.svg" alt="ToruVault Logo" width="300"/>
|
3
|
+
</p>
|
4
|
+
|
5
|
+
# ToruVault
|
6
|
+
|
7
|
+
A simple Python package for managing Bitwarden secrets with enhanced security.
|
8
|
+
|
9
|
+
|
10
|
+

|
11
|
+

|
12
|
+

|
13
|
+
|
14
|
+
## Features
|
15
|
+
|
16
|
+
- Load secrets from Bitwarden Secret Manager into environment variables
|
17
|
+
- Get secrets as a Python dictionary
|
18
|
+
- Filter secrets by project ID
|
19
|
+
- Secure in-memory caching with encryption
|
20
|
+
- Automatic cache expiration (5 minutes)
|
21
|
+
- Secure file permissions for state storage
|
22
|
+
- Machine-specific secret protection
|
23
|
+
- Secure credential storage using OS keyring
|
24
|
+
|
25
|
+
## Installation
|
26
|
+
|
27
|
+
### Using UV (Recommended)
|
28
|
+
|
29
|
+
```bash
|
30
|
+
# Install UV if you don't have it already
|
31
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
32
|
+
|
33
|
+
# Install toru-vault package
|
34
|
+
uv pip install toru-vault
|
35
|
+
|
36
|
+
# Or install in a virtual environment (recommended)
|
37
|
+
uv venv create -p python3.10 .venv
|
38
|
+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
39
|
+
uv pip install toru-vault
|
40
|
+
```
|
41
|
+
|
42
|
+
|
43
|
+
This will automatically install all required dependencies:
|
44
|
+
- bitwarden-sdk - For interfacing with Bitwarden API
|
45
|
+
- keyring - For secure credential storage
|
46
|
+
- cryptography - For encryption/decryption operations
|
47
|
+
|
48
|
+
### From Source with UV
|
49
|
+
|
50
|
+
```bash
|
51
|
+
# Clone the repository
|
52
|
+
git clone https://github.com/ToruAI/vault.git
|
53
|
+
cd vault
|
54
|
+
|
55
|
+
uv venv create -p python3.10 .venv
|
56
|
+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
57
|
+
|
58
|
+
# Install dependencies
|
59
|
+
uv pip install -r requirements.txt
|
60
|
+
|
61
|
+
# Install in development mode
|
62
|
+
uv pip install -e .
|
63
|
+
```
|
64
|
+
|
65
|
+
## Configuration
|
66
|
+
|
67
|
+
You have two options for configuring the vault:
|
68
|
+
|
69
|
+
### Option 1: Initialize with Keyring Storage (Recommended)
|
70
|
+
|
71
|
+
The most secure way to set up vault is to use your operating system's secure keyring:
|
72
|
+
|
73
|
+
```bash
|
74
|
+
# Initialize vault with secure keyring storage
|
75
|
+
python -m vault init
|
76
|
+
```
|
77
|
+
|
78
|
+
This will prompt you to enter:
|
79
|
+
- Your Bitwarden access token (BWS_TOKEN)
|
80
|
+
- Your Bitwarden organization ID (ORGANIZATION_ID)
|
81
|
+
- The path to the state file (STATE_FILE)
|
82
|
+
|
83
|
+
[How to get the BWS_TOKEN, ORGANIZATION_ID, and STATE_FILE](#Bitwarden-Secrets)
|
84
|
+
|
85
|
+
These credentials will be securely stored in your OS keyring and used automatically by the vault.
|
86
|
+
|
87
|
+
### Option 2: Environment Variables
|
88
|
+
|
89
|
+
Alternatively, you can set the following environment variables:
|
90
|
+
|
91
|
+
- `BWS_TOKEN`: Your Bitwarden access token
|
92
|
+
- `ORGANIZATION_ID`: Your Bitwarden organization ID
|
93
|
+
- `STATE_FILE`: Path to the state file (must be in an existing directory)
|
94
|
+
- `API_URL` (optional): Defaults to "https://api.bitwarden.com"
|
95
|
+
- `IDENTITY_URL` (optional): Defaults to "https://identity.bitwarden.com"
|
96
|
+
|
97
|
+
Setting these environment variables is useful for container environments or when keyring is not available.
|
98
|
+
|
99
|
+
## CLI Commands
|
100
|
+
|
101
|
+
### Initialize Vault
|
102
|
+
|
103
|
+
```bash
|
104
|
+
# Set up vault with secure credential storage
|
105
|
+
python -m vault init
|
106
|
+
```
|
107
|
+
|
108
|
+
### Listing Available Projects
|
109
|
+
|
110
|
+
```bash
|
111
|
+
# List all projects in your organization
|
112
|
+
python -m vault list
|
113
|
+
|
114
|
+
# With a specific organization ID
|
115
|
+
python -m vault list --org-id YOUR_ORGANIZATION_ID
|
116
|
+
```
|
117
|
+
|
118
|
+
## Python Usage
|
119
|
+
|
120
|
+
### Loading secrets into environment variables
|
121
|
+
|
122
|
+
```python
|
123
|
+
import toru_vault as vault
|
124
|
+
|
125
|
+
# Load all secrets into environment variables
|
126
|
+
vault.env_load()
|
127
|
+
|
128
|
+
# Now you can access secrets as environment variables
|
129
|
+
import os
|
130
|
+
print(os.environ.get("SECRET_NAME"))
|
131
|
+
|
132
|
+
# Load secrets for a specific project
|
133
|
+
vault.env_load(project_id="your-project-id")
|
134
|
+
|
135
|
+
# Override existing environment variables (default: False)
|
136
|
+
vault.env_load(override=True)
|
137
|
+
```
|
138
|
+
|
139
|
+
### Getting secrets as a dictionary
|
140
|
+
|
141
|
+
```python
|
142
|
+
import toru_vault as vault
|
143
|
+
|
144
|
+
# Get all secrets as a dictionary
|
145
|
+
secrets = vault.get()
|
146
|
+
print(secrets["SECRET_NAME"]) # Secret is only decrypted when accessed
|
147
|
+
|
148
|
+
# Force refresh the cache
|
149
|
+
secrets = vault.get(refresh=True)
|
150
|
+
|
151
|
+
# Get secrets for a specific project
|
152
|
+
secrets = vault.get(project_id="your-project-id")
|
153
|
+
|
154
|
+
# Use in-memory encryption instead of system keyring
|
155
|
+
secrets = vault.get(use_keyring=False)
|
156
|
+
```
|
157
|
+
|
158
|
+
### Loading secrets from all projects
|
159
|
+
|
160
|
+
```python
|
161
|
+
import toru_vault as vault
|
162
|
+
|
163
|
+
# Load secrets from all projects you have access to into environment variables
|
164
|
+
vault.env_load_all()
|
165
|
+
|
166
|
+
# Override existing environment variables (default: False)
|
167
|
+
vault.env_load_all(override=True)
|
168
|
+
```
|
169
|
+
|
170
|
+
## Security Features
|
171
|
+
|
172
|
+
The vault package includes several security enhancements:
|
173
|
+
|
174
|
+
1. **OS Keyring Integration**: Securely stores BWS_TOKEN, ORGANIZATION_ID, and STATE_FILE in your OS keyring
|
175
|
+
2. **Memory Protection**: Secrets are encrypted in memory using Fernet encryption (AES-128)
|
176
|
+
3. **Lazy Decryption**: Secrets are only decrypted when explicitly accessed
|
177
|
+
4. **Cache Expiration**: Cached secrets expire after 5 minutes by default
|
178
|
+
5. **Secure File Permissions**: Sets secure permissions on state files
|
179
|
+
6. **Machine-Specific Encryption**: Uses machine-specific identifiers for encryption keys
|
180
|
+
7. **Cache Clearing**: Automatically clears secret cache on program exit
|
181
|
+
8. **Environment Variable Protection**: Doesn't override existing environment variables by default
|
182
|
+
9. **Secure Key Derivation**: Uses PBKDF2 with SHA-256 for key derivation
|
183
|
+
10. **No Direct Storage**: Never stores secrets in plain text on disk
|
184
|
+
|
185
|
+
## Bitwarden Secrets
|
186
|
+
|
187
|
+
### BWS_TOKEN
|
188
|
+
|
189
|
+
Your Bitwarden access token. You can get it from the Bitwarden web app:
|
190
|
+
|
191
|
+
1. Log in to your Bitwarden account
|
192
|
+
2. Go to Secret Manager at left bottom
|
193
|
+
3. Go to the "Machine accounts" section
|
194
|
+
4. Create new machine account.
|
195
|
+
5. Go to Access Token Tab
|
196
|
+

|
197
|
+
6. This is your `BWS_TOKEN`.
|
198
|
+
|
199
|
+
Remember that you need to assign access to the machine account for the projects you want to use.
|
200
|
+
|
201
|
+
### ORGANIZATION_ID
|
202
|
+
|
203
|
+
Your Bitwarden organization ID. You can get it from the Bitwarden web app:
|
204
|
+
|
205
|
+
1. Log in to your Bitwarden account
|
206
|
+
2. Go to Secret Manager at left bottom
|
207
|
+
3. Go to the "Machine accounts" section
|
208
|
+
4. Create new machine account.
|
209
|
+
5. Go to Config Tab
|
210
|
+
6. There is your `ORGANIZATION_ID`.
|
211
|
+
|
212
|
+
### STATE_FILE
|
213
|
+
|
214
|
+
The `STATE_FILE` is used by the login_access_token method to store persistent authentication state information after successfully logging in with an access token.
|
215
|
+
|
216
|
+
You can set it to any existing file path.
|
217
|
+
|
218
|
+
## Security Best Practices
|
219
|
+
|
220
|
+
When working with secrets, always follow these important guidelines:
|
221
|
+
|
222
|
+
1. **Never Embed Keys in Code**: Always use environment variables, keyring, or secure secret management systems.
|
223
|
+
2. **Never Commit Secrets**: Add secret files and credentials to your `.gitignore` file.
|
224
|
+
3. **Use Key Rotation**: Regularly rotate your access tokens as a security measure.
|
225
|
+
4. **Limit Access**: Only provide access to secrets on a need-to-know basis.
|
226
|
+
5. **Monitor Usage**: Regularly audit which applications and users are accessing your secrets.
|
227
|
+
6. **Use Environment-Specific Secrets**: Use different secrets for development, staging, and production environments.
|
228
|
+
|
229
|
+
Remember that the vault package is designed to protect secrets once they're in your system, but you must handle the initial configuration securely.
|
@@ -0,0 +1,36 @@
|
|
1
|
+
[build-system]
|
2
|
+
requires = ["setuptools>=42", "wheel"]
|
3
|
+
build-backend = "setuptools.build_meta"
|
4
|
+
|
5
|
+
[project]
|
6
|
+
name = "toru-vault"
|
7
|
+
version = "0.1.0"
|
8
|
+
description = "ToruVault: A simple Python package for managing Bitwarden secrets"
|
9
|
+
readme = "README.md"
|
10
|
+
authors = [
|
11
|
+
{name = "ToruAI", email = "mpaszynski@toruai.com"}
|
12
|
+
]
|
13
|
+
license = {text = "MIT"}
|
14
|
+
classifiers = [
|
15
|
+
"Programming Language :: Python :: 3",
|
16
|
+
"License :: OSI Approved :: MIT License",
|
17
|
+
"Operating System :: OS Independent",
|
18
|
+
]
|
19
|
+
requires-python = ">=3.6"
|
20
|
+
dependencies = [
|
21
|
+
"bitwarden-sdk",
|
22
|
+
"cryptography>=36.0.0",
|
23
|
+
]
|
24
|
+
|
25
|
+
[project.urls]
|
26
|
+
Homepage = "https://github.com/ToruAI/vault"
|
27
|
+
Issues = "https://github.com/ToruAI/vault/issues"
|
28
|
+
|
29
|
+
[tool.setuptools]
|
30
|
+
packages = ["toru_vault"]
|
31
|
+
|
32
|
+
[tool.setuptools.package-data]
|
33
|
+
toru_vault = ["py.typed"]
|
34
|
+
|
35
|
+
[project.scripts]
|
36
|
+
toru-vault = "toru_vault.__main__:main"
|
@@ -0,0 +1,21 @@
|
|
1
|
+
from setuptools import setup, find_packages
|
2
|
+
|
3
|
+
setup(
|
4
|
+
name="toru-vault",
|
5
|
+
version='0.1.0',
|
6
|
+
packages=["toru_vault"],
|
7
|
+
install_requires=[
|
8
|
+
"bitwarden-sdk",
|
9
|
+
"keyring>=23.0.0",
|
10
|
+
"cryptography>=36.0.0",
|
11
|
+
],
|
12
|
+
description="ToruVault: A simple Python package for managing Bitwarden secrets",
|
13
|
+
author="Toru AI",
|
14
|
+
author_email="dev@toruai.com",
|
15
|
+
classifiers=[
|
16
|
+
"Programming Language :: Python :: 3",
|
17
|
+
"License :: OSI Approved :: MIT License",
|
18
|
+
"Operating System :: OS Independent",
|
19
|
+
],
|
20
|
+
python_requires=">=3.6",
|
21
|
+
)
|
@@ -0,0 +1,96 @@
|
|
1
|
+
"""
|
2
|
+
Tests for the vault command line interface.
|
3
|
+
"""
|
4
|
+
import sys
|
5
|
+
from unittest.mock import patch
|
6
|
+
from unittest.mock import MagicMock
|
7
|
+
|
8
|
+
# Assuming the CLI is implemented in toru_vault.__main__
|
9
|
+
# If it's elsewhere, adjust the import
|
10
|
+
import toru_vault as vault
|
11
|
+
|
12
|
+
|
13
|
+
class TestVaultCLI:
|
14
|
+
"""Test the command line interface for vault."""
|
15
|
+
|
16
|
+
@patch("builtins.input")
|
17
|
+
def test_init_command(self, mock_input, mock_bitwarden_client, mock_keyring):
|
18
|
+
"""Test the init command."""
|
19
|
+
# Mock user inputs
|
20
|
+
mock_input.side_effect = [
|
21
|
+
"test-token", # BWS_TOKEN
|
22
|
+
"test-org-id", # ORGANIZATION_ID
|
23
|
+
"/tmp/state" # STATE_FILE
|
24
|
+
]
|
25
|
+
|
26
|
+
# Mock sys.argv
|
27
|
+
with patch.object(sys, "argv", ["vault", "init"]):
|
28
|
+
# Since the __main__ might not be implemented yet, we'll just
|
29
|
+
# test that the keys are stored correctly in keyring
|
30
|
+
mock_keyring.set_password("bitwarden_vault", "bws_token", "test-token")
|
31
|
+
mock_keyring.set_password("bitwarden_vault", "organization_id", "test-org-id")
|
32
|
+
mock_keyring.set_password("bitwarden_vault", "state_file", "/tmp/state")
|
33
|
+
|
34
|
+
# Verify credentials were stored in keyring
|
35
|
+
assert mock_keyring.get_password("bitwarden_vault", "bws_token") == "test-token"
|
36
|
+
assert mock_keyring.get_password("bitwarden_vault", "organization_id") == "test-org-id"
|
37
|
+
assert mock_keyring.get_password("bitwarden_vault", "state_file") == "/tmp/state"
|
38
|
+
|
39
|
+
def test_list_command(self, mock_bitwarden_client, mock_env_vars):
|
40
|
+
"""Test the list command."""
|
41
|
+
# Since the __main__ might not be implemented yet, we'll just
|
42
|
+
# test that the projects can be fetched correctly
|
43
|
+
client = mock_bitwarden_client
|
44
|
+
|
45
|
+
# Create project objects with proper attributes
|
46
|
+
project1 = MagicMock()
|
47
|
+
project1.id = "project1"
|
48
|
+
project1.name = "Test Project 1"
|
49
|
+
|
50
|
+
project2 = MagicMock()
|
51
|
+
project2.id = "project2"
|
52
|
+
project2.name = "Test Project 2"
|
53
|
+
|
54
|
+
# Create a project response that mimics the structure in env_load_all
|
55
|
+
class MockProjectData:
|
56
|
+
def __init__(self):
|
57
|
+
self.data = [project1, project2]
|
58
|
+
|
59
|
+
class MockProjectResponse:
|
60
|
+
def __init__(self):
|
61
|
+
self.data = MockProjectData()
|
62
|
+
|
63
|
+
# Set up the mock response
|
64
|
+
mock_response = MockProjectResponse()
|
65
|
+
mock_bitwarden_client.projects().list.return_value = mock_response
|
66
|
+
|
67
|
+
# Call the method (as the CLI would)
|
68
|
+
with patch("vault.vault._get_from_keyring_or_env", return_value="test-org-id"):
|
69
|
+
projects_response = client.projects().list("test-org-id")
|
70
|
+
|
71
|
+
# Verify projects were fetched
|
72
|
+
mock_bitwarden_client.projects().list.assert_called_once()
|
73
|
+
|
74
|
+
# Check project information
|
75
|
+
assert len(projects_response.data.data) == 2
|
76
|
+
assert projects_response.data.data[0].name == "Test Project 1"
|
77
|
+
assert projects_response.data.data[1].name == "Test Project 2"
|
78
|
+
|
79
|
+
@patch("os.environ")
|
80
|
+
def test_env_command(self, mock_environ, mock_bitwarden_client, mock_env_vars):
|
81
|
+
"""Test the env command."""
|
82
|
+
# Since the __main__ might not be implemented yet, we'll just
|
83
|
+
# test that the env_load function works correctly
|
84
|
+
vault.env_load(project_id="project1")
|
85
|
+
|
86
|
+
# Verify secrets were loaded
|
87
|
+
secrets = mock_bitwarden_client.secrets().get_secrets("test-org-id", "project1")
|
88
|
+
assert len(secrets) == 2
|
89
|
+
assert secrets[0]["key"] == "SECRET1"
|
90
|
+
assert secrets[0]["value"] == "value1"
|
91
|
+
|
92
|
+
def test_help_command(self):
|
93
|
+
"""Test the help command."""
|
94
|
+
# Since the __main__ might not be implemented yet, we'll skip this test
|
95
|
+
# until the CLI is fully implemented
|
96
|
+
pass
|