Skip to content

Feat: secrets #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
97f6e96
feat: added exceptions.py
nimish-ks May 4, 2024
655ed9e
feat: added network.py
nimish-ks May 4, 2024
14687db
wip: crypto.py
nimish-ks May 4, 2024
7a3ab8f
chore: remove version.py - version moved to const.py
nimish-ks May 4, 2024
e479649
feat: added const.py
nimish-ks May 4, 2024
f5f1eb7
feat: added secret management support to phase
nimish-ks May 4, 2024
99f71e7
wip: misc utils and helper functions
nimish-ks May 4, 2024
055aae7
temporary: remove tests
nimish-ks May 4, 2024
b9a3a9e
chore: move exceptions
nimish-ks May 6, 2024
46fed15
feat: phase.create
nimish-ks May 6, 2024
efaf95c
feat: phase.get secrets
nimish-ks May 6, 2024
011ff84
feat: phase.update secrets
nimish-ks May 7, 2024
da4bc46
feat: make decrypt private
nimish-ks May 8, 2024
83df419
chore: updated comments
nimish-ks May 8, 2024
b104939
chore: update comments
nimish-ks May 8, 2024
06357b8
chore: fix comment
nimish-ks May 8, 2024
14746a2
feat: improved phase delete
nimish-ks May 8, 2024
3d4d11d
chore: updated pyproject
nimish-ks Jul 22, 2024
99dec97
chore: updated README
nimish-ks Jul 22, 2024
2fb17cc
fix: phase delete path
nimish-ks Jul 22, 2024
f4a8494
chore: create phase python module
nimish-ks Jul 22, 2024
72cb566
feat: added tests
nimish-ks Jul 22, 2024
89b2a6d
feat: added secret_referencing logic
nimish-ks Jul 22, 2024
3f453cb
chore: updated exceptions
nimish-ks Jul 22, 2024
01303d6
test: fix workflow
nimish-ks Jul 22, 2024
dfbfd60
fix: test names
nimish-ks Jul 22, 2024
53b66ce
chore: cleanup workflow
nimish-ks Jul 22, 2024
47a08db
feat: added secret referencing support
nimish-ks Jul 22, 2024
3879f93
wip
nimish-ks Jul 30, 2024
369a987
chore: updated module
nimish-ks Jul 31, 2024
4fe2ae6
refactor: phase class
nimish-ks Jul 31, 2024
d16f42d
feat: updated phase_io and secret ref logic
nimish-ks Jul 31, 2024
e6dc78b
feat: extended Phase to utilize all phase_io utils
nimish-ks Aug 1, 2024
0734648
feat: updated readme
nimish-ks Aug 1, 2024
2e2d4e0
feat: rename SecretUpdateOptions to UpdateSecretOptions
rohan-chaturvedi Aug 7, 2024
cec10e8
feat: add contributing doc
rohan-chaturvedi Aug 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.x
python-version: '3.12'

- name: Install dependencies
run: pip install -r requirements.txt
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pytest

- name: Run pytest
run: python -m pytest
run: |
python -m pytest -v tests/
116 changes: 116 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
## Local setup

Clone the reposistory to your machine and install the required dependencies.

### Create a virtual environment

```fish
python3 -m venv.venv
```

### Install dependencies

```fish
pip install -r requirements.txt
```

### Demo script

This demo python script will create, read, update and delete secrets via the SDK. Just update the host, app, env and token constants at the top.

```python
from src.phase import Phase, CreateSecretsOptions, GetAllSecretsOptions, UpdateSecretOptions, DeleteSecretOptions

CONSOLE_HOST = 'https://console.phase.dev'
APP_NAME = '<app-name>'
ENV_NAME = "<env-name>"
TOKEN = '<service-token>'

# Initialize the Phase object with host and service token
phase = Phase(init=False,
pss=TOKEN,
host=CONSOLE_HOST)

# Create secrets with references
create_options = CreateSecretsOptions(
env_name=ENV_NAME,
app_name=APP_NAME,
key_value_pairs=[
{"BASE_URL": "https://api.example.com"},
{"API_ENDPOINT": "${BASE_URL}/v1/data"},
{"NESTED_REF": "Nested ${API_ENDPOINT}"}
]
)
create_result = phase.create_secrets(create_options)
print(f"Create secrets result: {create_result}")

# Read and resolve references
get_options = GetAllSecretsOptions(
env_name=ENV_NAME,
app_name=APP_NAME
)
secrets = phase.get_all_secrets(get_options)

resolved_secrets = phase.resolve_references(secrets, ENV_NAME, APP_NAME)

print("\nResolved Secrets:")
print("----------------")
for secret in resolved_secrets:
print(f"{secret.key}: {secret.value}")

# Update secrets
update_options = UpdateSecretOptions(
env_name=ENV_NAME,
app_name=APP_NAME,
key="BASE_URL",
value="https://api.acme.com",
secret_path="/",
destination_path="/", # Optional: move secret to a new path
override=False, # Optional: create a personal override
toggle_override=False # Optional: toggle personal override
)
update_result = phase.update_secret(update_options)

print(f"\nUpdate secrets result: {update_result}")
print("----------------")


## Refetch secrets
secrets = phase.get_all_secrets(get_options)

resolved_secrets = phase.resolve_references(secrets, ENV_NAME, APP_NAME)

print("\nResolved Secrets:")
print("----------------")
for secret in resolved_secrets:
print(f"{secret.key}: {secret.value}")


# Delete secrets
delete_options = DeleteSecretOptions(
env_name=ENV_NAME,
app_name=APP_NAME,
key_to_delete="BASE_URL",
secret_path="/"
)
result = phase.delete_secret(delete_options)
print(f"Delete result: {result}")

## Refetch secrets
secrets = phase.get_all_secrets(get_options)

resolved_secrets = phase.resolve_references(secrets, ENV_NAME, APP_NAME)

print("\nResolved Secrets:")
print("----------------")
for secret in resolved_secrets:
print(f"{secret.key}: {secret.value}")
```

