Source code for smarter.apps.account.management.commands.update_secret

"""
Django management command to update the encrypted value of a Secret.

This module defines the ``update_secret`` management command for the Smarter platform.
It allows administrators or users to update the encrypted value for a named Secret
associated with a user's profile.

Features
--------
- Updates or sets a new encrypted value for an existing Secret belonging to a user.
- Associates the Secret to the specified user or the current user if not explicitly provided.
- If the value is not passed as an argument, it prompts securely for one at runtime.
- Provides command-line feedback for errors such as missing users, user profiles, or secrets.

Command-line Options
-------------------
- ``--name``: The name of the Smarter Secret to update (required).
- ``--username``: The username associated with the Secret. If not provided, will attempt to use the current user.
- ``--value``: The value to encrypt and store. If not provided, you will be securely prompted for it.

Typical Usage
-------------
Used by administrators or trusted users via ``manage.py update_secret`` to update account secrets,
such as API keys, credentials, or private tokens.
"""

import getpass

from smarter.apps.secret.models import Secret, User, UserProfile
from smarter.lib.django.management.base import SmarterCommand


# pylint: disable=E1101
[docs] class Command(SmarterCommand): """Django manage.py create_user command. This command is used to update the encrypted value of a Secret. """
[docs] def add_arguments(self, parser): """Add arguments to the command.""" parser.add_argument( "--name", type=str, help="The name of the Smarter Secret to update. This is the name of the Secret, not the key.", ) parser.add_argument( "--username", type=str, help="The user to associate with this Secret. If not provided, the current user will be used.", ) parser.add_argument( "--value", type=str, help="The value to encrypt and persist. If not provided, you will be prompted." )
[docs] def handle(self, *args, **options): """Create the superuser account.""" self.handle_begin() name = options.get("name") if not name: self.stdout.write(self.style.ERROR("You must provide a name for the Secret")) return username = options.get("username") if not username: self.stdout.write(self.style.ERROR("No username provided, using the current user for this Secret.")) return value = options.get("value") if not value: value = getpass.getpass(f"Provide the value for Secret {name} owned by user {username}: ") value = Secret.encrypt(value) try: user = User.objects.get(username=username) except User.DoesNotExist as e: self.handle_completed_failure(e, msg=f"User '{username}' does not exist.") return user_profile = UserProfile.get_cached_object(user=user) if not user_profile: self.handle_completed_failure(msg=f"User profile for '{username}' does not exist.") return try: secret = Secret.objects.get(name=name, user_profile=user_profile) secret.encrypted_value = value secret.save() except Secret.DoesNotExist as e: self.handle_completed_failure(e, msg=f"Secret '{name}' does not exist for user '{username}'.") return # pylint: disable=W0718 except Exception as e: self.handle_completed_failure(e) return self.handle_completed_success()