Coverage Improvements (Task 3 - Week 1): - governance.routes.js: 31.81% → 100% (+68.19%) - markdown.util.js: 17.39% → 89.13% (+71.74%) New Test Files: - tests/integration/api.governance.test.js (33 tests) - Authentication/authorization for all 6 governance endpoints - Request validation (missing fields, invalid input) - Admin-only access control enforcement - Framework component testing (classify, validate, enforce, pressure, verify) - tests/unit/markdown.util.test.js (60 tests) - markdownToHtml: conversion, syntax highlighting, XSS sanitization (23 tests) - extractTOC: heading extraction and slug generation (11 tests) - extractFrontMatter: YAML front matter parsing (10 tests) - generateSlug: URL-safe slug generation (16 tests) This completes Week 1, Task 3: Increase test coverage on critical services. Previous tasks in same session: - Task 1: Fixed 29 production test failures ✓ - Task 2: Completed Koha security implementation ✓ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
514 lines
16 KiB
JavaScript
514 lines
16 KiB
JavaScript
/**
|
|
* Integration Tests - Governance API
|
|
* Tests Tractatus framework testing endpoints
|
|
*/
|
|
|
|
const request = require('supertest');
|
|
const { MongoClient } = require('mongodb');
|
|
const bcrypt = require('bcrypt');
|
|
const app = require('../../src/server');
|
|
const config = require('../../src/config/app.config');
|
|
|
|
describe('Governance API Integration Tests', () => {
|
|
let connection;
|
|
let db;
|
|
let adminToken;
|
|
let regularUserToken;
|
|
|
|
const adminUser = {
|
|
email: 'admin@governance.test.local',
|
|
password: 'AdminGov123!',
|
|
role: 'admin'
|
|
};
|
|
|
|
const regularUser = {
|
|
email: 'user@governance.test.local',
|
|
password: 'UserGov123!',
|
|
role: 'user'
|
|
};
|
|
|
|
// Setup test users
|
|
beforeAll(async () => {
|
|
connection = await MongoClient.connect(config.mongodb.uri);
|
|
db = connection.db(config.mongodb.db);
|
|
|
|
// Clean up existing test users
|
|
await db.collection('users').deleteMany({
|
|
email: { $in: [adminUser.email, regularUser.email] }
|
|
});
|
|
|
|
// Create admin user
|
|
const adminHash = await bcrypt.hash(adminUser.password, 10);
|
|
await db.collection('users').insertOne({
|
|
email: adminUser.email,
|
|
password: adminHash,
|
|
name: 'Test Admin',
|
|
role: adminUser.role,
|
|
created_at: new Date(),
|
|
active: true
|
|
});
|
|
|
|
// Create regular user
|
|
const userHash = await bcrypt.hash(regularUser.password, 10);
|
|
await db.collection('users').insertOne({
|
|
email: regularUser.email,
|
|
password: userHash,
|
|
name: 'Test User',
|
|
role: regularUser.role,
|
|
created_at: new Date(),
|
|
active: true
|
|
});
|
|
|
|
// Get tokens
|
|
const adminLogin = await request(app)
|
|
.post('/api/auth/login')
|
|
.send({
|
|
email: adminUser.email,
|
|
password: adminUser.password
|
|
});
|
|
adminToken = adminLogin.body.token;
|
|
|
|
const userLogin = await request(app)
|
|
.post('/api/auth/login')
|
|
.send({
|
|
email: regularUser.email,
|
|
password: regularUser.password
|
|
});
|
|
regularUserToken = userLogin.body.token;
|
|
});
|
|
|
|
// Clean up
|
|
afterAll(async () => {
|
|
await db.collection('users').deleteMany({
|
|
email: { $in: [adminUser.email, regularUser.email] }
|
|
});
|
|
await connection.close();
|
|
});
|
|
|
|
describe('GET /api/governance', () => {
|
|
test('should require authentication', async () => {
|
|
const response = await request(app)
|
|
.get('/api/governance')
|
|
.expect(401);
|
|
|
|
expect(response.body).toHaveProperty('error');
|
|
});
|
|
|
|
test('should require admin role', async () => {
|
|
const response = await request(app)
|
|
.get('/api/governance')
|
|
.set('Authorization', `Bearer ${regularUserToken}`)
|
|
.expect(403);
|
|
|
|
expect(response.body).toHaveProperty('error');
|
|
});
|
|
|
|
test('should redirect HTML requests to API documentation', async () => {
|
|
const response = await request(app)
|
|
.get('/api/governance')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.set('Accept', 'text/html')
|
|
.expect(302);
|
|
|
|
expect(response.headers.location).toContain('api-reference.html#governance');
|
|
});
|
|
|
|
test('should return JSON for JSON requests with admin auth', async () => {
|
|
const response = await request(app)
|
|
.get('/api/governance')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.set('Accept', 'application/json')
|
|
.expect(200);
|
|
|
|
// Response is the framework object directly (not wrapped in success)
|
|
expect(response.body).toHaveProperty('name', 'Tractatus Governance Framework');
|
|
expect(response.body).toHaveProperty('operational', true);
|
|
expect(response.body).toHaveProperty('services');
|
|
});
|
|
});
|
|
|
|
describe('GET /api/governance/status', () => {
|
|
test('should require authentication', async () => {
|
|
const response = await request(app)
|
|
.get('/api/governance/status')
|
|
.expect(401);
|
|
|
|
expect(response.body).toHaveProperty('error');
|
|
});
|
|
|
|
test('should require admin role', async () => {
|
|
const response = await request(app)
|
|
.get('/api/governance/status')
|
|
.set('Authorization', `Bearer ${regularUserToken}`)
|
|
.expect(403);
|
|
|
|
expect(response.body).toHaveProperty('error');
|
|
});
|
|
|
|
test('should return detailed framework status with admin auth', async () => {
|
|
const response = await request(app)
|
|
.get('/api/governance/status')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.expect(200);
|
|
|
|
expect(response.body).toHaveProperty('success', true);
|
|
expect(response.body).toHaveProperty('uptime');
|
|
expect(response.body).toHaveProperty('environment');
|
|
expect(typeof response.body.uptime).toBe('number');
|
|
});
|
|
});
|
|
|
|
describe('POST /api/governance/classify', () => {
|
|
test('should require authentication', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/classify')
|
|
.send({ text: 'Test instruction' })
|
|
.expect(401);
|
|
|
|
expect(response.body).toHaveProperty('error');
|
|
});
|
|
|
|
test('should require admin role', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/classify')
|
|
.set('Authorization', `Bearer ${regularUserToken}`)
|
|
.send({ text: 'Test instruction' })
|
|
.expect(403);
|
|
|
|
expect(response.body).toHaveProperty('error');
|
|
});
|
|
|
|
test('should reject request without text field', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/classify')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({})
|
|
.expect(400);
|
|
|
|
expect(response.body).toHaveProperty('error', 'Bad Request');
|
|
expect(response.body.message).toContain('text field is required');
|
|
});
|
|
|
|
test('should classify instruction with admin auth', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/classify')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({
|
|
text: 'Always use TypeScript for new projects',
|
|
context: { source: 'test' }
|
|
})
|
|
.expect(200);
|
|
|
|
expect(response.body).toHaveProperty('success', true);
|
|
expect(response.body).toHaveProperty('classification');
|
|
expect(response.body.classification).toHaveProperty('quadrant');
|
|
expect(response.body.classification).toHaveProperty('persistence');
|
|
});
|
|
|
|
test('should classify without context parameter', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/classify')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({
|
|
text: 'Run tests before committing'
|
|
})
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.classification).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('POST /api/governance/validate', () => {
|
|
test('should require authentication', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/validate')
|
|
.send({ action: { type: 'test' } })
|
|
.expect(401);
|
|
});
|
|
|
|
test('should require admin role', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/validate')
|
|
.set('Authorization', `Bearer ${regularUserToken}`)
|
|
.send({ action: { type: 'test' } })
|
|
.expect(403);
|
|
});
|
|
|
|
test('should reject request without action field', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/validate')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({})
|
|
.expect(400);
|
|
|
|
expect(response.body).toHaveProperty('error', 'Bad Request');
|
|
expect(response.body.message).toContain('action object is required');
|
|
});
|
|
|
|
test('should validate action with admin auth', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/validate')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({
|
|
action: {
|
|
type: 'file-edit',
|
|
description: 'Update configuration file',
|
|
filePath: 'config.json'
|
|
},
|
|
context: {
|
|
messages: []
|
|
}
|
|
})
|
|
.expect(200);
|
|
|
|
expect(response.body).toHaveProperty('success', true);
|
|
expect(response.body).toHaveProperty('validation');
|
|
expect(response.body.validation).toHaveProperty('status');
|
|
expect(response.body.validation).toHaveProperty('action');
|
|
});
|
|
|
|
test('should validate without context parameter', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/validate')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({
|
|
action: {
|
|
type: 'database',
|
|
description: 'Update schema'
|
|
}
|
|
})
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('POST /api/governance/enforce', () => {
|
|
test('should require authentication', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/enforce')
|
|
.send({ action: { type: 'test' } })
|
|
.expect(401);
|
|
});
|
|
|
|
test('should require admin role', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/enforce')
|
|
.set('Authorization', `Bearer ${regularUserToken}`)
|
|
.send({ action: { type: 'test' } })
|
|
.expect(403);
|
|
});
|
|
|
|
test('should reject request without action field', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/enforce')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({})
|
|
.expect(400);
|
|
|
|
expect(response.body).toHaveProperty('error', 'Bad Request');
|
|
expect(response.body.message).toContain('action object is required');
|
|
});
|
|
|
|
test('should enforce boundaries with admin auth', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/enforce')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({
|
|
action: {
|
|
type: 'values',
|
|
description: 'Define project values',
|
|
decision: 'What are our core values?'
|
|
},
|
|
context: {}
|
|
})
|
|
.expect(200);
|
|
|
|
expect(response.body).toHaveProperty('success', true);
|
|
expect(response.body).toHaveProperty('enforcement');
|
|
expect(response.body.enforcement).toHaveProperty('allowed');
|
|
expect(response.body.enforcement).toHaveProperty('domain');
|
|
});
|
|
|
|
test('should enforce without context parameter', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/enforce')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({
|
|
action: {
|
|
type: 'architecture',
|
|
description: 'Change system architecture'
|
|
}
|
|
})
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('POST /api/governance/pressure', () => {
|
|
test('should require authentication', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/pressure')
|
|
.send({})
|
|
.expect(401);
|
|
});
|
|
|
|
test('should require admin role', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/pressure')
|
|
.set('Authorization', `Bearer ${regularUserToken}`)
|
|
.send({})
|
|
.expect(403);
|
|
});
|
|
|
|
test('should analyze pressure with admin auth', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/pressure')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({
|
|
context: {
|
|
tokenUsage: 100000,
|
|
tokenBudget: 200000,
|
|
messageCount: 50
|
|
}
|
|
})
|
|
.expect(200);
|
|
|
|
expect(response.body).toHaveProperty('success', true);
|
|
expect(response.body).toHaveProperty('pressure');
|
|
expect(response.body.pressure).toHaveProperty('pressureLevel');
|
|
expect(response.body.pressure).toHaveProperty('overall_score');
|
|
});
|
|
|
|
test('should use default context when not provided', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/pressure')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({})
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.pressure).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('POST /api/governance/verify', () => {
|
|
test('should require authentication', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/verify')
|
|
.send({ action: { type: 'test' } })
|
|
.expect(401);
|
|
});
|
|
|
|
test('should require admin role', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/verify')
|
|
.set('Authorization', `Bearer ${regularUserToken}`)
|
|
.send({ action: { type: 'test' } })
|
|
.expect(403);
|
|
});
|
|
|
|
test('should reject request without action field', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/verify')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({})
|
|
.expect(400);
|
|
|
|
expect(response.body).toHaveProperty('error', 'Bad Request');
|
|
expect(response.body.message).toContain('action object is required');
|
|
});
|
|
|
|
test('should verify action with admin auth', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/verify')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({
|
|
action: {
|
|
type: 'complex',
|
|
description: 'Refactor authentication system',
|
|
parameters: {
|
|
files: ['auth.js', 'middleware.js'],
|
|
changes: 'major'
|
|
}
|
|
},
|
|
reasoning: {
|
|
userGoal: 'Improve security',
|
|
approach: 'Use JWT tokens'
|
|
},
|
|
context: {}
|
|
})
|
|
.expect(200);
|
|
|
|
expect(response.body).toHaveProperty('success', true);
|
|
expect(response.body).toHaveProperty('verification');
|
|
expect(response.body.verification).toHaveProperty('checks');
|
|
expect(response.body.verification.checks).toHaveProperty('alignment');
|
|
});
|
|
|
|
test('should verify without reasoning parameter', async () => {
|
|
const response = await request(app)
|
|
.post('/api/governance/verify')
|
|
.set('Authorization', `Bearer ${adminToken}`)
|
|
.send({
|
|
action: {
|
|
type: 'simple',
|
|
description: 'Update README'
|
|
}
|
|
})
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('Admin-Only Access Control', () => {
|
|
test('should enforce admin-only access across all governance routes', async () => {
|
|
const governanceRoutes = [
|
|
{ method: 'get', path: '/api/governance/status' },
|
|
{ method: 'post', path: '/api/governance/classify', body: { text: 'test' } },
|
|
{ method: 'post', path: '/api/governance/validate', body: { action: { type: 'test' } } },
|
|
{ method: 'post', path: '/api/governance/enforce', body: { action: { type: 'test' } } },
|
|
{ method: 'post', path: '/api/governance/pressure', body: {} },
|
|
{ method: 'post', path: '/api/governance/verify', body: { action: { type: 'test' } } }
|
|
];
|
|
|
|
for (const route of governanceRoutes) {
|
|
const req = request(app)[route.method](route.path)
|
|
.set('Authorization', `Bearer ${regularUserToken}`);
|
|
|
|
if (route.body) {
|
|
req.send(route.body);
|
|
}
|
|
|
|
const response = await req;
|
|
expect(response.status).toBe(403);
|
|
}
|
|
});
|
|
|
|
test('should allow admin access to all governance routes', async () => {
|
|
const governanceRoutes = [
|
|
{ method: 'get', path: '/api/governance/status' },
|
|
{ method: 'post', path: '/api/governance/classify', body: { text: 'test' } },
|
|
{ method: 'post', path: '/api/governance/validate', body: { action: { type: 'test' } } },
|
|
{ method: 'post', path: '/api/governance/enforce', body: { action: { type: 'test' } } },
|
|
{ method: 'post', path: '/api/governance/pressure', body: {} },
|
|
{ method: 'post', path: '/api/governance/verify', body: { action: { type: 'test' } } }
|
|
];
|
|
|
|
for (const route of governanceRoutes) {
|
|
const req = request(app)[route.method](route.path)
|
|
.set('Authorization', `Bearer ${adminToken}`);
|
|
|
|
if (route.body) {
|
|
req.send(route.body);
|
|
}
|
|
|
|
const response = await req;
|
|
expect(response.status).toBe(200);
|
|
}
|
|
});
|
|
});
|
|
});
|