feat(server): add security middleware and website-specific routes
Server Infrastructure Updates: - Added response sanitization middleware (fixes Date serialization) - Added CSRF protection middleware (double-submit cookie pattern) - Enhanced rate limiting (public, form, auth limiters) - Added cache control middleware for static assets - Added cookie parser for CSRF support Route Organization: - Reorganized routes for website (auth, documents, blog, newsletter) - Separated admin routes with /admin prefix - Added koha routes for donations - Added demo routes for interactive demonstrations - Dev/test routes only in development environment Config Updates: - Updated app config for website platform - Added website-specific configuration options Model Updates: - Updated model exports for website collections - Added blog, media, newsletter models These changes support the website platform while maintaining the underlying Tractatus governance framework.
This commit is contained in:
parent
792a9e55b6
commit
4c656385fe
4 changed files with 317 additions and 101 deletions
|
|
@ -1,13 +1,12 @@
|
|||
/**
|
||||
* Application Configuration
|
||||
* Generic configuration template for Tractatus Framework implementations
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Server
|
||||
port: process.env.PORT || 9000,
|
||||
env: process.env.NODE_ENV || 'development',
|
||||
appName: process.env.APP_NAME || 'Tractatus Framework',
|
||||
appName: process.env.APP_NAME || 'Tractatus',
|
||||
|
||||
// MongoDB
|
||||
mongodb: {
|
||||
|
|
@ -15,12 +14,30 @@ module.exports = {
|
|||
db: process.env.MONGODB_DB || 'tractatus_dev'
|
||||
},
|
||||
|
||||
// JWT
|
||||
jwt: {
|
||||
secret: process.env.JWT_SECRET || 'CHANGE_THIS_IN_PRODUCTION',
|
||||
expiry: process.env.JWT_EXPIRY || '7d'
|
||||
},
|
||||
|
||||
// Admin
|
||||
admin: {
|
||||
email: process.env.ADMIN_EMAIL || 'john.stroh.nz@pm.me'
|
||||
},
|
||||
|
||||
// Logging
|
||||
logging: {
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
file: process.env.LOG_FILE || 'logs/app.log'
|
||||
},
|
||||
|
||||
// Feature Flags
|
||||
features: {
|
||||
aiCuration: process.env.ENABLE_AI_CURATION === 'true',
|
||||
mediaTriage: process.env.ENABLE_MEDIA_TRIAGE === 'true',
|
||||
caseSubmissions: process.env.ENABLE_CASE_SUBMISSIONS === 'true'
|
||||
},
|
||||
|
||||
// Security
|
||||
security: {
|
||||
rateLimitWindowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS || '900000'), // 15 min
|
||||
|
|
|
|||
|
|
@ -1,26 +1,28 @@
|
|||
/**
|
||||
* Models Index
|
||||
* Export all Tractatus Framework models
|
||||
* Export all models
|
||||
*/
|
||||
|
||||
const AuditLog = require('./AuditLog.model');
|
||||
const DeliberationSession = require('./DeliberationSession.model');
|
||||
const Document = require('./Document.model');
|
||||
const BlogPost = require('./BlogPost.model');
|
||||
const MediaInquiry = require('./MediaInquiry.model');
|
||||
const CaseSubmission = require('./CaseSubmission.model');
|
||||
const Resource = require('./Resource.model');
|
||||
const ModerationQueue = require('./ModerationQueue.model');
|
||||
const User = require('./User.model');
|
||||
const GovernanceLog = require('./GovernanceLog.model');
|
||||
const GovernanceRule = require('./GovernanceRule.model');
|
||||
const DeliberationSession = require('./DeliberationSession.model');
|
||||
const Precedent = require('./Precedent.model');
|
||||
const Project = require('./Project.model');
|
||||
const SessionState = require('./SessionState.model');
|
||||
const VariableValue = require('./VariableValue.model');
|
||||
const VerificationLog = require('./VerificationLog.model');
|
||||
|
||||
module.exports = {
|
||||
AuditLog,
|
||||
DeliberationSession,
|
||||
Document,
|
||||
BlogPost,
|
||||
MediaInquiry,
|
||||
CaseSubmission,
|
||||
Resource,
|
||||
ModerationQueue,
|
||||
User,
|
||||
GovernanceLog,
|
||||
GovernanceRule,
|
||||
Precedent,
|
||||
Project,
|
||||
SessionState,
|
||||
VariableValue,
|
||||
VerificationLog
|
||||
DeliberationSession,
|
||||
Precedent
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,71 +1,147 @@
|
|||
/**
|
||||
* Routes Index
|
||||
* Central routing configuration for Tractatus Framework API
|
||||
* Central routing configuration
|
||||
*/
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
// Import framework route modules
|
||||
// Import route modules
|
||||
const authRoutes = require('./auth.routes');
|
||||
const documentsRoutes = require('./documents.routes');
|
||||
const blogRoutes = require('./blog.routes');
|
||||
const newsletterRoutes = require('./newsletter.routes');
|
||||
const mediaRoutes = require('./media.routes');
|
||||
const casesRoutes = require('./cases.routes');
|
||||
const adminRoutes = require('./admin.routes');
|
||||
const hooksMetricsRoutes = require('./hooks-metrics.routes');
|
||||
const syncHealthRoutes = require('./sync-health.routes');
|
||||
const rulesRoutes = require('./rules.routes');
|
||||
const projectsRoutes = require('./projects.routes');
|
||||
const auditRoutes = require('./audit.routes');
|
||||
const governanceRoutes = require('./governance.routes');
|
||||
const kohaRoutes = require('./koha.routes');
|
||||
const demoRoutes = require('./demo.routes');
|
||||
|
||||
// Mount framework routes
|
||||
router.use('/rules', rulesRoutes);
|
||||
router.use('/projects', projectsRoutes);
|
||||
router.use('/audit', auditRoutes);
|
||||
// Development/test routes (only in development)
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const testRoutes = require('./test.routes');
|
||||
router.use('/test', testRoutes);
|
||||
}
|
||||
|
||||
// Mount routes
|
||||
router.use('/auth', authRoutes);
|
||||
router.use('/documents', documentsRoutes);
|
||||
router.use('/blog', blogRoutes);
|
||||
router.use('/newsletter', newsletterRoutes);
|
||||
router.use('/media', mediaRoutes);
|
||||
router.use('/cases', casesRoutes);
|
||||
router.use('/admin', adminRoutes);
|
||||
router.use('/admin/hooks', hooksMetricsRoutes);
|
||||
router.use('/admin/sync', syncHealthRoutes);
|
||||
router.use('/admin/rules', rulesRoutes);
|
||||
router.use('/admin/projects', projectsRoutes);
|
||||
router.use('/admin', auditRoutes);
|
||||
router.use('/governance', governanceRoutes);
|
||||
router.use('/koha', kohaRoutes);
|
||||
router.use('/demo', demoRoutes);
|
||||
|
||||
// API root endpoint
|
||||
// API root endpoint - redirect browsers to documentation
|
||||
router.get('/', (req, res) => {
|
||||
// Check if request is from a browser (Accept: text/html)
|
||||
const acceptsHtml = req.accepts('html');
|
||||
const acceptsJson = req.accepts('json');
|
||||
|
||||
// If browser request, redirect to API documentation page
|
||||
if (acceptsHtml && !acceptsJson) {
|
||||
return res.redirect(302, '/api-reference.html');
|
||||
}
|
||||
|
||||
res.json({
|
||||
name: 'Tractatus AI Safety Framework API',
|
||||
version: '3.5.0',
|
||||
version: '1.0.0',
|
||||
status: 'operational',
|
||||
documentation: 'https://agenticgovernance.digital',
|
||||
endpoints: {
|
||||
auth: {
|
||||
login: 'POST /api/auth/login',
|
||||
me: 'GET /api/auth/me',
|
||||
logout: 'POST /api/auth/logout'
|
||||
},
|
||||
documents: {
|
||||
list: 'GET /api/documents',
|
||||
get: 'GET /api/documents/:identifier',
|
||||
search: 'GET /api/documents/search?q=query',
|
||||
create: 'POST /api/documents (admin)',
|
||||
update: 'PUT /api/documents/:id (admin)',
|
||||
delete: 'DELETE /api/documents/:id (admin)'
|
||||
},
|
||||
blog: {
|
||||
list: 'GET /api/blog',
|
||||
get: 'GET /api/blog/:slug',
|
||||
create: 'POST /api/blog (admin)',
|
||||
update: 'PUT /api/blog/:id (admin)',
|
||||
publish: 'POST /api/blog/:id/publish (admin)',
|
||||
delete: 'DELETE /api/blog/:id (admin)',
|
||||
admin_list: 'GET /api/blog/admin/posts?status=draft (admin)',
|
||||
admin_get: 'GET /api/blog/admin/:id (admin)',
|
||||
suggest_topics: 'POST /api/blog/suggest-topics (admin)'
|
||||
},
|
||||
newsletter: {
|
||||
subscribe: 'POST /api/newsletter/subscribe',
|
||||
verify: 'GET /api/newsletter/verify/:token',
|
||||
unsubscribe: 'POST /api/newsletter/unsubscribe',
|
||||
preferences: 'PUT /api/newsletter/preferences',
|
||||
stats: 'GET /api/newsletter/admin/stats (admin)',
|
||||
subscriptions: 'GET /api/newsletter/admin/subscriptions (admin)',
|
||||
export: 'GET /api/newsletter/admin/export (admin)',
|
||||
delete: 'DELETE /api/newsletter/admin/subscriptions/:id (admin)'
|
||||
},
|
||||
media: {
|
||||
submit: 'POST /api/media/inquiries',
|
||||
list: 'GET /api/media/inquiries (admin)',
|
||||
urgent: 'GET /api/media/inquiries/urgent (admin)',
|
||||
get: 'GET /api/media/inquiries/:id (admin)',
|
||||
assign: 'POST /api/media/inquiries/:id/assign (admin)',
|
||||
respond: 'POST /api/media/inquiries/:id/respond (admin)',
|
||||
delete: 'DELETE /api/media/inquiries/:id (admin)'
|
||||
},
|
||||
cases: {
|
||||
submit: 'POST /api/cases/submit',
|
||||
list: 'GET /api/cases/submissions (admin)',
|
||||
high_relevance: 'GET /api/cases/submissions/high-relevance (admin)',
|
||||
get: 'GET /api/cases/submissions/:id (admin)',
|
||||
approve: 'POST /api/cases/submissions/:id/approve (admin)',
|
||||
reject: 'POST /api/cases/submissions/:id/reject (admin)',
|
||||
request_info: 'POST /api/cases/submissions/:id/request-info (admin)',
|
||||
delete: 'DELETE /api/cases/submissions/:id (admin)'
|
||||
},
|
||||
admin: {
|
||||
moderation_queue: 'GET /api/admin/moderation',
|
||||
moderation_item: 'GET /api/admin/moderation/:id',
|
||||
review: 'POST /api/admin/moderation/:id/review',
|
||||
stats: 'GET /api/admin/stats',
|
||||
activity: 'GET /api/admin/activity'
|
||||
},
|
||||
governance: {
|
||||
status: 'GET /api/governance',
|
||||
classify: 'POST /api/governance/classify',
|
||||
validate: 'POST /api/governance/validate',
|
||||
enforce: 'POST /api/governance/enforce',
|
||||
pressure: 'POST /api/governance/pressure',
|
||||
verify: 'POST /api/governance/verify'
|
||||
classify: 'POST /api/governance/classify (admin)',
|
||||
validate: 'POST /api/governance/validate (admin)',
|
||||
enforce: 'POST /api/governance/enforce (admin)',
|
||||
pressure: 'POST /api/governance/pressure (admin)',
|
||||
verify: 'POST /api/governance/verify (admin)'
|
||||
},
|
||||
rules: {
|
||||
list: 'GET /api/rules',
|
||||
get: 'GET /api/rules/:id',
|
||||
create: 'POST /api/rules',
|
||||
update: 'PUT /api/rules/:id',
|
||||
delete: 'DELETE /api/rules/:id',
|
||||
search: 'GET /api/rules/search'
|
||||
},
|
||||
projects: {
|
||||
list: 'GET /api/projects',
|
||||
get: 'GET /api/projects/:id',
|
||||
create: 'POST /api/projects',
|
||||
update: 'PUT /api/projects/:id',
|
||||
delete: 'DELETE /api/projects/:id'
|
||||
},
|
||||
audit: {
|
||||
logs: 'GET /api/audit/logs',
|
||||
stats: 'GET /api/audit/stats'
|
||||
koha: {
|
||||
checkout: 'POST /api/koha/checkout',
|
||||
webhook: 'POST /api/koha/webhook',
|
||||
transparency: 'GET /api/koha/transparency',
|
||||
cancel: 'POST /api/koha/cancel',
|
||||
verify: 'GET /api/koha/verify/:sessionId',
|
||||
statistics: 'GET /api/koha/statistics (admin)'
|
||||
}
|
||||
},
|
||||
framework: {
|
||||
name: 'Tractatus Framework',
|
||||
description: 'AI governance framework enforcing architectural safety constraints at runtime',
|
||||
services: [
|
||||
'InstructionPersistenceClassifier',
|
||||
'CrossReferenceValidator',
|
||||
'BoundaryEnforcer',
|
||||
'ContextPressureMonitor',
|
||||
'MetacognitiveVerifier',
|
||||
'PluralisticDeliberationOrchestrator'
|
||||
]
|
||||
}
|
||||
framework: 'Tractatus-Based LLM Safety Architecture',
|
||||
documentation: '/api/docs',
|
||||
health: '/health'
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
199
src/server.js
199
src/server.js
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Tractatus Framework Server
|
||||
* Generic Express server template for Tractatus implementations
|
||||
* Tractatus Express Server
|
||||
* Main application entry point
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
|
|
@ -8,14 +8,21 @@ require('dotenv').config();
|
|||
const express = require('express');
|
||||
const helmet = require('helmet');
|
||||
const cors = require('cors');
|
||||
const rateLimit = require('express-rate-limit');
|
||||
const cookieParser = require('cookie-parser');
|
||||
// const csrf = require('csurf'); // Disabled - deprecated package, will implement modern solution in Phase 3
|
||||
|
||||
const config = require('./config/app.config');
|
||||
const logger = require('./utils/logger.util');
|
||||
const { connect: connectDb, close: closeDb } = require('./utils/db.util');
|
||||
const { connect: connectMongoose, close: closeMongoose } = require('./utils/mongoose.util');
|
||||
const { notFound, errorHandler } = require('./middleware/error.middleware');
|
||||
|
||||
// Security middleware (Quick Wins)
|
||||
const { securityHeadersMiddleware } = require('./middleware/security-headers.middleware');
|
||||
const { publicRateLimiter } = require('./middleware/rate-limit.middleware');
|
||||
const { publicRateLimiter, formRateLimiter, authRateLimiter } = require('./middleware/rate-limit.middleware');
|
||||
const { sanitizeErrorResponse, sanitizeResponseData } = require('./middleware/response-sanitization.middleware');
|
||||
const { setCsrfToken, csrfProtection, getCsrfToken } = require('./middleware/csrf-protection.middleware');
|
||||
|
||||
// Create Express app
|
||||
const app = express();
|
||||
|
|
@ -24,35 +31,90 @@ const app = express();
|
|||
app.set('trust proxy', 1);
|
||||
|
||||
// ============================================================
|
||||
// SECURITY MIDDLEWARE
|
||||
// SECURITY MIDDLEWARE (Quick Wins - inst_041-046)
|
||||
// ============================================================
|
||||
|
||||
// Security headers
|
||||
// Enhanced security headers (replaces helmet CSP with more specific policy)
|
||||
app.use(securityHeadersMiddleware);
|
||||
|
||||
// Helmet for additional security
|
||||
// Keep helmet for other security features (but CSP already set above)
|
||||
app.use(helmet({
|
||||
contentSecurityPolicy: false // Using custom CSP in securityHeadersMiddleware
|
||||
contentSecurityPolicy: false, // Disabled - using our custom CSP in securityHeadersMiddleware
|
||||
}));
|
||||
|
||||
// CORS
|
||||
app.use(cors(config.cors));
|
||||
|
||||
// Body parsers
|
||||
// Cookie parser (required for CSRF)
|
||||
app.use(cookieParser());
|
||||
|
||||
// Set CSRF token cookie on all requests
|
||||
app.use(setCsrfToken);
|
||||
|
||||
// Response data sanitization (removes sensitive fields)
|
||||
app.use(sanitizeResponseData);
|
||||
|
||||
// Raw body capture for Stripe webhooks (must be before JSON parser)
|
||||
app.use('/api/koha/webhook', express.raw({ type: 'application/json' }), (req, res, next) => {
|
||||
req.rawBody = req.body;
|
||||
next();
|
||||
});
|
||||
|
||||
// Body parsers (reduced limit from 10mb to 1mb for security)
|
||||
app.use(express.json({ limit: '1mb' }));
|
||||
app.use(express.urlencoded({ extended: true, limit: '1mb' }));
|
||||
|
||||
// Request logging
|
||||
app.use(logger.request);
|
||||
|
||||
// Rate limiting
|
||||
// CSRF Protection (Modern Implementation - Phase 0 Complete)
|
||||
// Uses SameSite cookies + double-submit cookie pattern
|
||||
// Protection is applied selectively to state-changing routes (POST, PUT, DELETE, PATCH)
|
||||
// Webhooks and public endpoints are excluded
|
||||
|
||||
// Enhanced rate limiting (Quick Wins)
|
||||
// Public endpoints: 100 requests per 15 minutes per IP
|
||||
app.use(publicRateLimiter);
|
||||
|
||||
// ============================================================
|
||||
// ROUTES
|
||||
// ============================================================
|
||||
// Cache control middleware for static assets
|
||||
app.use((req, res, next) => {
|
||||
const path = req.path;
|
||||
|
||||
// Health check endpoint
|
||||
// Version manifest and service worker: No cache (always fetch fresh)
|
||||
if (path === '/version.json' || path === '/service-worker.js') {
|
||||
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
||||
res.setHeader('Pragma', 'no-cache');
|
||||
res.setHeader('Expires', '0');
|
||||
}
|
||||
// HTML files: No cache (always fetch fresh - users must see updates immediately)
|
||||
else if (path.endsWith('.html') || path === '/') {
|
||||
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0');
|
||||
res.setHeader('Pragma', 'no-cache');
|
||||
}
|
||||
// CSS and JS files: Longer cache (we use version parameters)
|
||||
else if (path.endsWith('.css') || path.endsWith('.js')) {
|
||||
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable'); // 1 year
|
||||
}
|
||||
// Images and fonts: Long cache
|
||||
else if (path.match(/\.(jpg|jpeg|png|gif|svg|ico|woff|woff2|ttf|eot)$/)) {
|
||||
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable'); // 1 year
|
||||
}
|
||||
// PWA manifest: Medium cache
|
||||
else if (path === '/manifest.json') {
|
||||
res.setHeader('Cache-Control', 'public, max-age=86400'); // 1 day
|
||||
}
|
||||
// Everything else: Short cache
|
||||
else {
|
||||
res.setHeader('Cache-Control', 'public, max-age=3600'); // 1 hour
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
// Static files
|
||||
app.use(express.static('public'));
|
||||
|
||||
// Health check endpoint (minimal, no sensitive data)
|
||||
app.get('/health', (req, res) => {
|
||||
res.json({
|
||||
status: 'ok',
|
||||
|
|
@ -60,47 +122,104 @@ app.get('/health', (req, res) => {
|
|||
});
|
||||
});
|
||||
|
||||
// CSRF token endpoint (modern implementation)
|
||||
// Returns the CSRF token from cookie for client-side usage
|
||||
app.get('/api/csrf-token', getCsrfToken);
|
||||
|
||||
// API routes
|
||||
const apiRoutes = require('./routes/index');
|
||||
app.use('/api', apiRoutes);
|
||||
|
||||
// Homepage
|
||||
// Homepage (temporary)
|
||||
app.get('/', (req, res) => {
|
||||
res.json({
|
||||
name: 'Tractatus AI Safety Framework',
|
||||
version: '3.5.0',
|
||||
status: 'operational',
|
||||
documentation: 'https://agenticgovernance.digital',
|
||||
endpoints: {
|
||||
health: 'GET /health',
|
||||
api: 'GET /api'
|
||||
}
|
||||
});
|
||||
res.send(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Tractatus AI Safety Framework</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 50px auto;
|
||||
padding: 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
h1 { color: #2563eb; }
|
||||
.status { color: #059669; font-weight: bold; }
|
||||
code { background: #f3f4f6; padding: 2px 6px; border-radius: 3px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Tractatus AI Safety Framework</h1>
|
||||
<p class="status">✓ Server Running</p>
|
||||
<p>Development environment for the Tractatus-Based LLM Safety Framework website.</p>
|
||||
|
||||
<h2>Status</h2>
|
||||
<ul>
|
||||
<li>✓ MongoDB connected (port 27017)</li>
|
||||
<li>✓ Express server running (port ${config.port})</li>
|
||||
<li>✓ Database initialized (10 collections)</li>
|
||||
<li>✓ Core models implemented</li>
|
||||
<li>✓ API routes complete (auth, documents, blog, admin)</li>
|
||||
<li>✓ Governance services active (6 core services)</li>
|
||||
<li>⏳ Frontend (pending)</li>
|
||||
</ul>
|
||||
|
||||
<h2>Available Endpoints</h2>
|
||||
<ul>
|
||||
<li><code>GET /health</code> - Health check</li>
|
||||
<li><code>GET /api</code> - API documentation</li>
|
||||
<li><code>POST /api/auth/login</code> - Admin login</li>
|
||||
<li><code>GET /api/documents</code> - List framework documents</li>
|
||||
<li><code>GET /api/blog</code> - List published blog posts</li>
|
||||
<li><code>GET /api/admin/stats</code> - System statistics (auth required)</li>
|
||||
</ul>
|
||||
|
||||
<p><em>Phase 1 Development - Not for public use</em></p>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
// ERROR HANDLING
|
||||
// ERROR HANDLING (Quick Wins)
|
||||
// ============================================================
|
||||
|
||||
// 404 handler
|
||||
app.use(notFound);
|
||||
|
||||
// Error handler
|
||||
// Enhanced error handler (sanitizes responses, hides stack traces)
|
||||
app.use(sanitizeErrorResponse);
|
||||
|
||||
// Fallback to original error handler if needed
|
||||
app.use(errorHandler);
|
||||
|
||||
// ============================================================
|
||||
// SERVER STARTUP
|
||||
// ============================================================
|
||||
|
||||
// Server startup
|
||||
async function start() {
|
||||
try {
|
||||
// Connect to MongoDB (native driver)
|
||||
await connectDb();
|
||||
logger.info('✅ MongoDB (native) connected');
|
||||
|
||||
// Connect Mongoose (for ODM models)
|
||||
await connectMongoose();
|
||||
logger.info('✅ Mongoose connected');
|
||||
|
||||
// Sync instructions from file to database
|
||||
try {
|
||||
const { syncInstructions } = require('../scripts/sync-instructions-to-db.js');
|
||||
const syncResult = await syncInstructions({ silent: true });
|
||||
if (syncResult && syncResult.success) {
|
||||
logger.info(`✅ Instructions synced to database: ${syncResult.finalCount} active rules`);
|
||||
if (syncResult.added > 0 || syncResult.deactivated > 0) {
|
||||
logger.info(` Added: ${syncResult.added}, Updated: ${syncResult.updated}, Deactivated: ${syncResult.deactivated}`);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.warn(`⚠️ Instruction sync failed: ${err.message}`);
|
||||
logger.warn(' Admin UI may show outdated rule counts');
|
||||
}
|
||||
|
||||
// Initialize governance services
|
||||
const BoundaryEnforcer = require('./services/BoundaryEnforcer.service');
|
||||
|
|
@ -113,12 +232,14 @@ async function start() {
|
|||
|
||||
// Start server
|
||||
const server = app.listen(config.port, () => {
|
||||
logger.info(`🚀 Tractatus Framework server started`);
|
||||
logger.info(` Environment: ${config.env}`);
|
||||
logger.info(` Port: ${config.port}`);
|
||||
logger.info(` MongoDB: ${config.mongodb.db}`);
|
||||
logger.info(` API: http://localhost:${config.port}/api`);
|
||||
console.log(`\n🌐 Server running at http://localhost:${config.port}\n`);
|
||||
logger.info(`🚀 Tractatus server started`);
|
||||
logger.info(`✅ Environment: ${config.env}`);
|
||||
logger.info(`✅ Port: ${config.port}`);
|
||||
logger.info(`✅ MongoDB: ${config.mongodb.db}`);
|
||||
logger.info(`🔒 Security: Quick Wins active (headers, rate limiting, input validation)`);
|
||||
logger.info(`📊 Security logs: ${process.env.HOME}/var/log/tractatus/security-audit.log`);
|
||||
logger.info(`✨ Ready for development`);
|
||||
console.log(`\n🌐 http://localhost:${config.port}\n`);
|
||||
});
|
||||
|
||||
// Graceful shutdown
|
||||
|
|
@ -139,7 +260,7 @@ async function shutdown(server) {
|
|||
logger.info('HTTP server closed');
|
||||
|
||||
await closeDb();
|
||||
logger.info('MongoDB (native) connection closed');
|
||||
logger.info('Native MongoDB connection closed');
|
||||
|
||||
await closeMongoose();
|
||||
logger.info('Mongoose connection closed');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue