๐Ÿงช Testing Guide

1. Unit Tests

Run the built-in test suite:

cargo test

This runs tests across all modules:

  • scanner.rs โ€” Import parsing, algorithm string parsing (aes-256-cbc โ†’ AES + 256 + CBC), hardcoded secret detection, insecure PRNG detection
  • diff.rs โ€” Set comparison logic, strict mode violation detection
  • policy.rs โ€” Severity classification, quantum-safety assessment, deprecation detection
  • dependencies.rs โ€” Lockfile parsing for requirements.txt, package-lock.json, Cargo.lock
  • models.rs โ€” CycloneDX conversion and OID lookup

2. Manual Testing with Sample Files

Create test fixture files to verify detection against real code patterns.

Step 1: Create a test directory

mkdir -p test-fixtures

Step 2: Create a Python test file

Create test-fixtures/crypto_sample.py:

import hashlib
import hmac
import ssl
import random  # โš ๏ธ Should be flagged as INSECURE_PRNG
from cryptography.hazmat.primitives.hashes import SHA256, SHA512
from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.primitives.ciphers.modes import CBC, GCM
from cryptography.hazmat.primitives.asymmetric.ec import SECP256R1
from cryptography.hazmat.primitives.asymmetric.padding import OAEP
from Crypto.Cipher import DES3
from Crypto.Hash import MD5

# Direct hashlib usage
digest = hashlib.sha256(b"hello").hexdigest()
digest2 = hashlib.new('sha3_256', b"hello").hexdigest()

# HMAC usage
mac = hmac.new(b"secret", b"message", digestmod=hashlib.sha256)

# โš ๏ธ Hardcoded IV โ€” should be flagged as HARDCODED_IV
iv = b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'

# โš ๏ธ Hardcoded salt โ€” should be flagged as HARDCODED_SALT
salt = b'my_fixed_salt_value'

# Non-crypto import (should NOT be detected)
import os
import json
from collections import defaultdict

Step 3: Create a JavaScript test file

Create test-fixtures/crypto_sample.js:

const crypto = require('crypto');

// Hash
const hash = crypto.createHash('sha256');
hash.update('hello');
console.log(hash.digest('hex'));

// HMAC
const hmac = crypto.createHmac('sha512', 'secret-key');

// Cipher โ€” should extract: AES, 256-bit, CBC mode
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);

// GCM cipher โ€” should extract: AES, 128-bit, GCM mode
const gcmCipher = crypto.createCipheriv('aes-128-gcm', key, iv);

// Random bytes
const token = crypto.randomBytes(32);

// Key generation
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
  modulusLength: 2048,
});

// โš ๏ธ Insecure PRNG โ€” should be flagged
const badRandom = Math.random();

// โš ๏ธ Hardcoded key โ€” should be flagged
const key = Buffer.from('my-secret-key-1234567890abcdef');

// Non-crypto code (should NOT be detected)
const fs = require('fs');
console.log("hello world");

Step 4: Add a requirements.txt

Create test-fixtures/requirements.txt:

flask==2.3.0
cryptography==41.0.0
PyJWT>=2.0
bcrypt
requests>=2.28

Step 5: Run the scan

# Default JSON output
keylens scan --path ./test-fixtures

# CycloneDX output
keylens scan --path ./test-fixtures --format cyclonedx

3. Testing the Diff Engine

keylens scan --path ./test-fixtures > base.json
# ... add crypto ...
keylens scan --path ./test-fixtures > head.json
keylens diff --base base.json --head head.json

4. Docker Testing

# Build the image
docker build -t keylens .

# Run a scan (default JSON)
docker run --rm -v $(pwd)/test-fixtures:/repo keylens scan --path /repo