## Running Tests

Run the test suite with:

```fish
python -m pytest -v tests/
```
126 changes: 117 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,143 @@
# Python SDK for Phase

SDK to integrate Phase in server-side applications running Python
SDK to integrate Phase in server-side applications running Python. This SDK allows you to manage secrets securely using the Phase platform.

## Install

`pip install phase-dev`
```
pip install phase-dev
```

## Import

```python
from phase import Phase;
from phase import Phase, CreateSecretsOptions, GetAllSecretsOptions, GetSecretOptions, UpdateSecretOptions, DeleteSecretOptions
```

## Initialize

Initialize the SDK with your `APP_ID` and `APP_SECRET`:
Initialize the SDK with your host and token:

```python
phase = Phase(APP_ID, APP_SECRET)
phase = Phase(
init=False,
host='https://your-phase-host.com',
pss=PHASE_SERVICE_TOKEN

)
```

## Usage

### Encrypt
### Create Secrets

Create one or more secrets in a specified application and environment:

```python
create_options = CreateSecretsOptions(
env_name="Development",
app_name="Your App Name",
key_value_pairs=[
{"API_KEY": "your-api-key"},
{"DB_PASSWORD": "your-db-password"}
],
secret_path="/api"
)
result = phase.create_secrets(create_options)
print(f"Create secrets result: {result}")
```

### Get Secrets

Fetch one or more secrets from a specified application and environment:

```python
get_options = GetAllSecretsOptions(
env_name="Development",
app_name="Your App Name",
tag="api", # Optional: filter by tag
secret_path="/api" # Optional: specify path
)
secrets = phase.get_all_secrets(get_options)
for secret in secrets:
print(f"Key: {secret.key}, Value: {secret.value}")
```

To get a specific secret:

```python
ciphertext = phase.encrypt("hello world");
get_options = GetSecretOptions(
env_name="Development",
app_name="Your App Name",
key_to_find="API_KEY",
secret_path="/api"
)
secret = phase.get_secret(get_options)
if secret:
print(f"Key: {secret.key}, Value: {secret.value}")
```

### Decrypt
### Update Secrets

Update an existing secret in a specified application and environment:

```python
plaintext = phase.decrypt(ciphertext);
update_options = UpdateSecretOptions(
env_name="Development",
app_name="Your App Name",
key="API_KEY",
value="new-api-key-value",
secret_path="/api",
destination_path="/new-api", # Optional: move secret to a new path
override=False, # Optional: create a personal override
toggle_override=False # Optional: toggle personal override
)
result = phase.update_secret(update_options)
print(f"Update result: {result}")
```

### Delete Secrets

Delete a secret from a specified application and environment:

```python
delete_options = DeleteSecretOptions(
env_name="Development",
app_name="Your App Name",
key_to_delete="API_KEY",
secret_path="/api"
)
result = phase.delete_secret(delete_options)
print(f"Delete result: {result}")
```

### Resolve Secret References

Resolve references in secret values:

```python
get_options = GetAllSecretsOptions(
env_name="Development",
app_name="Your App Name"
)
secrets = phase.get_all_secrets(get_options)
resolved_secrets = phase.resolve_references(secrets, "Development", "Your App Name")
for secret in resolved_secrets:
print(f"Key: {secret.key}, Resolved Value: {secret.value}")
```

## Error Handling

The SDK methods may raise exceptions for various error conditions. It's recommended to wrap SDK calls in try-except blocks to handle potential errors:

```python
try:
get_options = GetAllSecretsOptions(env_name="Development", app_name="Your App Name")
secrets = phase.get_all_secrets(get_options)
except ValueError as e:
print(f"An error occurred: {e}")
```

## Note on Security

Never hard-code sensitive information like tokens or secrets directly in your code. Always use environment variables or secure configuration management to provide these values to your application.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"

[project]
name = "phase_dev"
version = "1.1.0"
description = "Python SDK for Phase"
version = "2.0.0"
description = "Python SDK for Phase secrets manager"
readme = "README.md"
requires-python = ">=3.10"
classifiers = [
Expand Down
20 changes: 18 additions & 2 deletions src/phase/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
from .phase import Phase
from .phase import (
Phase,
GetSecretOptions,
GetAllSecretsOptions,
CreateSecretsOptions,
UpdateSecretOptions,
DeleteSecretOptions,
PhaseSecret
)

__all__ = ['Phase']
__all__ = [
'Phase',
'GetSecretOptions',
'GetAllSecretsOptions',
'CreateSecretsOptions',
'UpdateSecretOptions',
'DeleteSecretOptions',
'PhaseSecret'
]
Loading
Loading