semblance/backend/scripts/populate_db_direct.py
Vadym Samoilenko 3e1865edbd Apply Jintech security audit remediation (sprint 3) — 87/92 findings fixed
- Fix missing await on FocusGroup.get_messages() (N-L1)
- Replace time.sleep with asyncio.sleep in key_theme_service and focus_group_service (N-P10)
- Replace flask import with quart in focus_groups.py (N-S3)
- Add logger.error before all 500 returns in focus_groups.py (N-P6)
- Add logging to silent except blocks across routes (N-M10, N-M11)
- Add @rate_limit to 6 remaining AI endpoints (N-H4)
- Add --confirm flag to populate scripts before delete_many (S-H2)
- Remove hardcoded Azure ID fallbacks from msal_service.py and msalConfig.ts (A-M2, F-H4)
- Centralize make_serializable() in utils.py, remove duplicates from 3 route files (N-P7)
- Replace all datetime.utcnow() with datetime.now(timezone.utc) across entire backend (M-L2)
- AuthContext.tsx: only mark token validated on 200 success, not on non-401 errors (F-H2)
- Rename authType → auth_type in auth.py (N-S4)
- Add security_report.md and security_report.pdf with full 92-finding status

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 12:51:18 +00:00

548 lines
No EOL
22 KiB
Python
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
Standalone script to populate MongoDB with sample data for the Semblance Synthetic Society app.
This script doesn't rely on the backend modules and connects directly to MongoDB.
"""
import sys
import os
import json
import datetime
from pymongo import MongoClient
from getpass import getpass
from bson.objectid import ObjectId
import random
import string
# Sample persona data from the frontend
sample_personas = [
{
"id": "0",
"name": "Oliver Reynolds",
"age": "42",
"gender": "Male",
"occupation": "Senior Investment Manager",
"education": "Master's degree (Business and Finance)",
"location": "Kensington, London, UK",
"techSavviness": 85,
"personality": "Discerning, sophisticated, detail-oriented, values heritage and craftsmanship",
"interests": "Classic automobiles, high-end timepieces, luxury real estate, fine dining, art exhibitions",
"brandLoyalty": 90,
"priceConsciousness": 30,
"environmentalConcern": 60,
"hasPurchasingPower": True,
"hasChildren": True,
"thinkFeelDo": {
"thinks": [
"How does this reflect my personal standards and values?",
"Is this truly the pinnacle of craftsmanship and quality?",
"Will this purchase stand the test of time as a lasting investment?",
"How can this be further personalized to my exact preferences?"
],
"feels": [
"Proud to associate with heritage brands that reflect my achievements",
"Gratified by bespoke experiences that acknowledge my unique tastes",
"Frustrated by standardized approaches that fail to recognize individual preferences",
"Reassured by transparent, detailed information about craftsmanship and materials"
],
"does": [
"Conducts thorough research before making significant purchasing decisions",
"Seeks personalized consultations with dedicated specialists",
"Expects seamless integration between digital and in-person experiences",
"Values and maintains long-term relationships with trusted luxury brands",
"Regularly attends exclusive events and private showings"
]
},
"oceanTraits": {
"openness": 85,
"conscientiousness": 90,
"extraversion": 60,
"agreeableness": 65,
"neuroticism": 25
}
},
{
"id": "1",
"name": "Fiona Caldwell",
"age": "38",
"gender": "Female",
"occupation": "Founder and Creative Director of a luxury lifestyle brand",
"education": "First-Class Honours degree from a prestigious university",
"location": "Chelsea, London, UK",
"ethnicity": "White British",
"socialGrade": "A/B",
"householdIncome": "Approximately £195,000 per annum",
"householdComposition": "Single professional with established network",
"livingSituation": "Stylish, modern flat in exclusive London district",
"techSavviness": 90,
"personality": "Innovative, discerning, detail-oriented, values quality and distinctiveness",
"interests": "Bespoke fashion, high-end design, contemporary art, exclusive dining experiences",
"mediaConsumption": "Premium publications (The Spectator, Tatler, Vogue) and digital influencers",
"deviceUsage": "High-performance smartphone, tablet, and ultrabook; active on luxury-focused social platforms",
"shoppingHabits": "Prefers bespoke shopping with personalized digital interfaces and in-person exclusivity",
"brandPreferences": "Brands combining heritage with innovation; appreciates tailored craftsmanship",
"brandLoyalty": 85,
"priceConsciousness": 25,
"environmentalConcern": 70,
"hasPurchasingPower": True,
"hasChildren": False,
"communicationPreferences": "Clear, direct, personalized communication through premium channels",
"thinkFeelDo": {
"thinks": [
"How does this complement my personal brand and creative vision?",
"Is this innovative yet timeless enough for my lifestyle?",
"Will this experience or product truly stand out from the mainstream?",
"How can this be tailored to reflect my unique aesthetic sensibilities?"
],
"feels": [
"Excited by innovative designs that push creative boundaries",
"Valued when brands recognize her accomplishments and creative influence",
"Frustrated by cookie-cutter luxury experiences that lack personality",
"Inspired by perfect execution of bespoke experiences that reflect attention to detail"
],
"does": [
"Engages with immersive digital platforms and virtual showrooms",
"Attends exclusive industry events and creative collaborations",
"Seeks one-to-one consultancy sessions for significant purchases",
"Shares refined experiences within her select network of peers",
"Collaborates with luxury brands that align with her creative vision"
]
},
"oceanTraits": {
"openness": 95,
"conscientiousness": 85,
"extraversion": 70,
"agreeableness": 65,
"neuroticism": 30
}
},
{
"id": "2",
"name": "Michael Chen",
"age": "37",
"gender": "Male",
"occupation": "Software Engineer",
"location": "San Francisco, USA",
"techSavviness": 95,
"personality": "Analytical, detail-oriented, values efficiency",
"thinkFeelDo": {
"thinks": ["I need to understand how things work", "Efficiency is key"],
"feels": ["Annoyed by bugs or performance issues", "Satisfied by clean, logical interfaces"],
"does": ["Tests edge cases", "Reads documentation thoroughly"]
},
"oceanTraits": {
"openness": 70,
"conscientiousness": 90,
"extraversion": 40,
"agreeableness": 55,
"neuroticism": 30
}
},
{
"id": "4",
"name": "David Kim",
"age": "22",
"gender": "Male",
"occupation": "Student",
"location": "Austin, USA",
"techSavviness": 90,
"personality": "Curious, experimental, price-conscious",
"thinkFeelDo": {
"thinks": ["How can I customize this?", "Is this worth my time?"],
"feels": ["Bored by traditional interfaces", "Excited by customization options"],
"does": ["Tries all settings and features", "Abandons apps that don't engage quickly"]
},
"oceanTraits": {
"openness": 90,
"conscientiousness": 50,
"extraversion": 65,
"agreeableness": 70,
"neuroticism": 40
}
},
{
"id": "5",
"name": "Lisa Patel",
"age": "41",
"gender": "Female",
"occupation": "Product Manager",
"location": "Seattle, USA",
"techSavviness": 80,
"personality": "Strategic thinker, detail-oriented, collaborative",
"thinkFeelDo": {
"thinks": ["How does this fit into the ecosystem?", "What problems does this solve?"],
"feels": ["Concerned about integration issues", "Satisfied by cohesive user journeys"],
"does": ["Evaluates the full user journey", "Compares with competing products"]
},
"oceanTraits": {
"openness": 75,
"conscientiousness": 85,
"extraversion": 60,
"agreeableness": 75,
"neuroticism": 35
}
},
{
"id": "7",
"name": "Olivia Brown",
"age": "31",
"gender": "Female",
"occupation": "UX Designer",
"location": "Portland, USA",
"techSavviness": 90,
"personality": "Creative, empathetic, user-centered",
"thinkFeelDo": {
"thinks": ["How does this make users feel?", "Is this accessible to everyone?"],
"feels": ["Frustrated by poor accessibility", "Inspired by elegant solutions"],
"does": ["Analyzes micro-interactions", "Considers edge cases and accessibility"]
},
"oceanTraits": {
"openness": 85,
"conscientiousness": 75,
"extraversion": 60,
"agreeableness": 80,
"neuroticism": 40
}
},
{
"id": "8",
"name": "Arash Montazeri",
"age": "46",
"gender": "Male",
"occupation": "Senior Executive at a leading technology firm",
"education": "Bachelor's degree in Engineering from a prestigious UK university",
"location": "Ascot, Berkshire, UK",
"ethnicity": "Iranian-British",
"householdIncome": "Approximately £240,000 per annum",
"socialGrade": "A",
"householdComposition": "Married with two grown-up children",
"livingSituation": "Elegant country estate near Ascot blending British comfort and Persian design",
"techSavviness": 94,
"personality": "Integrates heritage and innovation; values bespoke, culturally nuanced service and excellence",
"interests": "Classic cars, bespoke tailoring, fine wines, Persian and contemporary art, luxury travel, golfing at country clubs",
"brandLoyalty": 95,
"priceConsciousness": 40,
"environmentalConcern": 75,
"hasPurchasingPower": True,
"hasChildren": True,
"deviceUsage": "Uses latest smartphones, tablets, smart home tech; prefers personalized luxury interfaces",
"shoppingHabits": "Relationship-driven, high-touch purchasing process with bespoke consultations; expects seamless online-offline integration",
"brandPreferences": "Heritage-driven, premium brands merging traditional craftsmanship with innovation (e.g., RollsRoyce)",
"paymentMethods": "Secure digital banking, premium credit, bespoke financing for high-value purchases",
"mediaConsumption": "Reads Financial Times, The Economist, and select cultural journals reflecting Iranian heritage and global outlook",
"coreValues": "Strong emphasis on heritage and innovation; bespoke service honoring tradition and Iranian culture",
"lifestyleChoices": "Golfing, fine dining at gourmet restaurants, immersive luxury travel, and revisiting Iranian roots",
"socialActivities": "Active in elite clubs, attends high-profile charity/cultural events, celebrates diversity and craftsmanship",
"categoryKnowledge": "Well-versed in luxury automotive engineering and bespoke options; values modern and traditional artistry",
"purchaseBehaviour": "Balances rational analysis and emotional attachment; major purchases are investments in legacy and taste",
"decisionInfluences": "Brand heritage, craftsmanship events, peer endorsements, transparency, and personalized narratives",
"painPoints": "Frustrated by fragmented, impersonal journeys and digital/in-person integration gaps",
"journeyContext": "Engages via invitation-only showrooms, virtual tours, and bespoke digital experiences with seamless support",
"keyTouchpoints": "One-to-one consultations, private previews of new bespoke options, post-purchase concierge support",
"communicationPreferences": "Prefers direct, timely engagement via a relationship manager, comfortable in-person and with premium digital",
"oceanTraits": {
"openness": 93,
"conscientiousness": 97,
"extraversion": 68,
"agreeableness": 64,
"neuroticism": 18
},
"selfDeterminationNeeds": {
"autonomy": "Seeks independence and offerings reflecting multifaceted identity",
"competence": "Desires recognition for refined taste and expects flawless service mirroring achievements",
"relatedness": "Wants personalized, respectful brand relationships honoring Iranian and British sophistication"
},
"motivations": [
"Pursuit of excellence in every aspect",
"Preserve cultural legacy through selective luxury experiences",
"Leave a lasting impact via refined, innovative purchases",
"Deep connections with heritage brands",
"Integrity and authenticity in every luxury engagement",
"Opportunities to express identity through bespoke, meaningful customization"
],
"fears": [
"Receiving subpar, impersonal service",
"Excessive digitization eroding tailored luxury experience"
],
"scenarioType": "Scenarios Across Life, Luxury, Technology, and Heritage",
"scenarios": [
"Arash attends a private RollsRoyce preview showcasing a bespoke vehicle that artfully blends British engineering with Persian design, collaborating one-on-one with brand artisans.",
"Invited to a virtual configurator experience, Arash works directly with a relationship manager to design a tailored vehicle from the comfort of his study, later completing the process with an in-person consultation.",
"At a high-profile cultural gala, Arash discusses his curated automotive and art collections, valuing brands that recognize and celebrate his unique heritage and refined taste.",
"Arash grows frustrated when a luxury brand's digital appointment system does not seamlessly coordinate with in-person experience, prompting him to seek out brands with superior omnichannel integration.",
"When considering a new bespoke vehicle, Arash weighs heritage, innovation, and family legacy, seeking a process that honors his background in every detail—from material selection to narrative storytelling.",
"Post-purchase, Arash values ongoing, dedicated aftercare provided by a trusted relationship manager, ensuring every aspect of ownership exceeds expectations and reflects his status."
],
"narrative": "Arash Montazeri exemplifies the modern luxury consumer who seamlessly integrates his Iranian heritage with contemporary British sophistication."
}
]
# Sample focus group data from the frontend
sample_focus_groups = [
{
"id": "1",
"name": "Mobile App UX Evaluation",
"status": "in-progress",
"participants": [
"1", "2", "4", "5", "7"
],
"date": "2023-06-12T15:30:00Z",
"duration": 60,
"topic": "user-experience",
"discussionGuide": """
# Discussion Guide: Mobile App UX Evaluation
## Introduction (5 minutes)
Welcome to our focus group discussion. Today we'll be exploring your experiences and opinions on our mobile app interface. There are no right or wrong answers, we're just interested in your honest thoughts.
## Warm-up Questions (10 minutes)
Let's start by introducing ourselves and sharing a bit about your daily smartphone usage.
## Navigation Experience Exploration (15 minutes)
Now, let's dive deeper into your experiences with the app navigation. What features do you find most intuitive? What frustrations have you encountered?
## Creative Testing (20 minutes)
We'll now show you some design concepts and get your feedback.
## Conclusion (10 minutes)
To wrap up, I'd like to hear your final thoughts on what we've discussed today and any additional insights you'd like to share.
"""
},
{
"id": "2",
"name": "Product Feature Feedback",
"status": "in-progress",
"participants": [
"1", "4", "5", "7"
],
"date": "2023-06-15T10:00:00Z",
"duration": 90,
"topic": "product-feedback",
"discussionGuide": """
# Discussion Guide: Product Feature Feedback
## Introduction (5 minutes)
Welcome to our focus group discussion. Today we'll be exploring your thoughts on our upcoming product features.
## Warm-up Questions (10 minutes)
Let's start by discussing your current experience with similar products.
## Feature Exploration (30 minutes)
We'll present several feature concepts and gather your feedback on each.
## Prioritization Exercise (15 minutes)
Help us understand which features would be most valuable to you.
## Conclusion (10 minutes)
Final thoughts and summary of the discussion.
"""
},
{
"id": "3",
"name": "Marketing Campaign Testing",
"status": "in-progress",
"participants": [
"2", "4", "7"
],
"date": "2023-06-12T15:30:00Z",
"duration": 45,
"topic": "creative-testing",
"discussionGuide": """
# Discussion Guide: Marketing Campaign Testing
## Introduction (5 minutes)
Welcome everyone. Today we're evaluating some marketing campaign concepts.
## Warm-up (5 minutes)
Brief discussion about marketing campaigns that have caught your attention recently.
## Campaign Concept Review (25 minutes)
We'll review several campaign directions and gather your impressions.
## Message Effectiveness (10 minutes)
Discussion about which messages resonate most strongly and why.
## Conclusion (5 minutes)
Final impressions and recommendations.
"""
}
]
def connect_to_mongodb():
"""Connect to MongoDB using MONGO_URI env var or interactive credentials."""
print("Connecting to MongoDB...")
# Prefer MONGO_URI from environment (S-H3: no credential brute-forcing)
mongo_uri = os.environ.get('MONGO_URI')
if mongo_uri:
try:
client = MongoClient(mongo_uri, serverSelectionTimeoutMS=5000)
db = client.semblance_db
db.command('ping')
print("Successfully connected to MongoDB using MONGO_URI")
return client, db
except Exception as e:
print(f"Could not connect using MONGO_URI (credentials redacted from error)")
sys.exit(1)
# Try connecting without auth (development environments)
try:
client = MongoClient('mongodb://localhost:27017', serverSelectionTimeoutMS=2000)
db = client.semblance_db
db.command('ping')
print("Successfully connected to MongoDB without authentication")
return client, db
except Exception as e:
pass
# Ask for credentials interactively
print("\nMongoDB requires authentication. Set MONGO_URI env var to avoid this prompt.")
username = input("MongoDB username: ")
password = getpass("MongoDB password: ")
try:
from urllib.parse import quote_plus
uri = f"mongodb://{quote_plus(username)}:{quote_plus(password)}@localhost:27017/semblance_db?authSource=admin"
client = MongoClient(uri, serverSelectionTimeoutMS=5000)
db = client.semblance_db
db.command('ping')
print("Successfully connected to MongoDB with provided credentials")
return client, db
except Exception as e:
print(f"Error connecting with provided credentials: {e}")
sys.exit(1)
def create_default_user(db):
"""Create a default admin user for sample data (DEV ONLY).
Password must be provided via SEED_ADMIN_PASSWORD env var.
"""
import bcrypt
username = os.environ.get('SEED_ADMIN_USERNAME', 'dev_admin')
password = os.environ.get('SEED_ADMIN_PASSWORD', '')
if not password:
print("ERROR: Set SEED_ADMIN_PASSWORD env var before running this script.")
sys.exit(1)
try:
existing_user = db.users.find_one({"username": username})
if existing_user:
print(f"User '{username}' already exists")
return existing_user["_id"]
# S-C1: Use bcrypt instead of MD5
password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
user = {
"username": username,
"email": f"{username}@example.com",
"password": password_hash,
"role": "admin", # S-M4: include role field
"created_at": datetime.datetime.now(datetime.timezone.utc).isoformat()
}
result = db.users.insert_one(user)
print(f"Created seed user '{username}'")
return result.inserted_id
except Exception as e:
print(f"Error creating seed user: {e}")
return ObjectId()
def main():
import argparse
parser = argparse.ArgumentParser(description="Populate MongoDB with sample data (DEV ONLY)")
parser.add_argument('--dry-run', action='store_true', help='Preview actions without writing to DB')
parser.add_argument('--confirm', action='store_true', help='Required: confirm destructive delete_many operations')
args = parser.parse_args()
# S-M2: Block execution in production environments
env = os.environ.get('FLASK_ENV', os.environ.get('APP_ENV', 'development'))
if env == 'production':
print("ERROR: This script must not be run in production. Set APP_ENV != production to override.")
sys.exit(1)
if args.dry_run:
print("[DRY RUN] No data will be written to the database.")
# Connect to MongoDB
client, db = connect_to_mongodb()
if args.dry_run:
print(f"[DRY RUN] Would insert {len(sample_personas)} personas and {len(sample_focus_groups)} focus groups.")
print(f"[DRY RUN] Would create seed user via SEED_ADMIN_USERNAME/SEED_ADMIN_PASSWORD env vars.")
sys.exit(0)
if not args.confirm:
print("ERROR: This script will delete all personas and focus groups. Pass --confirm to proceed.")
sys.exit(1)
# Create default user
user_id = create_default_user(db)
# Clear existing data
try:
db.personas.delete_many({})
db.focus_groups.delete_many({})
print("Cleared existing personas and focus groups")
except Exception as e:
print(f"Warning: Could not clear collections: {e}")
# Map from frontend IDs to MongoDB IDs
id_mapping = {}
# Import personas
print("\nAdding personas...")
for persona_data in sample_personas:
try:
# Remove frontend ID
frontend_id = persona_data.pop("id")
# Add metadata
persona_data["created_by"] = str(user_id)
persona_data["created_at"] = datetime.datetime.now()
# Insert into MongoDB
result = db.personas.insert_one(persona_data)
mongo_id = result.inserted_id
# Store mapping
id_mapping[frontend_id] = mongo_id
print(f"Imported persona: {persona_data.get('name')} (frontend ID: {frontend_id} → MongoDB ID: {mongo_id})")
except Exception as e:
print(f"Error importing persona: {e}")
# Import focus groups
print("\nAdding focus groups...")
for focus_group_data in sample_focus_groups:
try:
# Remove frontend ID
frontend_id = focus_group_data.pop("id")
# Map participants
frontend_participants = focus_group_data.pop("participants", [])
participants = []
for p_id in frontend_participants:
if p_id in id_mapping:
participants.append(id_mapping[p_id])
focus_group_data["participants"] = participants
# Add metadata
focus_group_data["created_by"] = str(user_id)
focus_group_data["created_at"] = datetime.datetime.now()
# Insert into MongoDB
result = db.focus_groups.insert_one(focus_group_data)
mongo_id = result.inserted_id
print(f"Imported focus group: {focus_group_data.get('name')} (frontend ID: {frontend_id} → MongoDB ID: {mongo_id})")
print(f" - Participants: {len(participants)}")
except Exception as e:
print(f"Error importing focus group: {e}")
print("\nData import complete!")
client.close()
if __name__ == "__main__":
main()