| {% extends "base.html" %} |
|
|
| {% block title %}Secrets - PyRunner{% endblock %} |
|
|
| {% block content %} |
| <div class="flex"> |
| {% include "cpanel/_sidebar.html" %} |
|
|
| <div class="flex-1 p-8"> |
| |
| <div class="flex items-start justify-between mb-8"> |
| <div> |
| <h1 class="text-2xl font-bold text-code-text">Secrets</h1> |
| <p class="text-code-muted">Encrypted credentials injected into scripts as environment variables</p> |
| </div> |
| {% if encryption_configured %} |
| <a href="{% url 'cpanel:secret_create' %}" |
| class="px-4 py-2 bg-code-accent hover:bg-code-accent/90 text-white font-semibold rounded-lg transition-colors inline-flex items-center"> |
| <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"/> |
| </svg> |
| Add Secret |
| </a> |
| {% endif %} |
| </div> |
|
|
| |
| {% if messages %} |
| <div class="mb-6 space-y-2"> |
| {% for message in messages %} |
| <div class="p-4 rounded-lg {% if message.tags == 'error' %}bg-code-red/10 border border-code-red/30 text-code-red{% elif message.tags == 'success' %}bg-code-green/10 border border-code-green/30 text-code-green{% else %}bg-code-accent/10 border border-code-accent/30 text-code-accent{% endif %}"> |
| {{ message }} |
| </div> |
| {% endfor %} |
| </div> |
| {% endif %} |
|
|
| |
| {% if not encryption_configured %} |
| <div class="mb-6 p-4 bg-code-red/10 border border-code-red/30 rounded-lg"> |
| <div class="flex items-start space-x-3"> |
| <svg class="w-5 h-5 text-code-red mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/> |
| </svg> |
| <div> |
| <h3 class="font-medium text-code-red">Encryption Not Configured</h3> |
| <p class="text-sm text-code-red/80 mt-1"> |
| Set the ENCRYPTION_KEY environment variable to enable secrets management. |
| Generate a key with: |
| </p> |
| <code class="block mt-2 p-2 bg-code-bg rounded text-xs font-mono text-code-text"> |
| python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" |
| </code> |
| </div> |
| </div> |
| </div> |
| {% endif %} |
|
|
| |
| {% if secrets %} |
| <div class="bg-code-surface border border-code-border rounded-xl overflow-hidden"> |
| <table class="w-full"> |
| <thead class="bg-code-bg border-b border-code-border"> |
| <tr> |
| <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Key</th> |
| <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Value</th> |
| <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Description</th> |
| <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Updated</th> |
| <th class="px-6 py-3 text-right text-xs font-semibold text-code-muted uppercase tracking-wider">Actions</th> |
| </tr> |
| </thead> |
| <tbody class="divide-y divide-code-border"> |
| {% for secret in secrets %} |
| <tr class="hover:bg-code-bg/50 transition-colors"> |
| <td class="px-6 py-4"> |
| <span class="font-mono text-code-accent">{{ secret.key }}</span> |
| </td> |
| <td class="px-6 py-4"> |
| <span class="font-mono text-code-muted text-sm">{{ secret.get_masked_value }}</span> |
| </td> |
| <td class="px-6 py-4 text-code-text text-sm max-w-xs truncate"> |
| {{ secret.description|default:"-" }} |
| </td> |
| <td class="px-6 py-4 text-code-muted text-sm"> |
| {{ secret.updated_at|timesince }} ago |
| </td> |
| <td class="px-6 py-4 text-right"> |
| <div class="flex items-center justify-end space-x-2"> |
| <a href="{% url 'cpanel:secret_edit' pk=secret.pk %}" |
| class="px-3 py-1.5 text-sm bg-code-surface border border-code-border hover:border-code-accent text-code-text rounded transition-colors"> |
| Edit |
| </a> |
| <form method="post" action="{% url 'cpanel:secret_delete' pk=secret.pk %}" |
| onsubmit="return confirm('Are you sure you want to delete the secret {{ secret.key }}? Scripts using this secret will fail.');" |
| class="inline"> |
| {% csrf_token %} |
| <button type="submit" |
| class="px-3 py-1.5 text-sm bg-code-red/10 border border-code-red/30 hover:bg-code-red/20 text-code-red rounded transition-colors"> |
| Delete |
| </button> |
| </form> |
| </div> |
| </td> |
| </tr> |
| {% endfor %} |
| </tbody> |
| </table> |
| </div> |
|
|
| |
| <div class="mt-6 p-4 bg-code-bg border border-code-border rounded-lg"> |
| <h3 class="text-sm font-medium text-code-text mb-2">Using Secrets in Scripts</h3> |
| <p class="text-sm text-code-muted mb-2"> |
| All secrets are automatically injected as environment variables when your scripts run. |
| </p> |
| <code class="block p-3 bg-code-surface rounded text-sm font-mono text-code-text"> |
| import os<br> |
| api_key = os.environ['YOUR_SECRET_KEY'] |
| </code> |
| </div> |
| {% else %} |
| <div class="bg-code-surface border border-code-border rounded-xl p-12 text-center"> |
| <div class="w-16 h-16 bg-code-accent/20 rounded-full flex items-center justify-center mx-auto mb-4"> |
| <svg class="w-8 h-8 text-code-accent" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/> |
| </svg> |
| </div> |
| <h3 class="text-lg font-semibold text-code-text mb-2">No secrets yet</h3> |
| <p class="text-code-muted mb-6">Add your first secret to store API keys and credentials securely.</p> |
| {% if encryption_configured %} |
| <a href="{% url 'cpanel:secret_create' %}" |
| class="px-6 py-2 bg-code-accent hover:bg-code-accent/90 text-white font-semibold rounded-lg transition-colors inline-flex items-center"> |
| <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"/> |
| </svg> |
| Add Secret |
| </a> |
| {% endif %} |
| </div> |
| {% endif %} |
| </div> |
| </div> |
| {% endblock %} |
|
|