Skip to content

Commit

Permalink
Feat: add --app-id flag (#173)
Browse files Browse the repository at this point in the history
* chore: remove commented gh actions workflow

* feat: refactored phase_get_context to handle app_id

* feat: add app_id support in phase_io crud

* feat: app_id in phase secrets create

* feat: app_id in phase run

* feat: app_id in phase secrets delete

* feat: app_id in phase secrets delete

* feat: app_id in phase secrets get

* feat: app_id in phase secrets list

* feat: app_id in phase secrets update

* feat: app_id in phase secrets import

* feat: added --app-id flag, updated comments

* fix: add phase_app_id context in phase_list_secrets after deleting secrets

* fix: pass phase+app_id context to phase_list_secrets after secret creation

* feat: use console.log

* fix: match the application using app_id first, then fall back to app_name if app_id is not provided

* fix: pass phase_app_id context to phase secret list after updating secrets

* feat: add --app-id flag to phase secrets update

* chore: bump version

* fix: phase run test and added run with app_id test
  • Loading branch information
nimish-ks authored Oct 28, 2024
1 parent ffd4e8f commit 82a7036
Show file tree
Hide file tree
Showing 16 changed files with 140 additions and 116 deletions.
18 changes: 0 additions & 18 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,6 @@ jobs:
if: runner.os == 'Windows'
shell: pwsh

# # Download the version file
# - uses: actions/download-artifact@v4
# with:
# name: phase-version

# # DEBUG
# - name: List files after downloading artifact
# shell: bash
# run: ls -al

# # Set the version environment variable
# - name: Set VERSION
# shell: bash
# run: |
# PHASE_CLI_VERSION=$(cat PHASE_CLI_VERSION.txt)
# echo "PHASE_CLI_VERSION is: $PHASE_CLI_VERSION"
# echo "PHASE_CLI_VERSION=$PHASE_CLI_VERSION" >> $GITHUB_ENV

# Build DEB and RPM packages for Linux
- run: |
sudo apt-get update
Expand Down
5 changes: 0 additions & 5 deletions .github/workflows/version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,3 @@ jobs:
else
echo "Versions match: ${{ steps.extract_version.outputs.version }}"
fi
# - uses: actions/upload-artifact@v4
# with:
# name: phase-version
# path: ./PHASE_CLI_VERSION.txt
2 changes: 1 addition & 1 deletion APKBUILD
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Maintainer: Phase <[email protected]>
pkgname=phase
pkgver=1.18.4
pkgver=1.18.5
pkgrel=0
pkgdesc="Phase CLI"
url="https://phase.dev"
Expand Down
4 changes: 2 additions & 2 deletions phase_cli/cmd/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from rich.console import Console
from rich.progress import Progress, SpinnerColumn, TimeElapsedColumn

def phase_run_inject(command, env_name=None, phase_app=None, tags=None, path: str = '/'):
def phase_run_inject(command, env_name=None, phase_app=None, phase_app_id=None, tags=None, path: str = '/'):
"""
Executes a shell command with environment variables set to the secrets
fetched from Phase for the specified environment, resolving references as needed.
Expand All @@ -31,7 +31,7 @@ def phase_run_inject(command, env_name=None, phase_app=None, tags=None, path: st
task1 = progress.add_task("[bold green]Fetching secrets...", total=None)

# Fetch all secrets
all_secrets = phase.get(env_name=env_name, app_name=phase_app, tag=tags, path=path)
all_secrets = phase.get(env_name=env_name, app_name=phase_app, app_id=phase_app_id, tag=tags, path=path)

# Organize all secrets into a dictionary for easier lookup
secrets_dict = {}
Expand Down
10 changes: 5 additions & 5 deletions phase_cli/cmd/secrets/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from phase_cli.utils.crypto import generate_random_secret
from rich.console import Console

def phase_secrets_create(key=None, env_name=None, phase_app=None, random_type=None, random_length=None, path='/', override=False):
def phase_secrets_create(key=None, env_name=None, phase_app=None, phase_app_id=None, random_type=None, random_length=None, path='/', override=False):
"""
Creates a new secret, encrypts it, and syncs it with the Phase, with support for specifying a path and overrides.
Expand Down Expand Up @@ -36,7 +36,7 @@ def phase_secrets_create(key=None, env_name=None, phase_app=None, random_type=No
elif random_type:
# Check if length is specified for key128 or key256
if random_type in ['key128', 'key256'] and random_length != 32:
print("⚠️\u200A Warning: The length argument is ignored for 'key128' and 'key256'. Using default lengths.")
console.log("⚠️\u200A Warning: The length argument is ignored for 'key128' and 'key256'. Using default lengths.")

try:
value = generate_random_secret(random_type, random_length)
Expand All @@ -58,15 +58,15 @@ def phase_secrets_create(key=None, env_name=None, phase_app=None, random_type=No

try:
# Encrypt and POST secret to the backend using phase create
response = phase.create(key_value_pairs=[(key, value)], env_name=env_name, app_name=phase_app, path=path, override_value=override_value)
response = phase.create(key_value_pairs=[(key, value)], env_name=env_name, app_name=phase_app, app_id=phase_app_id, path=path, override_value=override_value)

# Check the response status code
if response.status_code == 200:
# Call the phase_list_secrets function to list the secrets
phase_list_secrets(show=False, phase_app=phase_app, env_name=env_name, path=path)
phase_list_secrets(show=False, phase_app=phase_app, phase_app_id=phase_app_id, env_name=env_name, path=path)
else:
# Print an error message if the response status code indicates an error
print(f"Error: Failed to create secret. HTTP Status Code: {response.status_code}")
console.log(f"Error: Failed to create secret. HTTP Status Code: {response.status_code}")

except ValueError as e:
console.log(f"Error: {e}")
6 changes: 3 additions & 3 deletions phase_cli/cmd/secrets/delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from rich.console import Console
from typing import List

def phase_secrets_delete(keys_to_delete: List[str] = None, env_name: str = None, phase_app: str = None, path: str = None):
def phase_secrets_delete(keys_to_delete: List[str] = None, env_name: str = None, phase_app: str = None, phase_app_id: str = None, path: str = None):
"""
Deletes encrypted secrets based on key values, with optional path support.
Expand All @@ -27,15 +27,15 @@ def phase_secrets_delete(keys_to_delete: List[str] = None, env_name: str = None,

try:
# Delete keys within the specified path and get the list of keys not found
keys_not_found = phase.delete(env_name=env_name, keys_to_delete=keys_to_delete, app_name=phase_app, path=path)
keys_not_found = phase.delete(env_name=env_name, keys_to_delete=keys_to_delete, app_name=phase_app, app_id=phase_app_id, path=path)

if keys_not_found:
console.log(f"⚠️ Warning: The following keys were not found: {', '.join(keys_not_found)}")
else:
console.log("✅ Successfully deleted the secrets.")

# Optionally, list remaining secrets to confirm deletion
phase_list_secrets(show=False, env_name=env_name, phase_app=phase_app, path=path)
phase_list_secrets(show=False, env_name=env_name, phase_app=phase_app, phase_app_id=phase_app_id, path=path)

except ValueError as e:
console.log(f"Error: {e}")
4 changes: 2 additions & 2 deletions phase_cli/cmd/secrets/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from rich.progress import Progress, SpinnerColumn, BarColumn, TextColumn


def phase_secrets_env_export(env_name=None, phase_app=None, keys=None, tags=None, format='dotenv', path: str = ''):
def phase_secrets_env_export(env_name=None, phase_app=None, phase_app_id=None, keys=None, tags=None, format='dotenv', path: str = ''):
"""
Exports secrets from the specified environment with support for multiple export formats.
This function fetches secrets from Phase, resolves any cross-environment or local secret references, and then outputs them in the chosen format.
Expand Down Expand Up @@ -51,7 +51,7 @@ def phase_secrets_env_export(env_name=None, phase_app=None, keys=None, tags=None

try:
# Fetch all secrets
all_secrets = phase.get(env_name=env_name, app_name=phase_app, tag=tags, path=path)
all_secrets = phase.get(env_name=env_name, app_name=phase_app, app_id=phase_app_id, tag=tags, path=path)

# Organize all secrets into a dictionary for easier lookup.
secrets_dict = {}
Expand Down
4 changes: 2 additions & 2 deletions phase_cli/cmd/secrets/get.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from rich.console import Console
import json

def phase_secrets_get(key, env_name=None, phase_app=None, tags=None, path='/'):
def phase_secrets_get(key, env_name=None, phase_app=None, phase_app_id=None, tags=None, path='/'):
"""
Fetch and print a single secret based on a given key as beautified JSON with syntax highlighting.
Expand All @@ -18,7 +18,7 @@ def phase_secrets_get(key, env_name=None, phase_app=None, tags=None, path='/'):

try:
key = key.upper()
secrets_data = phase.get(env_name=env_name, keys=[key], app_name=phase_app, tag=tags, path=path)
secrets_data = phase.get(env_name=env_name, keys=[key], app_name=phase_app, app_id=phase_app_id, tag=tags, path=path)

# Find the specific secret for the given key within the provided path
secret_data = next((secret for secret in secrets_data if secret["key"] == key), None)
Expand Down
14 changes: 7 additions & 7 deletions phase_cli/cmd/secrets/import_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from phase_cli.utils.misc import get_default_user_id, sanitize_value
from rich.console import Console

def phase_secrets_env_import(env_file, env_name=None, phase_app=None, path: str = '/'):
def phase_secrets_env_import(env_file, env_name=None, phase_app=None, phase_app_id=None, path: str = '/'):
"""
Imports existing environment variables and secrets from a user's .env file.
Expand Down Expand Up @@ -32,23 +32,23 @@ def phase_secrets_env_import(env_file, env_name=None, phase_app=None, path: str
secrets.append((key.strip().upper(), sanitize_value(value.strip())))

except FileNotFoundError:
print(f"Error: The file {env_file} was not found.")
console.log(f"Error: The file {env_file} was not found.")
sys.exit(1)

try:
# Encrypt and send secrets to the backend using the `create` method
response = phase.create(key_value_pairs=secrets, env_name=env_name, app_name=phase_app, path=path)
response = phase.create(key_value_pairs=secrets, env_name=env_name, app_name=phase_app, app_id=phase_app_id, path=path)

# Check the response status code
if response.status_code == 200:
print(f"Successfully imported and encrypted {len(secrets)} secrets.")
console.log(f"Successfully imported and encrypted {len(secrets)} secrets.")
if env_name == None:
print("To view them please run: phase secrets list")
console.log("To view them please run: phase secrets list")
else:
print(f"To view them please run: phase secrets list --env {env_name}")
console.log(f"To view them please run: phase secrets list --env {env_name}")
else:
# Print an error message if the response status code indicates an error
print(f"Error: Failed to import secrets. HTTP Status Code: {response.status_code}")
console.log(f"Error: Failed to import secrets. HTTP Status Code: {response.status_code}")

except ValueError as e:
console.log(f"Error: {e}")
4 changes: 2 additions & 2 deletions phase_cli/cmd/secrets/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from phase_cli.utils.misc import render_tree_with_tables
from rich.console import Console

def phase_list_secrets(show=False, env_name=None, phase_app=None, tags=None, path=''):
def phase_list_secrets(show=False, env_name=None, phase_app=None, phase_app_id=None, tags=None, path=''):
"""
Lists the secrets fetched from Phase for the specified environment, optionally filtered by tags and path.
Expand All @@ -21,7 +21,7 @@ def phase_list_secrets(show=False, env_name=None, phase_app=None, tags=None, pat
console = Console()

try:
secrets_data = phase.get(env_name=env_name, app_name=phase_app, tag=tags, path=path)
secrets_data = phase.get(env_name=env_name, app_name=phase_app, app_id=phase_app_id, tag=tags, path=path)

# Check that secrets_data is a list of dictionaries
if not isinstance(secrets_data, list):
Expand Down
7 changes: 4 additions & 3 deletions phase_cli/cmd/secrets/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from phase_cli.utils.crypto import generate_random_secret
from rich.console import Console

def phase_secrets_update(key, env_name=None, phase_app=None, random_type=None, random_length=None, source_path='', destination_path=None, override=False, toggle_override=False):
def phase_secrets_update(key, env_name=None, phase_app=None, phase_app_id=None, random_type=None, random_length=None, source_path='', destination_path=None, override=False, toggle_override=False):
"""
Updates a secret with a new value or a randomly generated value, with optional source and destination path support.
Expand Down Expand Up @@ -59,7 +59,8 @@ def phase_secrets_update(key, env_name=None, phase_app=None, random_type=None, r
env_name=env_name,
key=key,
value=new_value,
app_name=phase_app,
app_name=phase_app,
app_id=phase_app_id,
source_path=source_path,
destination_path=destination_path,
override=override,
Expand All @@ -69,7 +70,7 @@ def phase_secrets_update(key, env_name=None, phase_app=None, random_type=None, r
console.log("✅ Successfully updated the secret.")

# Optionally, list secrets after update to confirm the change
phase_list_secrets(show=False, phase_app=phase_app, env_name=env_name, path=destination_path or source_path)
phase_list_secrets(show=False, phase_app=phase_app, env_name=env_name, phase_app_id=phase_app_id, path=destination_path or source_path)
else:
console.log(f"{response}")
except ValueError as e:
Expand Down
Loading

0 comments on commit 82a7036

Please sign in to comment.