Initial commit: Clean DSS implementation

Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm

Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)

Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability

Migration completed: $(date)
🤖 Clean migration with full functionality preserved
This commit is contained in:
Digital Production Factory
2025-12-09 18:45:48 -03:00
commit 276ed71f31
884 changed files with 373737 additions and 0 deletions

253
tools/dss_mcp/security.py Normal file
View File

@@ -0,0 +1,253 @@
"""
DSS MCP Security Module
Handles encryption, decryption, and secure storage of sensitive credentials.
Uses cryptography library for AES-256 encryption with per-credential salt.
"""
import os
import json
import secrets
from typing import Optional, Dict, Any
from datetime import datetime
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend
from .config import mcp_config
from storage.database import get_connection # Use absolute import (tools/ is in sys.path)
class CredentialVault:
"""
Manages encrypted credential storage.
All credentials are encrypted using Fernet (AES-128 in CBC mode)
with PBKDF2-derived keys from a master encryption key.
"""
# Master encryption key (should be set via environment variable)
MASTER_KEY = os.environ.get('DSS_ENCRYPTION_KEY', '').encode()
@classmethod
def _get_cipher_suite(cls, salt: bytes) -> Fernet:
"""Derive encryption cipher from master key and salt"""
if not cls.MASTER_KEY:
raise ValueError(
"DSS_ENCRYPTION_KEY environment variable not set. "
"Required for credential encryption."
)
# Derive key from master key using PBKDF2
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
backend=default_backend()
)
key = kdf.derive(cls.MASTER_KEY)
# Encode key for Fernet
import base64
key_b64 = base64.urlsafe_b64encode(key)
return Fernet(key_b64)
@classmethod
def encrypt_credential(
cls,
credential_type: str,
credential_data: Dict[str, Any],
user_id: Optional[str] = None
) -> str:
"""
Encrypt and store a credential.
Args:
credential_type: Type of credential (figma_token, jira_token, etc.)
credential_data: Dictionary containing credential details
user_id: Optional user ID for multi-tenant security
Returns:
Credential ID for later retrieval
"""
import uuid
import base64
credential_id = str(uuid.uuid4())
salt = secrets.token_bytes(16) # 128-bit salt
# Serialize credential data
json_data = json.dumps(credential_data)
# Encrypt
cipher = cls._get_cipher_suite(salt)
encrypted = cipher.encrypt(json_data.encode())
# Store in database
with get_connection() as conn:
conn.execute("""
INSERT INTO credentials (
id, credential_type, encrypted_data, salt, user_id, created_at
) VALUES (?, ?, ?, ?, ?, ?)
""", (
credential_id,
credential_type,
encrypted.decode(),
base64.b64encode(salt).decode(),
user_id,
datetime.utcnow().isoformat()
))
return credential_id
@classmethod
def decrypt_credential(
cls,
credential_id: str
) -> Optional[Dict[str, Any]]:
"""
Decrypt and retrieve a credential.
Args:
credential_id: Credential ID from encrypt_credential()
Returns:
Decrypted credential data or None if not found
"""
import base64
with get_connection() as conn:
cursor = conn.cursor()
cursor.execute("""
SELECT encrypted_data, salt FROM credentials WHERE id = ?
""", (credential_id,))
row = cursor.fetchone()
if not row:
return None
encrypted_data, salt_b64 = row
salt = base64.b64decode(salt_b64)
# Decrypt
cipher = cls._get_cipher_suite(salt)
decrypted = cipher.decrypt(encrypted_data.encode())
return json.loads(decrypted.decode())
@classmethod
def delete_credential(cls, credential_id: str) -> bool:
"""Delete a credential"""
with get_connection() as conn:
cursor = conn.cursor()
cursor.execute("DELETE FROM credentials WHERE id = ?", (credential_id,))
return cursor.rowcount > 0
@classmethod
def list_credentials(
cls,
credential_type: Optional[str] = None,
user_id: Optional[str] = None
) -> list:
"""List credentials (metadata only, not decrypted)"""
with get_connection() as conn:
cursor = conn.cursor()
query = "SELECT id, credential_type, user_id, created_at FROM credentials WHERE 1=1"
params = []
if credential_type:
query += " AND credential_type = ?"
params.append(credential_type)
if user_id:
query += " AND user_id = ?"
params.append(user_id)
cursor.execute(query, params)
return [dict(row) for row in cursor.fetchall()]
@classmethod
def rotate_encryption_key(cls) -> bool:
"""
Rotate the master encryption key.
This re-encrypts all credentials with a new master key.
Requires new key to be set in DSS_ENCRYPTION_KEY_NEW environment variable.
"""
new_key = os.environ.get('DSS_ENCRYPTION_KEY_NEW', '').encode()
if not new_key:
raise ValueError(
"DSS_ENCRYPTION_KEY_NEW environment variable not set for key rotation"
)
try:
with get_connection() as conn:
cursor = conn.cursor()
# Get all credentials
cursor.execute("SELECT id, encrypted_data, salt FROM credentials")
rows = cursor.fetchall()
# Re-encrypt with new key
for row in rows:
credential_id, encrypted_data, salt_b64 = row
import base64
salt = base64.b64decode(salt_b64)
# Decrypt with old key
old_cipher = cls._get_cipher_suite(salt)
decrypted = old_cipher.decrypt(encrypted_data.encode())
# Encrypt with new key (use new master key)
old_master = cls.MASTER_KEY
cls.MASTER_KEY = new_key
try:
new_cipher = cls._get_cipher_suite(salt)
new_encrypted = new_cipher.encrypt(decrypted)
# Update database
conn.execute(
"UPDATE credentials SET encrypted_data = ? WHERE id = ?",
(new_encrypted.decode(), credential_id)
)
finally:
cls.MASTER_KEY = old_master
# Update environment
os.environ['DSS_ENCRYPTION_KEY'] = new_key.decode()
return True
except Exception as e:
raise RuntimeError(f"Key rotation failed: {str(e)}")
@classmethod
def ensure_credentials_table(cls):
"""Ensure credentials table exists"""
with get_connection() as conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS credentials (
id TEXT PRIMARY KEY,
credential_type TEXT NOT NULL,
encrypted_data TEXT NOT NULL,
salt TEXT NOT NULL,
user_id TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
)
""")
conn.execute(
"CREATE INDEX IF NOT EXISTS idx_credentials_type ON credentials(credential_type)"
)
conn.execute(
"CREATE INDEX IF NOT EXISTS idx_credentials_user ON credentials(user_id)"
)
# Initialize table on import
CredentialVault.ensure_credentials_table()