7.1 KiB
Sensitive Variables - Usage Guide
This document explains how to use the GNOME Keyring integration for storing sensitive variable values securely.
Overview
Roster now supports marking variables as sensitive, which stores their values encrypted in GNOME Keyring instead of plain text in the JSON file.
Use sensitive variables for:
- API keys (
api_key,secret_key) - Authentication tokens (
bearer_token,oauth_token) - Passwords (
password,db_password) - Any secret credentials
Use regular variables for:
- Base URLs (
base_url,api_endpoint) - Environment names (
env,region) - Non-sensitive configuration values
Storage
Regular Variables
Stored in: ~/.local/share/cz.bugsy.roster/requests.json
{
"projects": [{
"variable_names": ["base_url", "api_key"],
"sensitive_variables": [], // empty = not sensitive
"environments": [{
"variables": {
"base_url": "https://api.example.com", // visible in JSON
"api_key": "secret-key-123" // visible (NOT SAFE!)
}
}]
}]
}
Sensitive Variables
Stored in: GNOME Keyring (encrypted)
{
"projects": [{
"variable_names": ["base_url", "api_key"],
"sensitive_variables": ["api_key"], // marked as sensitive
"environments": [{
"variables": {
"base_url": "https://api.example.com", // visible in JSON
"api_key": "" // empty placeholder
}
}]
}]
}
The actual value of api_key is stored encrypted in GNOME Keyring and automatically retrieved when needed.
Code Examples
Basic Usage
from roster.project_manager import ProjectManager
pm = ProjectManager()
project_id = "your-project-id"
env_id = "your-environment-id"
# Mark a variable as sensitive (moves existing values to keyring)
pm.mark_variable_as_sensitive(project_id, "api_key")
# Set a sensitive variable value (goes to keyring)
pm.set_variable_value(project_id, env_id, "api_key", "my-secret-key-123")
# Get a sensitive variable value (retrieved from keyring)
value = pm.get_variable_value(project_id, env_id, "api_key")
# Returns: "my-secret-key-123"
# Check if variable is sensitive
is_sensitive = pm.is_variable_sensitive(project_id, "api_key")
# Returns: True
Using in Request Substitution
# Get environment with ALL values (including secrets from keyring)
environment = pm.get_environment_with_secrets(project_id, env_id)
# Now use this environment for variable substitution
from roster.variable_substitution import VariableSubstitution
vs = VariableSubstitution()
request = HttpRequest(
method="GET",
url="{{base_url}}/users",
headers={"Authorization": "Bearer {{api_key}}"},
body=""
)
substituted_request, undefined = vs.substitute_request(request, environment)
# Result:
# url = "https://api.example.com/users"
# headers = {"Authorization": "Bearer my-secret-key-123"}
Mark Variable as Sensitive
# Existing variable with values in all environments
pm.mark_variable_as_sensitive(project_id, "token")
# This will:
# 1. Add "token" to project.sensitive_variables list
# 2. Move all environment values to GNOME Keyring
# 3. Clear values in JSON (replaced with empty strings)
Mark Variable as Non-Sensitive
# Move back from keyring to JSON
pm.mark_variable_as_nonsensitive(project_id, "base_url")
# This will:
# 1. Remove "base_url" from project.sensitive_variables list
# 2. Move all environment values from keyring to JSON
# 3. Delete secrets from keyring
Variable Operations (Automatic Secret Handling)
# Rename a sensitive variable
pm.rename_variable(project_id, "old_token", "new_token")
# Automatically renames in both JSON AND keyring
# Delete a sensitive variable
pm.delete_variable(project_id, "api_key")
# Automatically deletes from both JSON AND keyring
# Delete an environment
pm.delete_environment(project_id, env_id)
# Automatically deletes all secrets for that environment
# Delete a project
pm.delete_project(project_id)
# Automatically deletes ALL secrets for that project
Integration with UI
When implementing UI for sensitive variables:
Variable List Display
# Show lock icon for sensitive variables
for var_name in project.variable_names:
is_sensitive = var_name in project.sensitive_variables
icon = "🔒" if is_sensitive else ""
label = f"{icon} {var_name}"
Variable Value Entry
# Use password entry for sensitive variables
entry = Gtk.Entry()
if var_name in project.sensitive_variables:
entry.set_visibility(False) # Show bullets instead of text
entry.set_input_purpose(Gtk.InputPurpose.PASSWORD)
Context Menu
# Right-click menu on variable
menu = Gio.Menu()
if pm.is_variable_sensitive(project_id, var_name):
menu.append("Mark as Non-Sensitive", f"app.mark-nonsensitive::{var_name}")
else:
menu.append("Mark as Sensitive", f"app.mark-sensitive::{var_name}")
How It Works
GNOME Keyring Schema
Each secret is stored with these attributes:
{
"project_id": "uuid-of-project",
"environment_id": "uuid-of-environment",
"variable_name": "api_key"
}
Label shown in Seahorse (Passwords and Keys app):
"Roster: ProjectName/EnvironmentName/variable_name"
Viewing Secrets in Seahorse
- Open "Passwords and Keys" application
- Look under "Login" keyring
- Find entries labeled "Roster: ..."
- These are your sensitive variable values
Security
- Encrypted at rest with your login password
- Automatically unlocked when you log in
- Protected by OS-level security
- Uses the same secure backend as browser passwords, WiFi passwords, SSH keys
Migration Guide
If you have existing variables with sensitive data:
project_id = "your-project-id"
sensitive_vars = ["api_key", "token", "password", "secret"]
for var_name in sensitive_vars:
pm.mark_variable_as_sensitive(project_id, var_name)
# Done! All values are now encrypted in GNOME Keyring
Error Handling
from roster.secret_manager import get_secret_manager
sm = get_secret_manager()
# store_secret returns bool
success = sm.store_secret(project_id, env_id, "api_key", "value")
if not success:
# Handle error (check logs)
print("Failed to store secret")
# retrieve_secret returns None on failure
value = sm.retrieve_secret(project_id, env_id, "api_key")
if value is None:
# Secret not found or error occurred
print("Secret not found")
Best Practices
-
Mark variables as sensitive BEFORE entering values
- This ensures values never touch the JSON file
-
Use descriptive variable names
github_tokeninstead oftokenstripe_api_keyinstead ofkey
-
Don't commit the JSON file with sensitive data
- If you accidentally stored secrets in JSON, mark as sensitive to move them
-
Regular variables are fine for most things
- Only use sensitive variables for actual secrets
- Base URLs, regions, etc. don't need encryption
-
Backup your GNOME Keyring
- Sensitive variables are stored in your system keyring
- Backup
~/.local/share/keyrings/if needed