@versatil/sdlc-framework
Version:
🚀 AI-Native SDLC framework with 11-MCP ecosystem, RAG memory, OPERA orchestration, and 6 specialized agents achieving ZERO CONTEXT LOSS. Features complete CI/CD pipeline with 7 GitHub workflows (MCP testing, security scanning, performance benchmarking),
613 lines (525 loc) • 16.6 kB
JavaScript
/**
* VERSATIL Framework - Isolation Stress Test
*
* Tests that framework installation in user projects maintains perfect isolation:
* - No framework files in user project (except .versatil-project.json)
* - All framework data in ~/.versatil/
* - No accidental commits of framework data
* - Multi-project support works correctly
* - Framework updates don't touch user code
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const os = require('os');
// Colors for output
const colors = {
reset: '\x1b[0m',
green: '\x1b[32m',
red: '\x1b[31m',
yellow: '\x1b[33m',
blue: '\x1b[36m',
bold: '\x1b[1m'
};
// Test results
const results = {
passed: 0,
failed: 0,
warnings: 0,
tests: []
};
// Framework home directory
const FRAMEWORK_HOME = path.join(os.homedir(), '.versatil');
/**
* Log test result
*/
function logTest(name, passed, message = '') {
const status = passed ? '✅' : '❌';
const color = passed ? colors.green : colors.red;
console.log(`${color}${status} ${name}${colors.reset}`);
if (message) {
console.log(` ${message}`);
}
results.tests.push({ name, passed, message });
if (passed) {
results.passed++;
} else {
results.failed++;
}
}
/**
* Log warning
*/
function logWarning(name, message) {
console.log(`${colors.yellow}⚠️ ${name}${colors.reset}`);
if (message) {
console.log(` ${message}`);
}
results.warnings++;
}
/**
* Check if path exists
*/
function pathExists(p) {
try {
return fs.existsSync(p);
} catch {
return false;
}
}
/**
* Create temporary test project
*/
function createTestProject(name) {
const tempDir = path.join(os.tmpdir(), `versatil-test-${name}-${Date.now()}`);
fs.mkdirSync(tempDir, { recursive: true });
// Create a simple Node.js project
const packageJson = {
name: `test-project-${name}`,
version: '1.0.0',
description: 'Test project for VERSATIL isolation',
main: 'index.js'
};
fs.writeFileSync(
path.join(tempDir, 'package.json'),
JSON.stringify(packageJson, null, 2)
);
// Create a simple source file
fs.mkdirSync(path.join(tempDir, 'src'));
fs.writeFileSync(
path.join(tempDir, 'src', 'index.js'),
'// User project code\nconsole.log("Hello from user project");'
);
// Initialize git
try {
execSync('git init', { cwd: tempDir, stdio: 'ignore' });
execSync('git config user.email "test@example.com"', { cwd: tempDir, stdio: 'ignore' });
execSync('git config user.name "Test User"', { cwd: tempDir, stdio: 'ignore' });
execSync('git add .', { cwd: tempDir, stdio: 'ignore' });
execSync('git commit -m "Initial commit"', { cwd: tempDir, stdio: 'ignore' });
} catch (error) {
console.warn('Could not initialize git:', error.message);
}
return tempDir;
}
/**
* Simulate framework installation
*/
function simulateFrameworkInstall(projectPath) {
// Create .versatil-project.json (the ONLY file allowed in user project)
const projectConfig = {
name: path.basename(projectPath),
frameworkVersion: '3.0.0',
installedAt: new Date().toISOString(),
frameworkHome: FRAMEWORK_HOME
};
fs.writeFileSync(
path.join(projectPath, '.versatil-project.json'),
JSON.stringify(projectConfig, null, 2)
);
}
/**
* Test 1: Framework home exists
*/
function testFrameworkHomeExists() {
const exists = pathExists(FRAMEWORK_HOME);
logTest(
'Framework home directory exists',
exists,
exists ? `Found at: ${FRAMEWORK_HOME}` : 'Framework home not initialized'
);
}
/**
* Test 2: No framework pollution in user project
*/
function testNoFrameworkPollution(projectPath) {
const forbiddenPaths = [
'.versatil',
'versatil',
'supabase',
'.versatil-memory',
'.versatil-logs',
'.versatil-self',
'node_modules/versatil-sdlc-framework/.versatil'
];
let polluted = false;
const foundPollution = [];
for (const forbidden of forbiddenPaths) {
const fullPath = path.join(projectPath, forbidden);
if (pathExists(fullPath)) {
polluted = true;
foundPollution.push(forbidden);
}
}
logTest(
'No framework pollution in user project',
!polluted,
polluted
? `Found forbidden paths: ${foundPollution.join(', ')}`
: 'Project is clean'
);
}
/**
* Test 3: Only allowed file exists (.versatil-project.json)
*/
function testOnlyAllowedFile(projectPath) {
const allowedFile = '.versatil-project.json';
const allowedPath = path.join(projectPath, allowedFile);
const exists = pathExists(allowedPath);
logTest(
'Only allowed file (.versatil-project.json) exists',
exists,
exists ? 'Configuration file present' : 'Configuration file missing'
);
if (exists) {
try {
const content = JSON.parse(fs.readFileSync(allowedPath, 'utf8'));
const hasRequiredFields = content.frameworkVersion && content.frameworkHome;
logTest(
'Configuration file has required fields',
hasRequiredFields,
hasRequiredFields
? `Version: ${content.frameworkVersion}, Home: ${content.frameworkHome}`
: 'Missing required fields'
);
} catch (error) {
logTest('Configuration file is valid JSON', false, error.message);
}
}
}
/**
* Test 4: Framework data in correct location
*/
function testFrameworkDataLocation() {
const expectedPaths = [
'logs',
'rag-memory',
'config',
'supabase'
];
let allPresent = true;
const missing = [];
for (const dir of expectedPaths) {
const fullPath = path.join(FRAMEWORK_HOME, dir);
if (!pathExists(fullPath)) {
allPresent = false;
missing.push(dir);
}
}
if (missing.length > 0) {
logWarning(
'Some framework directories missing',
`Missing: ${missing.join(', ')} (may not be initialized yet)`
);
} else {
logTest(
'Framework data in correct location (~/.versatil/)',
true,
`All expected directories present: ${expectedPaths.join(', ')}`
);
}
}
/**
* Test 5: Git safety (no framework files would be committed)
*/
function testGitSafety(projectPath) {
try {
// Check git status
const status = execSync('git status --porcelain', {
cwd: projectPath,
encoding: 'utf8'
});
// Parse status for framework-related files
const lines = status.split('\n').filter(l => l.trim());
const frameworkFiles = lines.filter(line => {
const lowerLine = line.toLowerCase();
return lowerLine.includes('.versatil/') ||
lowerLine.includes('supabase/') ||
lowerLine.includes('versatil-logs');
});
const isSafe = frameworkFiles.length === 0;
logTest(
'Git safety: No framework files in staging',
isSafe,
isSafe
? 'No framework files would be accidentally committed'
: `Found ${frameworkFiles.length} framework files: ${frameworkFiles.join(', ')}`
);
} catch (error) {
logWarning('Git safety check', 'Project not a git repository or git not available');
}
}
/**
* Test 6: Multi-project isolation
*/
function testMultiProjectIsolation() {
const project1 = createTestProject('proj1');
const project2 = createTestProject('proj2');
simulateFrameworkInstall(project1);
simulateFrameworkInstall(project2);
const config1 = JSON.parse(fs.readFileSync(path.join(project1, '.versatil-project.json'), 'utf8'));
const config2 = JSON.parse(fs.readFileSync(path.join(project2, '.versatil-project.json'), 'utf8'));
// Both should point to same framework home
const sameHome = config1.frameworkHome === config2.frameworkHome;
logTest(
'Multi-project isolation: Both projects share framework home',
sameHome,
sameHome
? `Both use: ${config1.frameworkHome}`
: `Project 1: ${config1.frameworkHome}, Project 2: ${config2.frameworkHome}`
);
// Cleanup
fs.rmSync(project1, { recursive: true, force: true });
fs.rmSync(project2, { recursive: true, force: true });
}
/**
* Test 7: .gitignore recommendation
*/
function testGitignoreRecommendation(projectPath) {
const gitignorePath = path.join(projectPath, '.gitignore');
if (pathExists(gitignorePath)) {
const content = fs.readFileSync(gitignorePath, 'utf8');
const hasIgnore = content.includes('.versatil-project.json');
if (hasIgnore) {
logTest(
'.gitignore includes .versatil-project.json',
true,
'Configuration file is ignored (recommended)'
);
} else {
logWarning(
'.gitignore recommendation',
'Consider adding .versatil-project.json to .gitignore'
);
}
} else {
logWarning(
'.gitignore recommendation',
'No .gitignore found. Recommend creating one with .versatil-project.json'
);
}
}
/**
* Test 8: File system permissions
*/
function testFileSystemPermissions() {
try {
const testFile = path.join(FRAMEWORK_HOME, '.test-write');
fs.writeFileSync(testFile, 'test');
fs.unlinkSync(testFile);
logTest(
'Framework home is writable',
true,
`Can write to ${FRAMEWORK_HOME}`
);
} catch (error) {
logTest(
'Framework home is writable',
false,
`Cannot write to ${FRAMEWORK_HOME}: ${error.message}`
);
}
}
/**
* Test 9: Symlink detection (potential isolation breach)
*/
function testNoSymlinks(projectPath) {
try {
const entries = fs.readdirSync(projectPath, { withFileTypes: true });
const symlinks = entries.filter(e => e.isSymbolicLink());
const frameworkSymlinks = symlinks.filter(s => {
const linkPath = fs.readlinkSync(path.join(projectPath, s.name));
return linkPath.includes('.versatil') || linkPath.includes('framework');
});
const noFrameworkSymlinks = frameworkSymlinks.length === 0;
logTest(
'No framework symlinks in project',
noFrameworkSymlinks,
noFrameworkSymlinks
? 'No symlinks pointing to framework directories'
: `Found ${frameworkSymlinks.length} framework symlinks: ${frameworkSymlinks.map(s => s.name).join(', ')}`
);
} catch (error) {
logWarning('Symlink detection', `Could not check symlinks: ${error.message}`);
}
}
/**
* Test 10: Environment variable isolation
*/
function testEnvironmentIsolation() {
const frameworkEnvVars = [
'VERSATIL_HOME',
'VERSATIL_PROJECT_ROOT',
'VERSATIL_FRAMEWORK_PATH'
];
const setVars = frameworkEnvVars.filter(v => process.env[v]);
if (setVars.length > 0) {
logTest(
'Environment variables are set',
true,
`Found: ${setVars.join(', ')}`
);
// Check they point to correct locations
if (process.env.VERSATIL_HOME) {
const pointsToHome = process.env.VERSATIL_HOME === FRAMEWORK_HOME;
logTest(
'VERSATIL_HOME points to framework home',
pointsToHome,
pointsToHome
? `Correctly set to: ${FRAMEWORK_HOME}`
: `Expected: ${FRAMEWORK_HOME}, Got: ${process.env.VERSATIL_HOME}`
);
}
} else {
logWarning(
'Environment variables',
'No framework environment variables set (may be normal if not running framework)'
);
}
}
/**
* Test 11: Package.json dependency check
*/
function testPackageJsonClean(projectPath) {
const packageJsonPath = path.join(projectPath, 'package.json');
if (pathExists(packageJsonPath)) {
const content = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const deps = { ...content.dependencies, ...content.devDependencies };
// Check if framework is a dependency (it shouldn't be for isolation)
const hasFrameworkDep = Object.keys(deps).some(dep =>
dep.includes('versatil') || dep.includes('opera')
);
if (hasFrameworkDep) {
logWarning(
'Framework as dependency',
'Framework found in package.json. For isolation, consider global install.'
);
} else {
logTest(
'No framework dependencies in package.json',
true,
'Project dependencies are clean'
);
}
}
}
/**
* Test 12: Stress test with multiple simultaneous projects
*/
function testConcurrentProjects() {
console.log(`\n${colors.blue}${colors.bold}Running concurrent projects stress test...${colors.reset}\n`);
const numProjects = 10;
const projects = [];
// Create multiple projects simultaneously
for (let i = 0; i < numProjects; i++) {
const proj = createTestProject(`concurrent-${i}`);
simulateFrameworkInstall(proj);
projects.push(proj);
}
// Verify isolation for each
let allIsolated = true;
for (const proj of projects) {
const config = JSON.parse(fs.readFileSync(path.join(proj, '.versatil-project.json'), 'utf8'));
// Check only allowed file exists
const entries = fs.readdirSync(proj);
const frameworkFiles = entries.filter(e =>
e.includes('.versatil') && e !== '.versatil-project.json'
);
if (frameworkFiles.length > 0) {
allIsolated = false;
break;
}
}
logTest(
`Concurrent projects stress test (${numProjects} projects)`,
allIsolated,
allIsolated
? `All ${numProjects} projects maintain isolation`
: 'Some projects have isolation breaches'
);
// Cleanup
for (const proj of projects) {
fs.rmSync(proj, { recursive: true, force: true });
}
}
/**
* Generate report
*/
function generateReport() {
console.log(`\n${'='.repeat(70)}`);
console.log(`${colors.bold}VERSATIL Framework Isolation Stress Test Report${colors.reset}`);
console.log(`${'='.repeat(70)}\n`);
// Summary
console.log(`${colors.bold}Summary:${colors.reset}`);
console.log(` ${colors.green}✅ Passed: ${results.passed}${colors.reset}`);
console.log(` ${colors.red}❌ Failed: ${results.failed}${colors.reset}`);
console.log(` ${colors.yellow}⚠️ Warnings: ${results.warnings}${colors.reset}`);
const totalTests = results.passed + results.failed;
const passRate = totalTests > 0 ? (results.passed / totalTests * 100).toFixed(1) : 0;
console.log(`\n Pass Rate: ${passRate}%`);
// Isolation score
let score = 100;
score -= results.failed * 10;
score -= results.warnings * 2;
score = Math.max(0, score);
console.log(`\n${colors.bold}Isolation Score: ${score}/100${colors.reset}`);
if (score >= 90) {
console.log(`${colors.green}${colors.bold}✅ EXCELLENT - Framework isolation is robust${colors.reset}`);
} else if (score >= 70) {
console.log(`${colors.yellow}${colors.bold}⚠️ GOOD - Minor isolation concerns${colors.reset}`);
} else if (score >= 50) {
console.log(`${colors.yellow}${colors.bold}⚠️ FAIR - Some isolation issues detected${colors.reset}`);
} else {
console.log(`${colors.red}${colors.bold}❌ POOR - Significant isolation problems${colors.reset}`);
}
// Recommendations
if (results.failed > 0 || results.warnings > 0) {
console.log(`\n${colors.bold}Recommendations:${colors.reset}`);
if (results.failed > 0) {
console.log(' • Review failed tests and fix isolation breaches');
}
if (results.warnings > 0) {
console.log(' • Address warnings to improve isolation');
console.log(' • Add .versatil-project.json to .gitignore');
console.log(' • Consider global framework installation');
}
}
console.log(`\n${'='.repeat(70)}\n`);
return score >= 70;
}
/**
* Main test suite
*/
function runIsolationStressTest() {
console.log(`\n${colors.blue}${colors.bold}VERSATIL Framework - Isolation Stress Test${colors.reset}`);
console.log(`Testing framework installation isolation in user projects\n`);
console.log(`Framework Home: ${FRAMEWORK_HOME}\n`);
// Create test project
const testProject = createTestProject('main');
console.log(`${colors.blue}Test Project: ${testProject}${colors.reset}\n`);
// Simulate installation
simulateFrameworkInstall(testProject);
// Run tests
console.log(`${colors.bold}Running Tests:${colors.reset}\n`);
testFrameworkHomeExists();
testNoFrameworkPollution(testProject);
testOnlyAllowedFile(testProject);
testFrameworkDataLocation();
testGitSafety(testProject);
testMultiProjectIsolation();
testGitignoreRecommendation(testProject);
testFileSystemPermissions();
testNoSymlinks(testProject);
testEnvironmentIsolation();
testPackageJsonClean(testProject);
testConcurrentProjects();
// Cleanup
fs.rmSync(testProject, { recursive: true, force: true });
// Generate report
const passed = generateReport();
// Exit code
process.exit(passed ? 0 : 1);
}
// Run tests
runIsolationStressTest();