chore: import upstream snapshot with attribution
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:24:08 +08:00
commit 0d3cb498a3
5438 changed files with 1316560 additions and 0 deletions
@@ -0,0 +1,77 @@
import { describe, expect, it } from 'vitest';
import {
ALIASED_PLUGIN_MAPPINGS,
ALIASED_PLUGINS,
DOD_AI_ETHICS_MAPPING,
DOD_AI_ETHICS_PRINCIPLE_NAMES,
FRAMEWORK_NAMES,
} from '../../../src/redteam/constants/frameworks';
import { ALL_PLUGINS } from '../../../src/redteam/constants/plugins';
describe('DoD AI Ethical Principles framework mapping', () => {
describe('DOD_AI_ETHICS_PRINCIPLE_NAMES', () => {
it('should contain all 5 principles', () => {
expect(DOD_AI_ETHICS_PRINCIPLE_NAMES).toHaveLength(5);
});
it('should have the expected principle names in order', () => {
expect(DOD_AI_ETHICS_PRINCIPLE_NAMES).toEqual([
'Responsible',
'Equitable',
'Traceable',
'Reliable',
'Governable',
]);
});
});
describe('DOD_AI_ETHICS_MAPPING', () => {
it('should have mappings for all 5 principles', () => {
const expectedKeys = Array.from(
{ length: 5 },
(_, i) => `dod:ai:ethics:${String(i + 1).padStart(2, '0')}`,
);
expectedKeys.forEach((key) => {
expect(DOD_AI_ETHICS_MAPPING).toHaveProperty(key);
});
});
it('each principle mapping should have plugins and strategies arrays', () => {
Object.values(DOD_AI_ETHICS_MAPPING).forEach((mapping) => {
expect(Array.isArray(mapping.plugins)).toBe(true);
expect(Array.isArray(mapping.strategies)).toBe(true);
expect(mapping.plugins.length).toBeGreaterThan(0);
});
});
it('all mapped plugins should be valid plugin IDs', () => {
const validPluginIds = new Set<string>(ALL_PLUGINS);
Object.values(DOD_AI_ETHICS_MAPPING).forEach((mapping) => {
mapping.plugins.forEach((pluginId) => {
expect(validPluginIds.has(pluginId)).toBe(true);
});
});
});
});
describe('framework integration', () => {
it('should register DoD framework display name', () => {
expect(FRAMEWORK_NAMES['dod:ai:ethics']).toBe('DoD AI Ethical Principles');
});
it('should include dod:ai:ethics in aliased plugins', () => {
expect(ALIASED_PLUGINS).toContain('dod:ai:ethics');
});
it('should include all principle keys in aliased plugins', () => {
Object.keys(DOD_AI_ETHICS_MAPPING).forEach((key) => {
expect(ALIASED_PLUGINS).toContain(key);
});
});
it('should map dod:ai:ethics alias to DOD_AI_ETHICS_MAPPING', () => {
expect(ALIASED_PLUGIN_MAPPINGS['dod:ai:ethics']).toBe(DOD_AI_ETHICS_MAPPING);
});
});
});
+190
View File
@@ -0,0 +1,190 @@
import { describe, expect, it } from 'vitest';
import {
categoryAliases,
categoryAliasesReverse,
categoryDescriptions,
categoryLabels,
categoryMapReverse,
DEFAULT_OUTPUT_PATH,
displayNameOverrides,
PLUGIN_PRESET_DESCRIPTIONS,
pluginDescriptions,
riskCategories,
riskCategorySeverityMap,
Severity,
strategyDescriptions,
strategyDisplayNames,
subCategoryDescriptions,
} from '../../../src/redteam/constants/metadata';
import {
ADDITIONAL_PLUGINS,
BASE_PLUGINS,
BIAS_PLUGINS,
FINANCIAL_PLUGINS,
HARM_PLUGINS,
MEDICAL_PLUGINS,
PII_PLUGINS,
} from '../../../src/redteam/constants/plugins';
import type { Plugin } from '../../../src/redteam/constants/plugins';
import type { Strategy } from '../../../src/redteam/constants/strategies';
describe('metadata constants', () => {
describe('Risk category severity map', () => {
it('should have valid severity levels', () => {
Object.values(riskCategorySeverityMap).forEach((severity) => {
expect(Object.values(Severity)).toContain(severity);
});
});
});
describe('Risk categories', () => {
it('should have valid category descriptions', () => {
Object.keys(riskCategories).forEach((category) => {
// @ts-expect-error: categoryDescriptions is only indexed by TopLevelCategory (not string)
expect(categoryDescriptions[category]).toBeDefined();
// @ts-expect-error: categoryDescriptions is only indexed by TopLevelCategory (not string)
expect(typeof categoryDescriptions[category]).toBe('string');
});
});
it('should have valid category mapping for each plugin', () => {
Object.entries(categoryMapReverse).forEach(([plugin, category]) => {
const foundInCategory = Object.entries(riskCategories).some(
([cat, plugins]) => cat === category && plugins.includes(plugin as Plugin),
);
expect(foundInCategory).toBe(true);
});
});
it('should have matching category labels', () => {
expect(categoryLabels).toEqual(Object.keys(categoryMapReverse));
});
it('should not include duplicate plugin ids within a category', () => {
Object.entries(riskCategories).forEach(([_category, plugins]) => {
const uniquePlugins = new Set(plugins);
expect(uniquePlugins.size).toBe(plugins.length);
});
});
it('should include all defined plugins in risk categories', () => {
// Get all plugins from risk categories
const riskCategoryPlugins = new Set<Plugin>();
Object.values(riskCategories).forEach((plugins) => {
plugins.forEach((plugin) => {
riskCategoryPlugins.add(plugin);
});
});
// Get all defined plugins from constants
const allDefinedPlugins = new Set<Plugin>();
// Add plugins from various constant arrays
[...BASE_PLUGINS].forEach((plugin) => allDefinedPlugins.add(plugin));
[...ADDITIONAL_PLUGINS].forEach((plugin) => allDefinedPlugins.add(plugin));
[...BIAS_PLUGINS].forEach((plugin) => allDefinedPlugins.add(plugin));
[...PII_PLUGINS].forEach((plugin) => allDefinedPlugins.add(plugin));
[...MEDICAL_PLUGINS].forEach((plugin) => allDefinedPlugins.add(plugin));
[...FINANCIAL_PLUGINS].forEach((plugin) => allDefinedPlugins.add(plugin));
// Add plugins from HARM_PLUGINS object
Object.keys(HARM_PLUGINS).forEach((plugin) => {
allDefinedPlugins.add(plugin as Plugin);
});
// Special plugins that shouldn't be in risk categories (collections and custom plugins)
const excludedPlugins = new Set([
'intent', // Custom intent plugin handled separately in UI
'policy', // Custom policy plugin handled separately in UI
'default', // Collection
'foundation', // Collection
'harmful', // Collection
'bias', // Collection
'pii', // Collection
'medical', // Collection
'guardrails-eval', // Collection
]);
// Find plugins that are defined but missing from risk categories
const missingPlugins = Array.from(allDefinedPlugins).filter(
(plugin) => !riskCategoryPlugins.has(plugin) && !excludedPlugins.has(plugin),
);
if (missingPlugins.length > 0) {
throw new Error(
`The following plugins are defined but missing from risk categories: ${missingPlugins.join(
', ',
)}. Please add them to the appropriate category in riskCategories object in metadata.ts`,
);
}
expect(missingPlugins).toEqual([]);
});
});
describe('Category aliases', () => {
it('should have valid aliases mapping', () => {
const uniqueValues = new Set(Object.values(categoryAliases));
uniqueValues.forEach((value) => {
const keys = Object.entries(categoryAliases)
.filter(([, v]) => v === value)
.map(([k]) => k);
const reverseKey = categoryAliasesReverse[value];
expect(keys).toContain(reverseKey);
});
});
});
describe('Plugin and strategy descriptions', () => {
it('should have descriptions for all plugins', () => {
Object.keys(pluginDescriptions).forEach((plugin) => {
expect(typeof pluginDescriptions[plugin as Plugin]).toBe('string');
expect(pluginDescriptions[plugin as Plugin].length).toBeGreaterThan(0);
});
});
it('should have descriptions for all strategies', () => {
Object.keys(strategyDescriptions).forEach((strategy) => {
expect(typeof strategyDescriptions[strategy as Strategy]).toBe('string');
expect(strategyDescriptions[strategy as Strategy].length).toBeGreaterThan(0);
});
});
it('should have display names for all strategies', () => {
Object.keys(strategyDisplayNames).forEach((strategy) => {
expect(typeof strategyDisplayNames[strategy as Strategy]).toBe('string');
expect(strategyDisplayNames[strategy as Strategy].length).toBeGreaterThan(0);
});
});
});
describe('Plugin preset descriptions', () => {
it('should have valid preset descriptions', () => {
Object.entries(PLUGIN_PRESET_DESCRIPTIONS).forEach(([preset, description]) => {
expect(typeof preset).toBe('string');
expect(typeof description).toBe('string');
expect(description.length).toBeGreaterThan(0);
});
});
});
describe('Display name overrides', () => {
it('should have display names for memory poisoning plugin', () => {
expect(displayNameOverrides['agentic:memory-poisoning']).toBe('Agentic Memory Poisoning');
});
it('should have matching subcategory descriptions', () => {
Object.keys(displayNameOverrides).forEach((key) => {
const keyAsPluginOrStrategy = key as Plugin | Strategy;
expect(subCategoryDescriptions[keyAsPluginOrStrategy]).toBeDefined();
});
});
});
describe('Default output path', () => {
it('should be defined correctly', () => {
expect(DEFAULT_OUTPUT_PATH).toBe('redteam.yaml');
});
});
});
+85
View File
@@ -0,0 +1,85 @@
import { describe, expect, it } from 'vitest';
import {
ALIASED_PLUGIN_MAPPINGS,
ALIASED_PLUGINS,
MITRE_ATLAS_LEGACY_MAPPING,
MITRE_ATLAS_MAPPING,
} from '../../../src/redteam/constants/frameworks';
import { ALL_PLUGINS, COLLECTIONS } from '../../../src/redteam/constants/plugins';
import { ALL_STRATEGIES } from '../../../src/redteam/constants/strategies';
describe('MITRE ATLAS framework mapping', () => {
const currentAtlasTacticAliases = [
'mitre:atlas:reconnaissance',
'mitre:atlas:resource-development',
'mitre:atlas:initial-access',
'mitre:atlas:ai-model-access',
'mitre:atlas:execution',
'mitre:atlas:persistence',
'mitre:atlas:privilege-escalation',
'mitre:atlas:defense-evasion',
'mitre:atlas:credential-access',
'mitre:atlas:discovery',
'mitre:atlas:lateral-movement',
'mitre:atlas:collection',
'mitre:atlas:ai-attack-staging',
'mitre:atlas:command-and-control',
'mitre:atlas:exfiltration',
'mitre:atlas:impact',
];
it('maps the current ATLAS tactic aliases', () => {
expect(Object.keys(MITRE_ATLAS_MAPPING).sort()).toEqual([...currentAtlasTacticAliases].sort());
});
it('keeps the legacy ML Attack Staging alias outside the full preset', () => {
expect(MITRE_ATLAS_MAPPING).not.toHaveProperty('mitre:atlas:ml-attack-staging');
expect(MITRE_ATLAS_LEGACY_MAPPING['mitre:atlas:ml-attack-staging']).toBe(
MITRE_ATLAS_MAPPING['mitre:atlas:ai-attack-staging'],
);
});
it('makes empty tactic coverage explicit', () => {
const emptyTacticAliases = Object.entries(MITRE_ATLAS_MAPPING)
.filter(([, { plugins, strategies }]) => plugins.length === 0 && strategies.length === 0)
.map(([alias]) => alias);
expect(emptyTacticAliases).toEqual(['mitre:atlas:ai-model-access']);
});
it('registers MITRE aliases for validator expansion', () => {
expect(ALIASED_PLUGINS).toContain('mitre:atlas');
expect(ALIASED_PLUGINS).toContain('mitre:atlas:ml-attack-staging');
currentAtlasTacticAliases.forEach((key) => {
expect(ALIASED_PLUGINS).toContain(key);
});
expect(ALIASED_PLUGIN_MAPPINGS['mitre:atlas']).toBe(MITRE_ATLAS_MAPPING);
expect(ALIASED_PLUGIN_MAPPINGS['mitre:atlas:ml-attack-staging']).toBe(
MITRE_ATLAS_LEGACY_MAPPING,
);
});
it('uses valid plugin and strategy identifiers', () => {
const validPlugins = new Set<string>([...ALL_PLUGINS, ...COLLECTIONS]);
const validStrategies = new Set<string>(ALL_STRATEGIES);
[...Object.values(MITRE_ATLAS_MAPPING), ...Object.values(MITRE_ATLAS_LEGACY_MAPPING)].forEach(
({ plugins, strategies }) => {
plugins.forEach((plugin) => expect(validPlugins.has(plugin)).toBe(true));
strategies.forEach((strategy) => expect(validStrategies.has(strategy)).toBe(true));
},
);
});
it('covers newly-added agentic ATLAS tactics with existing promptfoo checks', () => {
expect(MITRE_ATLAS_MAPPING['mitre:atlas:persistence'].plugins).toContain(
'agentic:memory-poisoning',
);
expect(MITRE_ATLAS_MAPPING['mitre:atlas:credential-access'].plugins).toContain(
'tool-discovery',
);
expect(MITRE_ATLAS_MAPPING['mitre:atlas:command-and-control'].plugins).toContain('mcp');
expect(MITRE_ATLAS_MAPPING['mitre:atlas:impact'].plugins).toContain('reasoning-dos');
});
});
+146
View File
@@ -0,0 +1,146 @@
import { describe, expect, it } from 'vitest';
import {
ALIASED_PLUGIN_MAPPINGS,
ALIASED_PLUGINS,
OWASP_AGENTIC_NAMES,
OWASP_AGENTIC_TOP_10_MAPPING,
} from '../../../src/redteam/constants/frameworks';
import { ALL_PLUGINS } from '../../../src/redteam/constants/plugins';
describe('OWASP Top 10 for Agentic Applications (ASI01-ASI10)', () => {
describe('OWASP_AGENTIC_NAMES', () => {
it('should contain all 10 risk categories', () => {
expect(OWASP_AGENTIC_NAMES).toHaveLength(10);
});
it('should have correct risk names in order (ASI01-ASI10)', () => {
const expectedNames = [
'ASI01: Agent Goal Hijack',
'ASI02: Tool Misuse and Exploitation',
'ASI03: Identity and Privilege Abuse',
'ASI04: Agentic Supply Chain Vulnerabilities',
'ASI05: Unexpected Code Execution',
'ASI06: Memory and Context Poisoning',
'ASI07: Insecure Inter-Agent Communication',
'ASI08: Cascading Failures',
'ASI09: Human Agent Trust Exploitation',
'ASI10: Rogue Agents',
];
expect(OWASP_AGENTIC_NAMES).toEqual(expectedNames);
});
it('should have sequential numbering from ASI01 to ASI10', () => {
OWASP_AGENTIC_NAMES.forEach((name, index) => {
const expectedPrefix = `ASI${String(index + 1).padStart(2, '0')}:`;
expect(name.startsWith(expectedPrefix)).toBe(true);
});
});
});
describe('OWASP_AGENTIC_TOP_10_MAPPING', () => {
it('should have mappings for all 10 risks (asi01-asi10)', () => {
const expectedKeys = Array.from(
{ length: 10 },
(_, i) => `owasp:agentic:asi${String(i + 1).padStart(2, '0')}`,
);
expectedKeys.forEach((key) => {
expect(OWASP_AGENTIC_TOP_10_MAPPING).toHaveProperty(key);
});
});
it('should have exactly 10 risk mappings', () => {
expect(Object.keys(OWASP_AGENTIC_TOP_10_MAPPING)).toHaveLength(10);
});
it('each mapping should have plugins and strategies arrays', () => {
Object.entries(OWASP_AGENTIC_TOP_10_MAPPING).forEach(([, mapping]) => {
expect(Array.isArray(mapping.plugins)).toBe(true);
expect(Array.isArray(mapping.strategies)).toBe(true);
expect(mapping.plugins.length).toBeGreaterThan(0);
});
});
it('all mapped plugins should be valid plugin IDs', () => {
const allPluginIds = new Set<string>(ALL_PLUGINS);
Object.entries(OWASP_AGENTIC_TOP_10_MAPPING).forEach(([, mapping]) => {
mapping.plugins.forEach((pluginId) => {
expect(allPluginIds.has(pluginId)).toBe(true);
});
});
});
describe('specific risk mappings', () => {
it('ASI01 (Agent Goal Hijack) should map to hijacking and system-prompt-override', () => {
const asi01Plugins = OWASP_AGENTIC_TOP_10_MAPPING['owasp:agentic:asi01'].plugins;
expect(asi01Plugins).toContain('hijacking');
expect(asi01Plugins).toContain('system-prompt-override');
expect(asi01Plugins).toContain('indirect-prompt-injection');
});
it('ASI02 (Tool Misuse and Exploitation) should map to tool-related plugins', () => {
const asi02Plugins = OWASP_AGENTIC_TOP_10_MAPPING['owasp:agentic:asi02'].plugins;
expect(asi02Plugins).toContain('excessive-agency');
expect(asi02Plugins).toContain('mcp');
expect(asi02Plugins).toContain('tool-discovery');
});
it('ASI03 (Identity and Privilege Abuse) should map to authorization plugins', () => {
const asi03Plugins = OWASP_AGENTIC_TOP_10_MAPPING['owasp:agentic:asi03'].plugins;
expect(asi03Plugins).toContain('rbac');
expect(asi03Plugins).toContain('bfla');
expect(asi03Plugins).toContain('bola');
});
it('ASI05 (Unexpected Code Execution) should map to injection plugins', () => {
const asi05Plugins = OWASP_AGENTIC_TOP_10_MAPPING['owasp:agentic:asi05'].plugins;
expect(asi05Plugins).toContain('shell-injection');
expect(asi05Plugins).toContain('sql-injection');
expect(asi05Plugins).toContain('ssrf');
});
it('ASI06 (Memory and Context Poisoning) should map to memory-related plugins', () => {
const asi06Plugins = OWASP_AGENTIC_TOP_10_MAPPING['owasp:agentic:asi06'].plugins;
expect(asi06Plugins).toContain('agentic:memory-poisoning');
expect(asi06Plugins).toContain('cross-session-leak');
});
it('ASI10 (Rogue Agents) should map to agency and access control plugins', () => {
const asi10Plugins = OWASP_AGENTIC_TOP_10_MAPPING['owasp:agentic:asi10'].plugins;
expect(asi10Plugins).toContain('excessive-agency');
expect(asi10Plugins).toContain('hijacking');
expect(asi10Plugins).toContain('rbac');
});
});
});
describe('ALIASED_PLUGINS integration', () => {
it('should include owasp:agentic as an aliased plugin', () => {
expect(ALIASED_PLUGINS).toContain('owasp:agentic');
});
it('should include all individual risk keys (owasp:agentic:asi01-asi10) as aliased plugins', () => {
const riskKeys = Array.from(
{ length: 10 },
(_, i) => `owasp:agentic:asi${String(i + 1).padStart(2, '0')}`,
);
riskKeys.forEach((key) => {
expect(ALIASED_PLUGINS).toContain(key);
});
});
});
describe('ALIASED_PLUGIN_MAPPINGS integration', () => {
it('should map owasp:agentic to OWASP_AGENTIC_TOP_10_MAPPING', () => {
expect(ALIASED_PLUGIN_MAPPINGS['owasp:agentic']).toBe(OWASP_AGENTIC_TOP_10_MAPPING);
});
it('owasp:agentic should expand to all 10 risk mappings', () => {
const mapping = ALIASED_PLUGIN_MAPPINGS['owasp:agentic'];
expect(Object.keys(mapping)).toHaveLength(10);
});
});
});
+76
View File
@@ -0,0 +1,76 @@
import { describe, expect, it } from 'vitest';
import {
AGENTIC_EXEMPT_PLUGINS,
ALL_PLUGINS,
DATASET_EXEMPT_PLUGINS,
STRATEGY_EXEMPT_PLUGINS,
} from '../../../src/redteam/constants/plugins';
describe('plugins constants', () => {
it('should have ALL_PLUGINS as sorted array', () => {
const sorted = [...ALL_PLUGINS].sort();
expect(ALL_PLUGINS).toEqual(sorted);
});
it('should have unique values in ALL_PLUGINS', () => {
const uniquePlugins = new Set(ALL_PLUGINS);
expect(uniquePlugins.size).toBe(ALL_PLUGINS.length);
});
describe('DATASET_EXEMPT_PLUGINS', () => {
it('should include static dataset plugins', () => {
expect(DATASET_EXEMPT_PLUGINS).toContain('aegis');
expect(DATASET_EXEMPT_PLUGINS).toContain('beavertails');
expect(DATASET_EXEMPT_PLUGINS).toContain('cyberseceval');
expect(DATASET_EXEMPT_PLUGINS).toContain('donotanswer');
expect(DATASET_EXEMPT_PLUGINS).toContain('harmbench');
expect(DATASET_EXEMPT_PLUGINS).toContain('pliny');
expect(DATASET_EXEMPT_PLUGINS).toContain('toxic-chat');
expect(DATASET_EXEMPT_PLUGINS).toContain('unsafebench');
expect(DATASET_EXEMPT_PLUGINS).toContain('vlguard');
expect(DATASET_EXEMPT_PLUGINS).toContain('vlsu');
expect(DATASET_EXEMPT_PLUGINS).toContain('xstest');
});
it('should have unique values', () => {
const uniquePlugins = new Set(DATASET_EXEMPT_PLUGINS);
expect(uniquePlugins.size).toBe(DATASET_EXEMPT_PLUGINS.length);
});
});
describe('AGENTIC_EXEMPT_PLUGINS', () => {
it('should include agentic plugins', () => {
expect(AGENTIC_EXEMPT_PLUGINS).toContain('system-prompt-override');
expect(AGENTIC_EXEMPT_PLUGINS).toContain('agentic:memory-poisoning');
});
it('should have unique values', () => {
const uniquePlugins = new Set(AGENTIC_EXEMPT_PLUGINS);
expect(uniquePlugins.size).toBe(AGENTIC_EXEMPT_PLUGINS.length);
});
});
describe('STRATEGY_EXEMPT_PLUGINS', () => {
it('should include both agentic and dataset plugins', () => {
// Should include all agentic plugins
AGENTIC_EXEMPT_PLUGINS.forEach((plugin) => {
expect(STRATEGY_EXEMPT_PLUGINS).toContain(plugin);
});
// Should include all dataset plugins
DATASET_EXEMPT_PLUGINS.forEach((plugin) => {
expect(STRATEGY_EXEMPT_PLUGINS).toContain(plugin);
});
});
it('should have unique values', () => {
const uniquePlugins = new Set(STRATEGY_EXEMPT_PLUGINS);
expect(uniquePlugins.size).toBe(STRATEGY_EXEMPT_PLUGINS.length);
});
it('should be the union of agentic and dataset plugins', () => {
const expectedLength = AGENTIC_EXEMPT_PLUGINS.length + DATASET_EXEMPT_PLUGINS.length;
expect(STRATEGY_EXEMPT_PLUGINS.length).toBe(expectedLength);
});
});
});
+42
View File
@@ -0,0 +1,42 @@
import { describe, expect, it } from 'vitest';
import {
ADDITIONAL_STRATEGIES,
AGENTIC_STRATEGIES,
ALL_STRATEGIES,
getDefaultNFanout,
isCustomStrategy,
isFanoutStrategy,
STRATEGY_COLLECTIONS,
} from '../../../src/redteam/constants/strategies';
describe('strategies constants', () => {
it('should have all strategies sorted', () => {
const expectedStrategies = new Set([
'default',
'basic',
'jailbreak',
'jailbreak:composite',
...AGENTIC_STRATEGIES,
...ADDITIONAL_STRATEGIES,
...STRATEGY_COLLECTIONS,
]);
expect(ALL_STRATEGIES).toEqual(Array.from(expectedStrategies).sort());
});
it('should correctly identify custom strategies', () => {
expect(isCustomStrategy('custom')).toBe(true);
expect(isCustomStrategy('custom:test')).toBe(true);
expect(isCustomStrategy('other')).toBe(false);
});
it('should expose fan-out metadata for supported strategies', () => {
expect(isFanoutStrategy('jailbreak:composite')).toBe(true);
expect(getDefaultNFanout('jailbreak:composite')).toBeGreaterThanOrEqual(1);
expect(isFanoutStrategy('gcg')).toBe(true);
expect(getDefaultNFanout('gcg')).toBeGreaterThanOrEqual(1);
expect(isFanoutStrategy('base64')).toBe(false);
});
});