feat: Initialize Zastava Webhook service with TLS and Authority authentication
- Added Program.cs to set up the web application with Serilog for logging, health check endpoints, and a placeholder admission endpoint. - Configured Kestrel server to use TLS 1.3 and handle client certificates appropriately. - Created StellaOps.Zastava.Webhook.csproj with necessary dependencies including Serilog and Polly. - Documented tasks in TASKS.md for the Zastava Webhook project, outlining current work and exit criteria for each task.
This commit is contained in:
		
							
								
								
									
										249
									
								
								bench/Scanner.Analyzers/run-bench.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								bench/Scanner.Analyzers/run-bench.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,249 @@ | ||||
| #!/usr/bin/env node | ||||
| 'use strict'; | ||||
|  | ||||
| const fs = require('fs'); | ||||
| const path = require('path'); | ||||
| const { performance } = require('perf_hooks'); | ||||
|  | ||||
| function globToRegExp(pattern) { | ||||
|   let working = pattern | ||||
|     .replace(/\*\*/g, ':::DOUBLE_WILDCARD:::') | ||||
|     .replace(/\*/g, ':::SINGLE_WILDCARD:::'); | ||||
|   working = working.replace(/([.+^${}()|[\]\\])/g, '\\$1'); | ||||
|   working = working | ||||
|     .replace(/:::DOUBLE_WILDCARD:::\//g, '(?:.*/)?') | ||||
|     .replace(/:::DOUBLE_WILDCARD:::/g, '.*') | ||||
|     .replace(/:::SINGLE_WILDCARD:::/g, '[^/]*'); | ||||
|   return new RegExp(`^${working}$`); | ||||
| } | ||||
|  | ||||
| function walkFiles(root, matcher) { | ||||
|   const out = []; | ||||
|   const stack = [root]; | ||||
|   while (stack.length) { | ||||
|     const current = stack.pop(); | ||||
|     const stat = fs.statSync(current, { throwIfNoEntry: true }); | ||||
|     if (stat.isDirectory()) { | ||||
|       const entries = fs.readdirSync(current); | ||||
|       for (const entry of entries) { | ||||
|         stack.push(path.join(current, entry)); | ||||
|       } | ||||
|     } else if (stat.isFile()) { | ||||
|       const relativePath = path.relative(root, current).replace(/\\/g, '/'); | ||||
|       if (matcher.test(relativePath)) { | ||||
|         out.push(current); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return out; | ||||
| } | ||||
|  | ||||
| function parseArgs(argv) { | ||||
|   const args = { | ||||
|     config: path.join(__dirname, 'config.json'), | ||||
|     iterations: undefined, | ||||
|     thresholdMs: undefined, | ||||
|     out: undefined, | ||||
|     repoRoot: path.join(__dirname, '..', '..'), | ||||
|   }; | ||||
|  | ||||
|   for (let i = 2; i < argv.length; i++) { | ||||
|     const current = argv[i]; | ||||
|     switch (current) { | ||||
|       case '--config': | ||||
|         args.config = argv[++i]; | ||||
|         break; | ||||
|       case '--iterations': | ||||
|         args.iterations = Number(argv[++i]); | ||||
|         break; | ||||
|       case '--threshold-ms': | ||||
|         args.thresholdMs = Number(argv[++i]); | ||||
|         break; | ||||
|       case '--out': | ||||
|         args.out = argv[++i]; | ||||
|         break; | ||||
|       case '--repo-root': | ||||
|       case '--samples': | ||||
|         args.repoRoot = argv[++i]; | ||||
|         break; | ||||
|       default: | ||||
|         throw new Error(`Unknown argument: ${current}`); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return args; | ||||
| } | ||||
|  | ||||
| function loadConfig(configPath) { | ||||
|   const json = fs.readFileSync(configPath, 'utf8'); | ||||
|   const cfg = JSON.parse(json); | ||||
|   if (!Array.isArray(cfg.scenarios) || cfg.scenarios.length === 0) { | ||||
|     throw new Error('config.scenarios must be a non-empty array'); | ||||
|   } | ||||
|   return cfg; | ||||
| } | ||||
|  | ||||
| function ensureWithinRepo(repoRoot, target) { | ||||
|   const relative = path.relative(repoRoot, target); | ||||
|   if (relative === '' || relative === '.') { | ||||
|     return true; | ||||
|   } | ||||
|   return !relative.startsWith('..') && !path.isAbsolute(relative); | ||||
| } | ||||
|  | ||||
| function parseNodePackage(contents) { | ||||
|   const parsed = JSON.parse(contents); | ||||
|   if (!parsed.name || !parsed.version) { | ||||
|     throw new Error('package.json missing name/version'); | ||||
|   } | ||||
|   return { name: parsed.name, version: parsed.version }; | ||||
| } | ||||
|  | ||||
| function parsePythonMetadata(contents) { | ||||
|   let name; | ||||
|   let version; | ||||
|   for (const line of contents.split(/\r?\n/)) { | ||||
|     if (!name && line.startsWith('Name:')) { | ||||
|       name = line.slice(5).trim(); | ||||
|     } else if (!version && line.startsWith('Version:')) { | ||||
|       version = line.slice(8).trim(); | ||||
|     } | ||||
|     if (name && version) { | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   if (!name || !version) { | ||||
|     throw new Error('METADATA missing Name/Version headers'); | ||||
|   } | ||||
|   return { name, version }; | ||||
| } | ||||
|  | ||||
| function formatRow(row) { | ||||
|   const cols = [ | ||||
|     row.id.padEnd(28), | ||||
|     row.sampleCount.toString().padStart(5), | ||||
|     row.meanMs.toFixed(2).padStart(9), | ||||
|     row.p95Ms.toFixed(2).padStart(9), | ||||
|     row.maxMs.toFixed(2).padStart(9), | ||||
|   ]; | ||||
|   return cols.join(' | '); | ||||
| } | ||||
|  | ||||
| function percentile(sortedDurations, percentile) { | ||||
|   if (sortedDurations.length === 0) { | ||||
|     return 0; | ||||
|   } | ||||
|   const rank = (percentile / 100) * (sortedDurations.length - 1); | ||||
|   const lower = Math.floor(rank); | ||||
|   const upper = Math.ceil(rank); | ||||
|   const weight = rank - lower; | ||||
|   if (upper >= sortedDurations.length) { | ||||
|     return sortedDurations[lower]; | ||||
|   } | ||||
|   return sortedDurations[lower] + weight * (sortedDurations[upper] - sortedDurations[lower]); | ||||
| } | ||||
|  | ||||
| function main() { | ||||
|   const args = parseArgs(process.argv); | ||||
|   const cfg = loadConfig(args.config); | ||||
|   const iterations = args.iterations ?? cfg.iterations ?? 5; | ||||
|   const thresholdMs = args.thresholdMs ?? cfg.thresholdMs ?? 5000; | ||||
|  | ||||
|   const results = []; | ||||
|   const failures = []; | ||||
|  | ||||
|   for (const scenario of cfg.scenarios) { | ||||
|     const scenarioRoot = path.resolve(args.repoRoot, scenario.root); | ||||
|     if (!ensureWithinRepo(args.repoRoot, scenarioRoot)) { | ||||
|       throw new Error(`Scenario root ${scenario.root} escapes repo root ${args.repoRoot}`); | ||||
|     } | ||||
|     if (!fs.existsSync(scenarioRoot)) { | ||||
|       throw new Error(`Scenario root ${scenarioRoot} does not exist`); | ||||
|     } | ||||
|  | ||||
|     const matcher = globToRegExp(scenario.matcher.replace(/\\/g, '/')); | ||||
|     const durations = []; | ||||
|     let sampleCount = 0; | ||||
|  | ||||
|     for (let attempt = 0; attempt < iterations; attempt++) { | ||||
|       const start = performance.now(); | ||||
|       const files = walkFiles(scenarioRoot, matcher); | ||||
|       if (files.length === 0) { | ||||
|         throw new Error(`Scenario ${scenario.id} matched no files`); | ||||
|       } | ||||
|  | ||||
|       for (const filePath of files) { | ||||
|         const contents = fs.readFileSync(filePath, 'utf8'); | ||||
|         if (scenario.parser === 'node') { | ||||
|           parseNodePackage(contents); | ||||
|         } else if (scenario.parser === 'python') { | ||||
|           parsePythonMetadata(contents); | ||||
|         } else { | ||||
|           throw new Error(`Unknown parser ${scenario.parser} for scenario ${scenario.id}`); | ||||
|         } | ||||
|       } | ||||
|       const end = performance.now(); | ||||
|       durations.push(end - start); | ||||
|       sampleCount = files.length; | ||||
|     } | ||||
|  | ||||
|     durations.sort((a, b) => a - b); | ||||
|     const mean = durations.reduce((acc, value) => acc + value, 0) / durations.length; | ||||
|     const p95 = percentile(durations, 95); | ||||
|     const max = durations[durations.length - 1]; | ||||
|  | ||||
|     if (max > thresholdMs) { | ||||
|       failures.push(`${scenario.id} exceeded threshold: ${(max).toFixed(2)} ms > ${thresholdMs} ms`); | ||||
|     } | ||||
|  | ||||
|     results.push({ | ||||
|       id: scenario.id, | ||||
|       label: scenario.label, | ||||
|       sampleCount, | ||||
|       meanMs: mean, | ||||
|       p95Ms: p95, | ||||
|       maxMs: max, | ||||
|       iterations, | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   console.log('Scenario                     | Count |   Mean(ms) |    P95(ms) |     Max(ms)'); | ||||
|   console.log('---------------------------- | ----- | --------- | --------- | ----------'); | ||||
|   for (const row of results) { | ||||
|     console.log(formatRow(row)); | ||||
|   } | ||||
|  | ||||
|   if (args.out) { | ||||
|     const header = 'scenario,iterations,sample_count,mean_ms,p95_ms,max_ms\n'; | ||||
|     const csvRows = results | ||||
|       .map((row) => | ||||
|         [ | ||||
|           row.id, | ||||
|           row.iterations, | ||||
|           row.sampleCount, | ||||
|           row.meanMs.toFixed(4), | ||||
|           row.p95Ms.toFixed(4), | ||||
|           row.maxMs.toFixed(4), | ||||
|         ].join(',') | ||||
|       ) | ||||
|       .join('\n'); | ||||
|     fs.writeFileSync(args.out, header + csvRows + '\n', 'utf8'); | ||||
|   } | ||||
|  | ||||
|   if (failures.length > 0) { | ||||
|     console.error('\nPerformance threshold exceeded:'); | ||||
|     for (const failure of failures) { | ||||
|       console.error(` - ${failure}`); | ||||
|     } | ||||
|     process.exitCode = 1; | ||||
|   } | ||||
| } | ||||
|  | ||||
| if (require.main === module) { | ||||
|   try { | ||||
|     main(); | ||||
|   } catch (err) { | ||||
|     console.error(err instanceof Error ? err.message : err); | ||||
|     process.exit(1); | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user