domains / security / semgrep-rule-variant-creator / semgrep-rule-variant-creator

semgrep-rule-variant-creator

Skill card

combined

The trailofbits copy is the operational source: it defines the shipped workflow, the required arguments, the referencesDir resolution procedure, and the resume semantics. The sickn33 copy is a broader procedural guide that adds material the trailofbits copy does not contain: explicit When/When NOT to Use boundaries, an output directory layout, a table of rationalizations to reject, a strictness level, and a detailed four-phase workflow with applicability verdicts and test-first requirements. Because each copy has steps and constraints the other lacks, crowning one would hide a real alternative.

Repositories

RepositoryPath
trailofbits/skillsplugins/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/SKILL.md
sickn33/agentic-awesome-skillsplugins/agentic-awesome-skills-claude/skills/semgrep-rule-variant-creator/SKILL.md

Other copies

RoleRepositoryPath
peertrailofbits/skillsplugins/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/SKILL.md
peersickn33/agentic-awesome-skillsplugins/agentic-awesome-skills-claude/skills/semgrep-rule-variant-creator/SKILL.md
adaptersickn33/agentic-awesome-skillsplugins/agentic-awesome-skills/skills/semgrep-rule-variant-creator/SKILL.md
adaptersickn33/agentic-awesome-skillsskills/semgrep-rule-variant-creator/SKILL.md

Combined skill

---
name: semgrep-rule-variant-creator
description: Creates language variants of existing Semgrep rules. Use when porting a Semgrep rule to specified target languages. Takes an existing rule and target languages as input, produces independent rule+test directories for each language.
---

# Semgrep Rule Variant Creator

Port an existing Semgrep rule to other languages, one independent test-driven cycle per language.

## When to Use
- Porting an existing Semgrep rule to one or more target languages.
- Creating language-specific variants of a universal vulnerability pattern.
- Expanding rule coverage across a polyglot codebase.

## When NOT to Use
- Creating a new Semgrep rule from scratch; use `semgrep-rule-creator` instead.
- Running existing rules against code.
- Languages where the vulnerability pattern fundamentally does not apply.
- Minor syntax variations within the same language.

## Inputs
- Existing Semgrep rule: YAML file path or YAML rule content.
- Target languages: one or more languages to port to.
- Output directory: where the variant directories should land.

## Output
For each applicable target language, produce:
```
<original-rule-id>-<language>/
├── <original-rule-id>-<language>.yaml
└── <original-rule-id>-<language>.<ext>
```

## Workflow Invocation

The trailofbits implementation ships as a dynamic workflow:

```
/semgrep-rule-variant-creator:port-rule-to-languages
```

Pass the required arguments:

```json
{
  "rulePath": "<path to the rule being ported>",
  "languages": ["Go", "Java"],
  "referencesDir": "<absolute path to the references directory>",
  "outputDir": "<where the variant directories should land>"
}
```

`referencesDir` must be a resolved absolute path. Resolve it in order, first hit wins:

1. Claude Code: `ls -d -- "${CLAUDE_PLUGIN_ROOT}/skills/semgrep-rule-variant-creator/references"`
2. Codex: the same command with `${CODEX_PLUGIN_ROOT}`, if that variable is set instead.
3. Neither set: `find ~/.claude ~/.codex . -type d -path '*/semgrep-rule-variant-creator/skills/*/references' -print -quit 2>/dev/null`

Confirm the directory holds both reference files with `ls -1 -- "<that path>"`. Pass the path exactly as printed. If all three come back empty, stop and say so rather than assembling a path by hand.

The rule travels as a path, not as text: every phase reads the file.

## Four-Phase Cycle Per Language

For each target language, complete the full cycle before moving to the next language.

### Phase 1: Applicability Analysis
Determine if the pattern applies to the target language.

Analysis criteria:
1. Does the vulnerability class exist in the target language?
2. Does an equivalent construct exist?
3. Are the semantics similar enough for meaningful detection?

Verdict options:
- `APPLICABLE` → Proceed with variant creation.
- `APPLICABLE_WITH_ADAPTATION` → Proceed but significant changes needed.
- `NOT_APPLICABLE` → Skip this language, document why.

A `NOT_APPLICABLE` verdict goes to an independent refuter before the language is dropped.

### Phase 2: Test Creation (Test-First)
Always write tests before the rule.

Create a test file with target language idioms:
- Minimum 2 vulnerable cases (`ruleid:`).
- Minimum 2 safe cases (`ok:`).
- Include language-specific edge cases.

### Phase 3: Rule Creation
1. Analyze AST: `semgrep --dump-ast -l <lang> test-file`.
2. Translate patterns to target language syntax.
3. Update metadata: language key, message, rule ID.
4. Adapt for idioms: handle language-specific constructs.

### Phase 4: Validation
```bash
semgrep --validate --config rule.yaml
semgrep --test --config rule.yaml test-file
```

Output MUST show `All tests passed`. Failed validation is retried up to three times rather than trusting one agent to iterate until green.

## Strictness
- Applicability analysis is mandatory.
- Each language is independent; complete the full cycle before moving to the next.
- Test-first for each variant.
- 100% test pass required.

## Rationalizations to Reject
- "Pattern structure is identical" — different ASTs across languages; always dump AST for the target language.
- "Same vulnerability, same detection" — data flow differs between languages; analyze target language idioms.
- "Rule doesn't need tests since original worked" — language edge cases differ; write new test cases.
- "Skip applicability — it obviously applies" — some patterns are language-specific; complete applicability analysis first.
- "I'll create all variants then test" — errors compound; complete the full cycle per language.
- "Library equivalent is close enough" — surface similarity hides differences; verify API semantics match.
- "Just translate the syntax 1:1" — languages have different idioms; research target language patterns.

## Resume Semantics

If a run is interrupted while the session is still alive, relaunch it with:

```
Workflow({scriptPath: "…", resumeFromRunId: "<runId>", args: {…}})
```

Pass the same arguments again. Arguments are not saved with a run, so a resume that omits them fails the pre-flight check. With them, languages that finished replay from cache and only the unfinished ones re-run.

Resume is same-session only. A session limit ends the session, and runs are stored under that session's own directory, so the next session cannot reach them. A run id it cannot resolve is not an error — the workflow starts from scratch under that id and re-runs every language at full cost. Check the id is still there before counting on a resume:

```
ls -d ~/.claude/projects/*/*/subagents/workflows/*/
```

If you cannot confirm the id, or the session ended, re-invoke with the same arguments and point `outputDir` somewhere fresh. The script never deletes a directory, so a language that flipped to `NOT_APPLICABLE` on the second run leaves the first run's variant behind.

## Foundational Reference

The `semgrep-rule-creator` skill is the authoritative reference for Semgrep rule creation fundamentals. Consult it for:
- When to use taint mode vs pattern matching.
- Test-first methodology.
- Anti-patterns to avoid.
- Iterating until tests pass.
- Rule optimization.

When porting a rule, you are applying these same principles in a new language context. If uncertain about rule structure or approach, refer to `semgrep-rule-creator` first.