feat: add security audit seed data with real findings from code review
All checks were successful
CI/CD / test (push) Successful in 18s
CI/CD / deploy (push) Successful in 1s

- Added seed-security.ts with comprehensive audit data for all 5 projects
- Real findings from actual code inspection: auth, CORS, rate limiting,
  error handling, dependencies, TLS certs, infrastructure
- 35 audit entries across Hammer Dashboard, Network App, Todo App, nKode,
  and Infrastructure
- Fixed unused deleteAudit import warning in SecurityPage
This commit is contained in:
2026-01-30 04:45:36 +00:00
parent dd2c80224e
commit fe18fc12f9
3 changed files with 480 additions and 3 deletions

View File

@@ -9,7 +9,8 @@
"db:push": "drizzle-kit push",
"db:studio": "drizzle-kit studio",
"test": "bun test",
"test:ci": "bun test --bail"
"test:ci": "bun test --bail",
"seed:security": "bun run src/seed-security.ts"
},
"dependencies": {
"@elysiajs/cors": "^1.2.0",

View File

@@ -0,0 +1,476 @@
import { db } from "./db";
import { securityAudits, type SecurityFinding } from "./db/schema";
const now = new Date().toISOString();
function finding(
status: SecurityFinding["status"],
title: string,
description: string,
recommendation: string
): SecurityFinding {
return {
id: crypto.randomUUID(),
status,
title,
description,
recommendation,
};
}
const auditData: {
projectName: string;
category: string;
score: number;
findings: SecurityFinding[];
}[] = [
// ═══════════════════════════════════════════
// HAMMER DASHBOARD
// ═══════════════════════════════════════════
{
projectName: "Hammer Dashboard",
category: "Authentication",
score: 75,
findings: [
finding("strong", "BetterAuth with email/password", "Uses BetterAuth library with email+password authentication, secure session management with cookie-based sessions.", ""),
finding("strong", "CSRF protection enabled", "BetterAuth CSRF check is explicitly enabled (disableCSRFCheck: false).", ""),
finding("strong", "Cross-subdomain cookies", "Secure cookie configuration with domain scoping to .donovankelly.xyz.", ""),
finding("needs_improvement", "No MFA support", "Multi-factor authentication is not implemented. Single-factor auth only.", "Add TOTP or WebAuthn MFA support via BetterAuth plugins."),
finding("needs_improvement", "No password policy enforcement", "No minimum password length, complexity, or breach-check enforcement visible in auth config.", "Configure BetterAuth password policy with minimum length (12+), complexity requirements."),
finding("needs_improvement", "Open signup", "emailAndPassword.enabled is true without disableSignUp — anyone can register.", "Set disableSignUp: true and use invite-only registration."),
],
},
{
projectName: "Hammer Dashboard",
category: "Authorization",
score: 70,
findings: [
finding("strong", "Role-based access control", "Users have roles (admin/user). Admin-only routes check role before processing.", ""),
finding("strong", "Bearer token + session dual auth", "API supports both session cookies and bearer token auth for programmatic access.", ""),
finding("needs_improvement", "Bearer token is env-based static token", "API_BEARER_TOKEN is a single static token shared across all API consumers. No per-client tokens.", "Implement per-client API keys or use OAuth2 client credentials."),
],
},
{
projectName: "Hammer Dashboard",
category: "Data Protection",
score: 80,
findings: [
finding("strong", "TLS encryption in transit", "All traffic served over HTTPS via Let's Encrypt certificates (auto-renewed). Valid cert for dash.donovankelly.xyz.", ""),
finding("strong", "Database in Docker network", "PostgreSQL is not exposed to the public internet — only accessible within the Docker compose network.", ""),
finding("needs_improvement", "No database encryption at rest", "PostgreSQL data volume uses default filesystem — no disk-level or column-level encryption.", "Consider enabling LUKS for the Docker volume or use PostgreSQL pgcrypto for sensitive columns."),
finding("needs_improvement", "No backup strategy visible", "No automated database backup configuration found in the compose file.", "Add pg_dump cron backup to S3 or another offsite location."),
],
},
{
projectName: "Hammer Dashboard",
category: "Infrastructure",
score: 70,
findings: [
finding("strong", "Container isolation", "Backend and database run as separate Docker containers with defined networking.", ""),
finding("strong", "Dokploy managed deployment", "Deployed via Dokploy with compose — automated builds and deploys on git push.", ""),
finding("needs_improvement", "Database uses simple credentials", "POSTGRES_USER/PASSWORD are set via env vars in docker-compose but appear to be simple values.", "Use strong randomly generated passwords stored in a secrets manager."),
finding("needs_improvement", "No health check monitoring", "Health endpoint exists (/health) but no external monitoring or alerting configured.", "Set up uptime monitoring (e.g., UptimeRobot, Betterstack) with alerts."),
],
},
{
projectName: "Hammer Dashboard",
category: "Application Security",
score: 65,
findings: [
finding("strong", "Elysia type validation on routes", "Most routes use Elysia's t.Object() schema validation for request bodies — provides automatic input validation.", ""),
finding("strong", "SQL injection protection via Drizzle ORM", "All database queries use Drizzle ORM's parameterized query builder — no raw SQL string concatenation.", ""),
finding("strong", "Generic error responses", "Error handler returns 'Internal server error' for unhandled errors without stack traces.", ""),
finding("needs_improvement", "No rate limiting", "No rate limiting middleware found on any routes. API is vulnerable to brute-force and abuse.", "Add rate limiting middleware (e.g., per-IP request limits on auth endpoints)."),
finding("needs_improvement", "CORS allows localhost", "CORS origin includes http://localhost:5173 in production, which is unnecessary.", "Remove localhost from CORS origins in production builds."),
finding("needs_improvement", "Some routes lack body validation", "Activity and chat routes have 0 type validations — accepting unvalidated input.", "Add t.Object() body/param validation to all routes."),
],
},
{
projectName: "Hammer Dashboard",
category: "Dependency Security",
score: 60,
findings: [
finding("needs_improvement", "Limited dependency set (good)", "Backend has only 5 production dependencies — small attack surface.", ""),
finding("needs_improvement", "No automated vulnerability scanning", "No bun audit or Snyk integration found. Dependencies not regularly checked for CVEs.", "Add dependency scanning to CI pipeline or run periodic audits."),
finding("needs_improvement", "Some dependencies slightly outdated", "Elysia 1.2.25 and drizzle-orm 0.44.2 — newer versions available with security fixes.", "Update to latest stable versions: elysia 1.4.x, drizzle-orm 0.45.x."),
],
},
{
projectName: "Hammer Dashboard",
category: "Logging & Monitoring",
score: 40,
findings: [
finding("needs_improvement", "Console-only logging", "Errors logged via console.error — no structured logging, no log aggregation.", "Use a structured logger (pino/winston) and ship logs to a central service."),
finding("critical", "No audit trail", "No logging of who accessed what, auth events, or data changes.", "Implement audit logging for auth events, CRUD operations, and admin actions."),
finding("critical", "No alerting", "No alerting on errors, failed auth attempts, or unusual activity.", "Set up alerting via email/Slack for critical errors and security events."),
],
},
{
projectName: "Hammer Dashboard",
category: "Compliance",
score: 45,
findings: [
finding("needs_improvement", "No data retention policy", "No defined policy for how long user data, tasks, or sessions are retained.", "Define and implement data retention policies — auto-expire old sessions, archive completed tasks."),
finding("needs_improvement", "No privacy policy", "No privacy policy or terms of service for users.", "Create a basic privacy policy documenting data collection and usage."),
finding("needs_improvement", "Session data lacks expiry cleanup", "Old sessions may accumulate in the database without cleanup.", "Add a periodic job to clean up expired sessions."),
],
},
// ═══════════════════════════════════════════
// NETWORK APP
// ═══════════════════════════════════════════
{
projectName: "Network App",
category: "Authentication",
score: 85,
findings: [
finding("strong", "BetterAuth with bearer plugin", "Uses BetterAuth with email/password and bearer token plugin for mobile app support.", ""),
finding("strong", "Invite-only registration", "Open signup is disabled (disableSignUp: true). Registration requires invite link.", ""),
finding("strong", "Session configuration", "7-day session expiry with daily refresh. Cookie caching enabled for 5 min. Cross-subdomain cookies with secure+sameSite:none.", ""),
finding("strong", "Signup endpoint blocked", "POST /api/auth/sign-up/email explicitly returns 403 — defense in depth on top of disableSignUp.", ""),
finding("needs_improvement", "No MFA", "No multi-factor authentication implemented.", "Add TOTP MFA via BetterAuth plugin."),
],
},
{
projectName: "Network App",
category: "Authorization",
score: 80,
findings: [
finding("strong", "Auth middleware plugin", "Dedicated authMiddleware Elysia plugin that derives user from session — consistently applied across routes.", ""),
finding("strong", "Admin separation", "Admin routes check user.role === 'admin' with dedicated admin routes.", ""),
finding("strong", "Scoped auth derivation", "Auth middleware uses 'as: scoped' derivation for proper Elysia context isolation.", ""),
],
},
{
projectName: "Network App",
category: "Application Security",
score: 80,
findings: [
finding("strong", "Rate limiting implemented", "Custom rate limiting middleware with per-IP buckets. Different limits for auth, general API, and sensitive routes.", ""),
finding("strong", "Extensive input validation", "Most routes (34+ files) use Elysia t.Object() type validation. High validation coverage.", ""),
finding("strong", "Drizzle ORM for SQL safety", "All queries via Drizzle ORM — parameterized, no raw SQL injection risk.", ""),
finding("needs_improvement", "Stack traces in error responses", "Error handler logs full stack traces and sends them in responses (line 100: stack) — even in production.", "Only include stack traces in development. Check NODE_ENV before including."),
finding("needs_improvement", "CORS allows any origin in fallback", "Falls back to localhost:3000 if ALLOWED_ORIGINS env not set — risky if env is misconfigured.", "Set a strict default origin list rather than localhost."),
],
},
{
projectName: "Network App",
category: "Data Protection",
score: 75,
findings: [
finding("strong", "TLS via Let's Encrypt", "Valid Let's Encrypt certificate for app.thenetwork.donovankelly.xyz. Auto-renewed.", ""),
finding("strong", "PII handling awareness", "Network app handles contacts and personal data — uses dedicated client/interaction models.", ""),
finding("needs_improvement", "No encryption at rest", "Contact data (names, emails, phone numbers) stored as plain text in PostgreSQL.", "Consider column-level encryption for PII fields."),
finding("needs_improvement", "Email service (Resend) integration", "Uses Resend for sending emails — API key stored in env vars.", "Ensure Resend API key is rotated periodically."),
],
},
{
projectName: "Network App",
category: "Dependency Security",
score: 55,
findings: [
finding("needs_improvement", "LangChain AI dependencies", "Includes @langchain/anthropic, @langchain/core, @langchain/openai — large dependency trees with potential supply chain risk.", "Audit LangChain dependencies regularly. Consider pinning exact versions."),
finding("needs_improvement", "No automated scanning", "No CI/CD vulnerability scanning configured.", "Add bun audit or Snyk scanning to the pipeline."),
],
},
{
projectName: "Network App",
category: "Logging & Monitoring",
score: 50,
findings: [
finding("strong", "Audit log routes", "Has dedicated audit-logs route — suggests audit logging infrastructure exists.", ""),
finding("needs_improvement", "Console-based logging", "Error logging via console.error only. No structured log format.", "Implement structured logging with request IDs and ship to log aggregation."),
finding("needs_improvement", "No external monitoring", "No uptime monitoring or alerting configured.", "Set up uptime monitoring and error alerting."),
],
},
{
projectName: "Network App",
category: "Infrastructure",
score: 75,
findings: [
finding("strong", "Docker container isolation", "Runs in isolated Docker containers on Dokploy.", ""),
finding("strong", "Production Dockerfile", "Multi-stage Dockerfile with production dependencies only (--production flag). NODE_ENV=production set.", ""),
finding("strong", "Entrypoint script", "Uses entrypoint.sh for startup — allows db:push before start.", ""),
finding("needs_improvement", "No container health checks", "Dockerfile doesn't define HEALTHCHECK instruction.", "Add Docker HEALTHCHECK to enable container auto-restart on failure."),
],
},
{
projectName: "Network App",
category: "Compliance",
score: 40,
findings: [
finding("needs_improvement", "Handles personal contacts", "Stores names, emails, phone numbers, notes about individuals — GDPR-relevant data.", "Implement data export and deletion capabilities for GDPR compliance."),
finding("needs_improvement", "No data retention policy", "No automatic cleanup of old data.", "Define retention periods for contacts and interactions."),
finding("critical", "No consent management", "No mechanism to track consent for storing contact information.", "Add consent tracking for contact data collection."),
],
},
// ═══════════════════════════════════════════
// TODO APP
// ═══════════════════════════════════════════
{
projectName: "Todo App",
category: "Authentication",
score: 80,
findings: [
finding("strong", "BetterAuth with invite system", "Uses BetterAuth for auth. Has a dedicated invite system with expiring tokens.", ""),
finding("strong", "Bearer token support", "Supports bearer tokens via @elysiajs/bearer for API access.", ""),
finding("strong", "Invite token validation", "Invite tokens are validated for expiry and status before acceptance.", ""),
finding("needs_improvement", "No MFA", "No multi-factor authentication available.", "Add TOTP MFA support."),
],
},
{
projectName: "Todo App",
category: "Authorization",
score: 75,
findings: [
finding("strong", "Hammer API key auth", "Separate authentication for the Hammer bot API using dedicated API key.", ""),
finding("strong", "Admin routes", "Admin routes with role checking for user management.", ""),
finding("needs_improvement", "Shared auth patterns", "Auth middleware duplicated across route files rather than centralized.", "Centralize auth middleware into a shared plugin like Network App does."),
],
},
{
projectName: "Todo App",
category: "Application Security",
score: 65,
findings: [
finding("strong", "Input validation", "Routes use Elysia type validation (t.Object) — high coverage across routes.", ""),
finding("strong", "Drizzle ORM", "Parameterized queries via Drizzle ORM prevent SQL injection.", ""),
finding("needs_improvement", "Stack traces conditional but present", "Error handler includes stack in non-production mode (NODE_ENV check). But stack is still captured.", "Ensure NODE_ENV=production is always set in deployed containers."),
finding("needs_improvement", "No rate limiting", "No rate limiting middleware found. Endpoints vulnerable to abuse.", "Implement rate limiting similar to Network App's approach."),
finding("needs_improvement", "CORS allows localhost fallback", "Falls back to localhost:5173 and todo.donovankelly.xyz if ALLOWED_ORIGINS not set.", "Remove localhost from production CORS."),
],
},
{
projectName: "Todo App",
category: "Data Protection",
score: 75,
findings: [
finding("strong", "TLS certificates valid", "Valid Let's Encrypt certs for api.todo.donovankelly.xyz and app.todo.donovankelly.xyz.", ""),
finding("strong", "Minimal PII", "Todo app stores minimal personal data — mainly task content.", ""),
finding("needs_improvement", "No backup automation", "No backup strategy visible in compose configuration.", "Add automated database backups."),
],
},
{
projectName: "Todo App",
category: "Dependency Security",
score: 55,
findings: [
finding("needs_improvement", "pg-boss dependency", "Uses pg-boss for job queuing — adds complexity and dependency surface.", "Ensure pg-boss is kept updated."),
finding("needs_improvement", "Zod v4 (beta)", "Using zod 4.3.6 which is a relatively new major version.", "Monitor for security advisories on the new Zod version."),
finding("needs_improvement", "No vulnerability scanning", "No automated dependency scanning in CI.", "Add scanning to CI pipeline."),
],
},
{
projectName: "Todo App",
category: "Infrastructure",
score: 70,
findings: [
finding("strong", "Docker compose with Dokploy", "Proper compose setup with db:push in CMD for schema management.", ""),
finding("strong", "Separate API and frontend", "API and frontend deployed as separate services.", ""),
finding("needs_improvement", "No health check monitoring", "No external monitoring configured.", "Add uptime monitoring."),
],
},
{
projectName: "Todo App",
category: "Logging & Monitoring",
score: 35,
findings: [
finding("needs_improvement", "Console logging only", "Errors logged to stdout/stderr via console. No structured logging.", "Implement structured logging."),
finding("critical", "No audit logging", "No tracking of user actions, auth events, or data changes.", "Add audit logging for all CRUD operations."),
finding("critical", "No alerting system", "No error alerting or uptime monitoring.", "Configure alerts for errors and downtime."),
],
},
{
projectName: "Todo App",
category: "Compliance",
score: 50,
findings: [
finding("needs_improvement", "No data retention policy", "No cleanup of completed tasks or expired sessions.", "Define data retention periods."),
finding("needs_improvement", "No privacy documentation", "No privacy policy for users.", "Create privacy policy."),
],
},
// ═══════════════════════════════════════════
// NKODE
// ═══════════════════════════════════════════
{
projectName: "nKode",
category: "Authentication",
score: 90,
findings: [
finding("strong", "OPAQUE protocol (state-of-the-art)", "Uses OPAQUE (opaque-ke v4) for password authentication — server never sees plaintext passwords. This is cryptographically stronger than traditional hashing.", ""),
finding("strong", "OIDC implementation", "Full OpenID Connect flow with discovery endpoint, JWKs, token endpoint, and userinfo.", ""),
finding("strong", "Argon2 password hashing", "OPAQUE configured with Argon2 (opaque-ke features=['argon2']) — the recommended modern password hashing algorithm.", ""),
finding("needs_improvement", "No MFA layer", "OPAQUE provides strong password auth but no second factor.", "Consider adding FIDO2/WebAuthn as a second factor."),
],
},
{
projectName: "nKode",
category: "Authorization",
score: 75,
findings: [
finding("strong", "Token-based authorization", "Uses OIDC tokens (JWT) for API authorization after OPAQUE login.", ""),
finding("strong", "Protected route extractors", "Has dedicated extractors.rs for auth extraction — consistent route protection.", ""),
finding("needs_improvement", "Role system unclear", "No visible role-based access control in the API routes.", "Implement RBAC if different user permission levels are needed."),
],
},
{
projectName: "nKode",
category: "Application Security",
score: 75,
findings: [
finding("strong", "Rust memory safety", "Backend written in Rust — eliminates entire classes of vulnerabilities (buffer overflows, use-after-free, data races).", ""),
finding("strong", "Type-safe with serde", "All request/response types defined with serde — strong input validation at deserialization.", ""),
finding("strong", "Axum framework", "Uses Axum (Tokio-based) — well-maintained with good security practices.", ""),
finding("needs_improvement", "CORS includes localhost", "CORS origins include localhost:3000 and localhost:5173 in production code.", "Move development origins to environment-only configuration."),
finding("needs_improvement", "No rate limiting visible", "No rate limiting middleware found in the Axum router setup.", "Add tower-governor or similar rate limiting middleware."),
],
},
{
projectName: "nKode",
category: "Data Protection",
score: 80,
findings: [
finding("strong", "TLS on all endpoints", "Valid Let's Encrypt certs for app.nkode.donovankelly.xyz and api.nkode.donovankelly.xyz.", ""),
finding("strong", "OPAQUE prevents password exposure", "Server stores OPAQUE registration records, not password hashes — even a database breach doesn't expose passwords.", ""),
finding("needs_improvement", "Login data storage", "Stores user login data (credentials manager data) — may contain sensitive information.", "Ensure login data is encrypted at the application level."),
],
},
{
projectName: "nKode",
category: "Dependency Security",
score: 75,
findings: [
finding("strong", "Rust ecosystem (cargo audit)", "Rust has cargo-audit for vulnerability checking. Smaller dependency trees than Node.js.", ""),
finding("strong", "Pinned versions", "Cargo.toml uses specific version ranges — reproducible builds.", ""),
finding("needs_improvement", "No CI audit pipeline", "No automated cargo-audit in CI.", "Add cargo-audit to CI pipeline."),
],
},
{
projectName: "nKode",
category: "Infrastructure",
score: 70,
findings: [
finding("strong", "Docker containerized", "Deployed as Docker container on Dokploy.", ""),
finding("strong", "Minimal base image", "Rust binary — small attack surface compared to Node.js containers.", ""),
finding("needs_improvement", "Service architecture spread", "Multiple microservices (OIDC, core, services) — increases operational complexity.", "Document service architecture and inter-service auth."),
],
},
{
projectName: "nKode",
category: "Logging & Monitoring",
score: 55,
findings: [
finding("strong", "tracing/tracing-subscriber", "Uses Rust tracing ecosystem — structured, span-based logging.", ""),
finding("needs_improvement", "Stdout only", "Logs go to stdout only. No log aggregation configured.", "Ship tracing output to a log aggregation service."),
finding("needs_improvement", "No alerting", "No alerting or monitoring configured.", "Set up monitoring and alerting."),
],
},
{
projectName: "nKode",
category: "Compliance",
score: 50,
findings: [
finding("needs_improvement", "Password manager data", "Stores user password/login data — high sensitivity. No documented data handling policy.", "Document data classification and handling procedures for stored credentials."),
finding("needs_improvement", "No data export/deletion", "No user data export or deletion capability visible.", "Implement GDPR-style data portability and right-to-erasure."),
],
},
// ═══════════════════════════════════════════
// INFRASTRUCTURE
// ═══════════════════════════════════════════
{
projectName: "Infrastructure",
category: "Authentication",
score: 65,
findings: [
finding("strong", "SSH key authentication available", "VPS supports SSH key authentication.", ""),
finding("strong", "Gitea self-hosted", "Self-hosted Gitea with authenticated access — no reliance on third-party code hosting.", ""),
finding("needs_improvement", "Git credentials in URL", "Git remote URLs contain credentials encoded in the URL string.", "Use SSH keys or git credential helper instead of URL-embedded credentials."),
finding("needs_improvement", "Dokploy API token", "Single API token for Dokploy management. Token compromise gives full deploy control.", "Rotate Dokploy API token periodically. Consider IP-restricted access."),
],
},
{
projectName: "Infrastructure",
category: "Data Protection",
score: 70,
findings: [
finding("strong", "TLS everywhere", "All 7 domains verified with valid Let's Encrypt certificates. Auto-renewal via Dokploy/Traefik.", ""),
finding("strong", "Separate VPS isolation", "Clawdbot VPS (72.60.68.214) and Dokploy VPS (191.101.0.153) are separate machines — blast radius limited.", ""),
finding("needs_improvement", "No centralized backup", "No unified backup strategy across all services.", "Implement automated backups for all databases to offsite storage."),
finding("needs_improvement", "DNS at Hostinger", "DNS managed through Hostinger control panel. No DNSSEC enabled.", "Consider enabling DNSSEC for donovankelly.xyz."),
],
},
{
projectName: "Infrastructure",
category: "Infrastructure",
score: 60,
findings: [
finding("strong", "Dokploy orchestration", "Dokploy manages container deployments with automated builds — reduces manual config drift.", ""),
finding("strong", "Let's Encrypt auto-renewal", "TLS certificates automatically renewed — no manual intervention needed.", ""),
finding("needs_improvement", "No firewall documentation", "Firewall rules for both VPS machines not documented or audited.", "Document and audit iptables/ufw rules on both VPS instances."),
finding("needs_improvement", "SSH configuration unknown", "SSH hardening status (password auth disabled, key-only, non-default port) not verified.", "Audit SSH config: disable password auth, use key-only, change default port."),
finding("needs_improvement", "No container vulnerability scanning", "Docker images not scanned for vulnerabilities before deployment.", "Add Trivy or similar container scanning to the deployment pipeline."),
finding("critical", "Exposed ports unknown", "No audit of which ports are exposed on both VPS machines.", "Run port scan audit on both VPS IPs and close unnecessary ports."),
],
},
{
projectName: "Infrastructure",
category: "Logging & Monitoring",
score: 30,
findings: [
finding("critical", "No centralized logging", "No log aggregation across services. Each container logs independently to stdout.", "Deploy a log aggregation stack (e.g., Loki + Grafana, or Betterstack)."),
finding("critical", "No uptime monitoring", "No external uptime monitoring for any of the 7+ domains.", "Set up UptimeRobot or Betterstack for all production domains."),
finding("critical", "No intrusion detection", "No IDS/IPS on either VPS. No fail2ban or similar tools verified.", "Install and configure fail2ban on both VPS instances."),
finding("needs_improvement", "No system update policy", "No documented policy for OS and package updates.", "Set up unattended-upgrades for security patches on both VPS machines."),
],
},
{
projectName: "Infrastructure",
category: "Compliance",
score: 40,
findings: [
finding("needs_improvement", "No incident response plan", "No documented procedure for security incidents.", "Create an incident response runbook."),
finding("needs_improvement", "No access review", "No periodic review of who has access to VPS, Dokploy, Gitea.", "Conduct quarterly access reviews."),
finding("needs_improvement", "No secrets rotation policy", "API tokens, database passwords, and auth secrets have no rotation schedule.", "Implement a secrets rotation policy (quarterly minimum)."),
],
},
];
async function seedSecurityAudits() {
console.log("🛡️ Seeding security audit data...");
// Clear existing data
await db.delete(securityAudits);
console.log(" Cleared existing audit data");
// Insert all audit data
for (const audit of auditData) {
await db.insert(securityAudits).values({
projectName: audit.projectName,
category: audit.category,
score: audit.score,
findings: audit.findings,
lastAudited: new Date(),
});
}
console.log(` ✅ Inserted ${auditData.length} audit entries across ${new Set(auditData.map(a => a.projectName)).size} projects`);
// Print summary
const projects = [...new Set(auditData.map(a => a.projectName))];
for (const project of projects) {
const projectAudits = auditData.filter(a => a.projectName === project);
const avgScore = Math.round(projectAudits.reduce((sum, a) => sum + a.score, 0) / projectAudits.length);
const totalFindings = projectAudits.reduce((sum, a) => sum + a.findings.length, 0);
console.log(` ${project}: avg score ${avgScore}/100, ${totalFindings} findings`);
}
process.exit(0);
}
seedSecurityAudits().catch((err) => {
console.error("Failed to seed security data:", err);
process.exit(1);
});