Skip to content

fix: unify skill and extension catalog generation to include derived suites#210

Merged
jithin23-kv merged 3 commits into
KeyValueSoftwareSystems:masterfrom
jithin23-kv:fix/unify-catalog-generation
Jul 22, 2026
Merged

fix: unify skill and extension catalog generation to include derived suites#210
jithin23-kv merged 3 commits into
KeyValueSoftwareSystems:masterfrom
jithin23-kv:fix/unify-catalog-generation

Conversation

@jithin23-kv

@jithin23-kv jithin23-kv commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Problem

The three catalog generators (core's runtime loader, the extension's build-catalog.mjs, and the skills' build-catalog.ts) reimplemented the same YAML-walk-and-derive logic independently, and had drifted:

  • The skills catalog (skills/{agent,mcp}-redteaming/opfor-setup/catalog.json) only emitted the 4 hand-curated suites and never derived the standards-based suites (OWASP LLM/API/Agentic/MCP Top 10, MITRE ATLAS, EU AI Act, NIST AI RMF) that core and the extension already derive from evaluator standards: tags.
  • opfor-setup/SKILL.md told the agent to offer exactly owasp-llm-top10 and owasp-agentic-ai as the only two suite choices — both absent from the catalog it reads, so following the skill literally was impossible.
  • The skills catalog used snake_case field names (pass_criteria, scan_mode, suite evaluators) while the extension catalog used camelCase (passCriteria, scanMode, suite evaluatorIds) for the same data, for no functional reason.

Solution

  • Extracted the shared parsing + derivation logic into scripts/lib/catalog-core.mjs (plain ESM, no core import — the skills catalog builds before tsc -b core runs, so nothing here can depend on core/dist).
  • scripts/build-catalog.ts (skills) and runners/extension/scripts/build-catalog.mjs (extension) now both import this shared module and only encode their genuine differences:
    • which evaluators to include (extension drops pattern-less whitebox source-scan evaluators; skills keep them for the static pre-scan step),
    • the output field set (extension's minimal shape vs skills' camelCase base + whitebox/MCP fields).
  • Skills catalog now emits the same camelCase schema as the extension catalog, plus the derived standards suites.
  • Updated opfor-setup/opfor-run SKILL.md + report-schema.md (both agent and mcp bundles) for the new field names, and rewrote the suite-selection step to enumerate suites from the catalog dynamically instead of hardcoding two suite IDs that didn't exist in it.
  • Documented the new shared module and both generators in AGENTS.md's Key files table.
  • runners/extension/catalog.json output is byte-for-byte unchanged — verified by diff before/after against the committed file.

Changes

  • scripts/lib/catalog-core.mjs (new) — shared discovery/parsing/deriveStandardSuites
  • scripts/build-catalog.ts — rewritten to use the shared module, emit camelCase + derived suites
  • runners/extension/scripts/build-catalog.mjs — rewritten to use the shared module (output unchanged)
  • skills/{agent,mcp}-redteaming/opfor-setup/catalog.json — regenerated (camelCase, derived suites added)
  • skills/{agent,mcp}-redteaming/opfor-{setup,run}/SKILL.md, report-schema.md — field-name updates, dynamic suite enumeration
  • AGENTS.md, eslint.config.js (added scripts/**/*.mjs to the existing node-globals block, needed by the new shared module)

Issue

N/A — found while auditing the agent-redteaming skills for drift against the CLI/extension engine.

How to test

npm run build                  # full clean build succeeds
npm run typecheck              # clean
npm run lint                   # clean
npm run format:check           # clean
npm test                       # 163 pass, 0 fail
npm run build:catalog:check    # catalogs up to date
npx tsx scripts/validate-skills.ts   # 0 errors

# confirm extension output is unaffected by the refactor
git show origin/master:runners/extension/catalog.json > /tmp/before.json
node runners/extension/scripts/build-catalog.mjs
diff /tmp/before.json runners/extension/catalog.json   # empty

# confirm skills catalog now carries the derived suites
node -e "console.log(require('./skills/agent-redteaming/opfor-setup/catalog.json').suites.map(s => s.id))"

All of the above were run locally against a full from-scratch rebuild (deleted all dist/, tsconfig.tsbuildinfo, and generated catalog.json files first).

Summary by CodeRabbit

  • New Features

    • Catalog generation now centralizes evaluator/suite parsing, produces deterministic outputs, and includes clearer derived standards coverage.
    • Extension catalog generation outputs a browser-ready evaluator set with stable, minimal metadata.
  • Documentation

    • Updated red-teaming setup/execution docs and report/schema text to use camelCase correlation and criteria fields, aligning examples with the updated catalog schema.
  • Bug Fixes

    • Improved warnings/validation for suites that reference missing evaluators and refined generator summary reporting.
  • Tests

    • Added unit tests for shared catalog core and extension catalog helpers; CI now runs these generator tests.
  • Chores

    • Expanded ESLint coverage for .mjs build scripts.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Catalog parsing and suite derivation are centralized in a shared module. Extension and skills catalog builders now consume normalized data, while agent and MCP catalogs and workflow documentation adopt camelCase fields and suite-driven selection.

Changes

Catalog generation

Layer / File(s) Summary
Shared catalog parsing and normalization
scripts/lib/catalog-core.mjs, scripts/tests/catalog-core.test.mjs
Adds deterministic evaluator and suite discovery, YAML normalization, standard-suite derivation, dangling-reference warnings, and parser tests.
Catalog generator integration
runners/extension/scripts/build-catalog.mjs, scripts/build-catalog.ts, scripts/tests/build-catalog.test.ts, runners/extension/tests/build-catalog.test.mjs, eslint.config.js, AGENTS.md
Refactors both catalog builders to use shared logic, emits surface-specific evaluator shapes, adds direct-import guards and serialization tests, and extends ESLint coverage.
Agent catalog and workflow schema
skills/agent-redteaming/opfor-setup/*, skills/agent-redteaming/opfor-run/*
Aligns agent catalog fields and workflow documentation with camelCase criteria, source-scan metadata, suite selection, and correlation naming.
MCP catalog and workflow schema
skills/mcp-redteaming/opfor-setup/*, skills/mcp-redteaming/opfor-run/*
Updates MCP catalog metadata, evaluator fields, setup instructions, static-scan terminology, and correlation references.
Catalog test CI wiring
package.json, .github/workflows/ci.yml
Adds the catalog generator test command and runs it in the catalogs CI job.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BuildScripts
  participant CatalogCore
  participant CatalogJSON
  participant OpforSetup
  participant OpforRun
  BuildScripts->>CatalogCore: discover and normalize evaluators and suites
  CatalogCore->>BuildScripts: return derived suites and validated references
  BuildScripts->>CatalogJSON: write surface-specific catalog output
  OpforSetup->>CatalogJSON: read suites, evaluatorIds, and criteria
  OpforRun->>OpforSetup: use source-scan and correlation metadata
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 61.54% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly reflects the refactor and the addition of derived suites.
Description check ✅ Passed The description covers the required template sections, and the missing Screenshots section is non-critical.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
.github/workflows/ci.yml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

package.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
scripts/lib/catalog-core.mjs (2)

115-119: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Invalid severity values silently become "high".

A typo like sevirity: hgih or an unsupported string silently maps to "high" with no warning, masking config errors in the generated catalog (could misreport a finding's real severity).

🛡️ Proposed fix: warn on unrecognized values
 function normalizeSeverity(s) {
   const v = (s || "").toLowerCase();
   if (v === "critical" || v === "high" || v === "medium" || v === "low") return v;
+  if (v) console.warn(`[catalog] unrecognized severity "${s}", defaulting to "high"`);
   return "high";
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/lib/catalog-core.mjs` around lines 115 - 119, Update
normalizeSeverity so unrecognized non-empty severity values emit a warning
before falling back to "high", while preserving the existing accepted values and
fallback behavior. Include the invalid value in the warning to make
configuration typos diagnosable.

154-185: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Malformed pattern entries are dropped silently.

Inline patterns missing name/template (154-167) and file-based fallback patterns missing template (168-185) are skipped with no log, unlike the strict id/name/suite validations elsewhere in this file that throw. A typo in a pattern's template key would silently shrink the evaluator's attack surface without anyone noticing.

🛡️ Proposed fix: warn on skipped inline patterns
       if (pName && template) {
         const pattern = { name: pName, template };
         const judgeHint = str(item, "judge_hint").trim();
         if (judgeHint) pattern.judgeHint = judgeHint;
         patterns.push(pattern);
+      } else {
+        console.warn(`[catalog] ${filePath}: skipping malformed inline pattern (missing name/template)`);
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/lib/catalog-core.mjs` around lines 154 - 185, Add warnings when
malformed pattern entries are skipped in the inline parsing loop and file-based
fallback loop: report the relevant pattern identity/source and the missing or
invalid name/template fields before continuing. Preserve valid pattern
collection and existing file-read error handling, and ensure malformed entries
are no longer silently dropped.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/build-catalog.ts`:
- Around line 40-61: Update toSkillEvaluator to preserve the top-level
judge_hint field by mapping it onto the evaluator output alongside the other MCP
judging metadata. Ensure skills/*/catalog.json retains existing judge guidance
while leaving unrelated field handling unchanged.

---

Nitpick comments:
In `@scripts/lib/catalog-core.mjs`:
- Around line 115-119: Update normalizeSeverity so unrecognized non-empty
severity values emit a warning before falling back to "high", while preserving
the existing accepted values and fallback behavior. Include the invalid value in
the warning to make configuration typos diagnosable.
- Around line 154-185: Add warnings when malformed pattern entries are skipped
in the inline parsing loop and file-based fallback loop: report the relevant
pattern identity/source and the missing or invalid name/template fields before
continuing. Preserve valid pattern collection and existing file-read error
handling, and ensure malformed entries are no longer silently dropped.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 717033c4-5cd9-4767-81ab-143e90d76735

📥 Commits

Reviewing files that changed from the base of the PR and between c8c9f72 and 627ca53.

📒 Files selected for processing (13)
  • AGENTS.md
  • eslint.config.js
  • runners/extension/scripts/build-catalog.mjs
  • scripts/build-catalog.ts
  • scripts/lib/catalog-core.mjs
  • skills/agent-redteaming/opfor-run/SKILL.md
  • skills/agent-redteaming/opfor-run/report-schema.md
  • skills/agent-redteaming/opfor-setup/SKILL.md
  • skills/agent-redteaming/opfor-setup/catalog.json
  • skills/mcp-redteaming/opfor-run/SKILL.md
  • skills/mcp-redteaming/opfor-run/report-schema.md
  • skills/mcp-redteaming/opfor-setup/SKILL.md
  • skills/mcp-redteaming/opfor-setup/catalog.json

Comment thread scripts/build-catalog.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
scripts/tests/catalog-core.test.mjs (1)

157-160: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Guard cleanup against partial setup failures.

If mkdtemp fails for suitesDir during the before hook, suitesDir remains undefined. The after hook will then unconditionally pass undefined to rm(), throwing an ERR_INVALID_ARG_TYPE which masks the original test failure.

♻️ Proposed refactor
   after(async () => {
-    await rm(tmpRoot, { recursive: true, force: true });
-    await rm(suitesDir, { recursive: true, force: true });
+    if (tmpRoot) await rm(tmpRoot, { recursive: true, force: true });
+    if (suitesDir) await rm(suitesDir, { recursive: true, force: true });
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/tests/catalog-core.test.mjs` around lines 157 - 160, Guard the
suitesDir cleanup in the after hook so rm() is called only when mkdtemp
successfully initialized suitesDir. Keep cleanup of tmpRoot unchanged and ensure
partial setup failures do not trigger a secondary ERR_INVALID_ARG_TYPE that
masks the original failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@scripts/tests/catalog-core.test.mjs`:
- Around line 157-160: Guard the suitesDir cleanup in the after hook so rm() is
called only when mkdtemp successfully initialized suitesDir. Keep cleanup of
tmpRoot unchanged and ensure partial setup failures do not trigger a secondary
ERR_INVALID_ARG_TYPE that masks the original failure.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 12c5db2c-aeeb-40c9-8c4d-52a390005771

📥 Commits

Reviewing files that changed from the base of the PR and between 627ca53 and 6d2c24a.

📒 Files selected for processing (8)
  • .github/workflows/ci.yml
  • package.json
  • runners/extension/scripts/build-catalog.mjs
  • runners/extension/tests/build-catalog.test.mjs
  • scripts/build-catalog.ts
  • scripts/lib/catalog-core.mjs
  • scripts/tests/build-catalog.test.ts
  • scripts/tests/catalog-core.test.mjs
🚧 Files skipped from review as they are similar to previous changes (3)
  • scripts/build-catalog.ts
  • runners/extension/scripts/build-catalog.mjs
  • scripts/lib/catalog-core.mjs

@jithin23-kv
jithin23-kv merged commit 4908c16 into KeyValueSoftwareSystems:master Jul 22, 2026
8 checks passed
@jithin23-kv
jithin23-kv deleted the fix/unify-catalog-generation branch July 22, 2026 08:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants