fix(rust-bridge): correct Email.addHeader() calls and IBounceDetection interface
Use addHeader() instead of non-existent setHeader() for security result headers, and align IBounceDetection with actual Rust struct fields (bounce_type + category only).
This commit is contained in:
136
test/test.rustsecuritybridge.node.ts
Normal file
136
test/test.rustsecuritybridge.node.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
import { RustSecurityBridge } from '../ts/security/classes.rustsecuritybridge.js';
|
||||
|
||||
let bridge: RustSecurityBridge;
|
||||
|
||||
tap.test('RustSecurityBridge - should get singleton instance', async () => {
|
||||
bridge = RustSecurityBridge.getInstance();
|
||||
expect(bridge).toBeTruthy();
|
||||
expect(bridge).toEqual(RustSecurityBridge.getInstance()); // same instance
|
||||
});
|
||||
|
||||
tap.test('RustSecurityBridge - should start the Rust binary', async () => {
|
||||
const ok = await bridge.start();
|
||||
if (!ok) {
|
||||
console.log('WARNING: Rust binary not available — skipping bridge tests');
|
||||
console.log('Build it with: cd rust && cargo build --release');
|
||||
}
|
||||
// We accept both true and false — the binary may not be built yet
|
||||
expect(typeof ok).toEqual('boolean');
|
||||
});
|
||||
|
||||
tap.test('RustSecurityBridge - ping should return pong', async () => {
|
||||
if (!bridge.running) {
|
||||
console.log('SKIP: bridge not running');
|
||||
return;
|
||||
}
|
||||
const pong = await bridge.ping();
|
||||
expect(pong).toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('RustSecurityBridge - version should return crate versions', async () => {
|
||||
if (!bridge.running) {
|
||||
console.log('SKIP: bridge not running');
|
||||
return;
|
||||
}
|
||||
const version = await bridge.getVersion();
|
||||
expect(version.bin).toBeTruthy();
|
||||
expect(version.core).toBeTruthy();
|
||||
expect(version.security).toBeTruthy();
|
||||
});
|
||||
|
||||
tap.test('RustSecurityBridge - validateEmail with valid address', async () => {
|
||||
if (!bridge.running) {
|
||||
console.log('SKIP: bridge not running');
|
||||
return;
|
||||
}
|
||||
const result = await bridge.validateEmail('test@example.com');
|
||||
expect(result.valid).toBeTrue();
|
||||
expect(result.formatValid).toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('RustSecurityBridge - validateEmail with invalid address', async () => {
|
||||
if (!bridge.running) {
|
||||
console.log('SKIP: bridge not running');
|
||||
return;
|
||||
}
|
||||
const result = await bridge.validateEmail('not-an-email');
|
||||
expect(result.formatValid).toBeFalse();
|
||||
});
|
||||
|
||||
tap.test('RustSecurityBridge - detectBounce with known SMTP response', async () => {
|
||||
if (!bridge.running) {
|
||||
console.log('SKIP: bridge not running');
|
||||
return;
|
||||
}
|
||||
const result = await bridge.detectBounce({
|
||||
smtpResponse: '550 5.1.1 User unknown',
|
||||
});
|
||||
expect(result.bounce_type).toBeTruthy();
|
||||
expect(result.category).toBeTruthy();
|
||||
});
|
||||
|
||||
tap.test('RustSecurityBridge - checkIpReputation', async () => {
|
||||
if (!bridge.running) {
|
||||
console.log('SKIP: bridge not running');
|
||||
return;
|
||||
}
|
||||
// Use a well-known IP that should NOT be on blacklists
|
||||
const result = await bridge.checkIpReputation('8.8.8.8');
|
||||
expect(result.ip).toEqual('8.8.8.8');
|
||||
expect(typeof result.score).toEqual('number');
|
||||
expect(result.score).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
tap.test('RustSecurityBridge - verifyDkim with unsigned message', async () => {
|
||||
if (!bridge.running) {
|
||||
console.log('SKIP: bridge not running');
|
||||
return;
|
||||
}
|
||||
const rawMessage = 'From: test@example.com\r\nTo: receiver@example.com\r\nSubject: Test\r\n\r\nHello';
|
||||
const results = await bridge.verifyDkim(rawMessage);
|
||||
expect(results.length).toBeGreaterThan(0);
|
||||
expect(results[0].status).toEqual('none'); // no DKIM signature
|
||||
});
|
||||
|
||||
tap.test('RustSecurityBridge - verifyEmail compound call', async () => {
|
||||
if (!bridge.running) {
|
||||
console.log('SKIP: bridge not running');
|
||||
return;
|
||||
}
|
||||
const rawMessage = 'From: test@example.com\r\nTo: receiver@example.com\r\nSubject: Test\r\n\r\nHello';
|
||||
const result = await bridge.verifyEmail({
|
||||
rawMessage,
|
||||
ip: '93.184.216.34', // example.com IP
|
||||
heloDomain: 'example.com',
|
||||
hostname: 'mail.test.local',
|
||||
mailFrom: 'test@example.com',
|
||||
});
|
||||
expect(result.dkim).toBeTruthy();
|
||||
expect(result.dkim.length).toBeGreaterThan(0);
|
||||
expect(result.spf).toBeTruthy();
|
||||
// DMARC may or may not be present depending on DNS
|
||||
});
|
||||
|
||||
tap.test('RustSecurityBridge - should stop gracefully', async () => {
|
||||
if (!bridge.running) {
|
||||
console.log('SKIP: bridge not running');
|
||||
return;
|
||||
}
|
||||
await bridge.stop();
|
||||
expect(bridge.running).toBeFalse();
|
||||
});
|
||||
|
||||
tap.test('RustSecurityBridge - commands should fail when bridge is stopped', async () => {
|
||||
// Bridge should not be running now
|
||||
expect(bridge.running).toBeFalse();
|
||||
try {
|
||||
await bridge.ping();
|
||||
// If we get here, the bridge auto-restarted or something unexpected
|
||||
expect(true).toBeFalse(); // Should not reach here
|
||||
} catch (err) {
|
||||
expect(err).toBeTruthy(); // Expected: bridge not running error
|
||||
}
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
Reference in New Issue
Block a user