update-codeql-query-dataflow-csharp

Upgrade C# CodeQL queries from legacy (v1) language-specific dataflow API to modern (v2) shared dataflow API while ensuring query result equivalence through test-driven development. Use this skill when modernizing C# dataflow queries to use the unified dataflow library.

16 stars

Best use case

update-codeql-query-dataflow-csharp is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Upgrade C# CodeQL queries from legacy (v1) language-specific dataflow API to modern (v2) shared dataflow API while ensuring query result equivalence through test-driven development. Use this skill when modernizing C# dataflow queries to use the unified dataflow library.

Teams using update-codeql-query-dataflow-csharp should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/update-codeql-query-dataflow-csharp/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/development/update-codeql-query-dataflow-csharp/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/update-codeql-query-dataflow-csharp/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How update-codeql-query-dataflow-csharp Compares

Feature / Agentupdate-codeql-query-dataflow-csharpStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Upgrade C# CodeQL queries from legacy (v1) language-specific dataflow API to modern (v2) shared dataflow API while ensuring query result equivalence through test-driven development. Use this skill when modernizing C# dataflow queries to use the unified dataflow library.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# Update CodeQL Query Dataflow for C#

This skill guides you through migrating C# CodeQL queries from the legacy v1 (language-specific) dataflow API to the modern v2 (shared) dataflow API while ensuring query result equivalence.

## When to Use This Skill

- Migrating legacy C# queries using `DataFlow::Configuration` to modern `DataFlow::ConfigSig`
- Updating queries to use the shared dataflow library introduced in 2023
- Modernizing C# queries that use deprecated dataflow patterns
- Ensuring migrated queries produce identical results as the original

## Critical Success Factor: Query Result Equivalence

The most important outcome is ensuring the migrated query produces **exactly the same results** as the original query. Result changes due to query migration alone can cause:

- **Alert flapping**: Issues appearing and disappearing without code changes
- **False confidence**: Developers may lose trust in CodeQL analysis
- **Deployment issues**: CI/CD pipelines may fail due to new/changed alerts

**Test-Driven Development (TDD) is mandatory** for dataflow migration to guarantee result equivalence.

## Overview: v1 vs v2 Dataflow API

### Legacy v1 API (Language-Specific)

- **Configuration**: Uses `DataFlow::Configuration` classes
- **Predicates**: `isSource()`, `isSink()`, `isSanitizer()`, `isAdditionalTaintStep()`
- **Library**: Language-specific dataflow library (e.g., `semmle.code.csharp.dataflow.DataFlow`)
- **Nodes**: Language-specific node types (e.g., `ExprNode`, `ParameterNode`)

### Modern v2 API (Shared)

- **Configuration**: Uses `DataFlow::ConfigSig` signature modules with `DataFlow::Global<ConfigSig>`
- **Predicates**: `isSource()`, `isSink()`, `isBarrier()`, `isAdditionalFlowStep()`
- **Library**: Shared dataflow library (e.g., `semmle.code.csharp.dataflow.DataFlow2`)
- **Nodes**: Unified `DataFlow::Node` type with consistent semantics

### Key Differences

| Aspect        | v1 API                                                        | v2 API                                                                                            |
| ------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| Configuration | `class Config extends DataFlow::Configuration`                | `module ConfigSig implements DataFlow::ConfigSig` + `module Config = DataFlow::Global<ConfigSig>` |
| Sanitizer     | `isSanitizer(DataFlow::Node node)`                            | `isBarrier(DataFlow::Node node)`                                                                  |
| Custom flow   | `isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2)` | `isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2)`                                      |
| Flow check    | `config.hasFlow(source, sink)`                                | `Config::flow(source, sink)`                                                                      |
| Flow path     | `config.hasFlowPath(source, sink)`                            | `Config::flowPath(source, sink)`                                                                  |

## Migration Workflow with TDD

### Phase 1: Establish Baseline (Pre-Migration)

#### Step 1: Understand Query and Capture Baseline

Review the existing v1 query: metadata (`@name`, `@kind`, `@id`), sources, sinks, barriers, and custom flow steps.

Run existing tests with `codeql_test_run` and **capture baseline results** - the migrated query must match these exactly:

```json
{
  "testPath": "<query-pack>/test/{QueryName}",
  "searchPath": ["<query-pack>"]
}
```

#### Step 2: Ensure Comprehensive Test Coverage

Add test cases for positive (vulnerable), negative (safe), and edge cases (sanitization, async/await, LINQ, properties). Update `.expected` file, then extract and run tests:

```json
{ "testPath": "<query-pack>/test/{QueryName}", "searchPath": ["<query-pack>"] }
```

#### Step 3: Create v2 Query Structure

Create new query file (or backup original and modify in place):

**Import v2 dataflow library**:

```ql
import csharp
import semmle.code.csharp.dataflow.TaintTracking
import semmle.code.csharp.security.dataflow.SqlInjectionQuery
```

**Define configuration signature**:

```ql
/**
 * Configuration for detecting [vulnerability description]
 */
module MyConfigSig implements DataFlow::ConfigSig {
  predicate isSource(DataFlow::Node source) {
    // Define sources - user-controllable input
    source instanceof RemoteFlowSource or
    exists(Parameter p |
      p.fromSource() and
      source.asParameter() = p
    )
  }

  predicate isSink(DataFlow::Node sink) {
    // Define sinks - dangerous operations
    exists(MethodCall call |
      call.getTarget().hasName("FromSqlRaw") and
      call.getAnArgument() = sink.asExpr()
    )
  }

  predicate isBarrier(DataFlow::Node node) {
    // Define barriers - sanitization/validation
    // Renamed from isSanitizer in v1
    node instanceof SanitizerGuard or
    exists(MethodCall sanitize |
      sanitize.getTarget().hasName(["Sanitize", "Validate", "Encode"]) and
      DataFlow::localFlow(sanitize, node)
    )
  }

  predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
    // Define custom flow steps
    // Renamed from isAdditionalTaintStep in v1
    // Example: flow through string formatting
    exists(MethodCall format |
      format.getTarget().hasName("Format") and
      format.getAnArgument() = node1.asExpr() and
      format = node2.asExpr()
    )
  }
}
```

**Instantiate global flow module**:

```ql
module MyConfig = TaintTracking::Global<MyConfigSig>;
```

**Update query select**:

```ql
from DataFlow::Node source, DataFlow::Node sink
where MyConfig::flow(source, sink)
select sink, "Dataflow from $@ to sink", source, "user input"
```

For path queries (`@kind path-problem`), use `PathNode` from the instantiated module:

```ql
import DataFlow::PathGraph

from MyConfig::PathNode source, MyConfig::PathNode sink
where MyConfig::flowPath(source, sink)
select sink.getNode(), source, sink, "Dataflow from $@ to sink", source.getNode(), "user input"
```

#### Step 4: Apply C#-Specific Migration Patterns

**RemoteFlowSource** (v2 pattern):

```ql
// v1 pattern
source.asExpr().(Parameter).fromSource()

// v2 pattern
source instanceof RemoteFlowSource
```

**Barrier Guards** (renamed from sanitizers):

```ql
// v1 pattern
predicate isSanitizer(DataFlow::Node node) {
  // guard logic
}

// v2 pattern
predicate isBarrier(DataFlow::Node node) {
  // same guard logic
}
```

**Library Extensions** (C#-specific):

```ql
// For custom library dataflow in C#
import semmle.code.csharp.dataflow.LibraryTypeDataFlow

class MyLibraryFlow extends LibraryTypeDataFlow {
  override predicate callableFlow(
    CallableFlowSource source,
    CallableFlowSink sink,
    SourceDeclarationCallable c,
    boolean preservesValue
  ) {
    // Define flow through library methods
  }
}
```

**ASP.NET Patterns**:

```ql
// Web input sources
source.asExpr() instanceof WebInput or
exists(Parameter p |
  p.getAnAttribute().getType().hasName("FromBodyAttribute") and
  source.asParameter() = p
)

// Controller action sinks
exists(MethodCall redirect |
  redirect.getTarget().hasName(["Redirect", "RedirectToAction"]) and
  sink.asExpr() = redirect.getAnArgument()
)
```

#### Step 5: Compile and Test

Compile with `codeql_query_compile`, then run tests with `codeql_test_run` to validate result equivalence.

#### Step 6: Debug and Refine

If tests fail, analyze differences: missing sources (v2 `RemoteFlowSource` coverage), barrier semantics, flow steps, or node conversions. Use `codeql_query_run` with PrintAST for debugging. Iterate until tests pass.

#### Step 7: Finalize

Once tests pass: extract helper predicates, update QLDoc comments, format with `codeql_query_format`, install pack dependencies with `codeql_pack_install`, and run full test suite to ensure no regressions.

## C#-Specific Considerations

### ASP.NET Core Patterns

```ql
// Controller actions as sources
exists(Method m, Parameter p |
  m.getDeclaringType().getABaseType*().hasName("Controller") and
  p = m.getAParameter() and
  source.asParameter() = p
)
```

### Entity Framework Operations

```ql
// Database sinks
exists(MethodCall call |
  call.getTarget().hasName(["FromSqlRaw", "ExecuteSqlRaw", "ExecuteSqlCommand"]) and
  sink.asExpr() = call.getAnArgument()
)
```

### LINQ Expressions

```ql
// Flow through LINQ
exists(LambdaExpr lambda |
  node1.asExpr() = lambda.getAParameter() and
  node2.asExpr() = lambda.getExpressionBody()
)
```

### Async/Await Patterns

```ql
// Async method flow
exists(AwaitExpr await |
  node1.asExpr() = await.getExpr() and
  DataFlow::localFlow(await, node2)
)
```

## MCP Tools Reference

- **`codeql_test_extract`**: Extract test databases from C# code
- **`codeql_test_run`**: Run query tests and validate result equivalence
- **`codeql_query_compile`**: Compile queries and check for v2 API syntax errors
- **`codeql_query_format`**: Format migrated query code
- **`codeql_query_run`**: Run PrintAST for debugging AST structure
- **`codeql_pack_install`**: Install pack dependencies
- **`codeql_bqrs_decode`**: Decode query results for analysis

## Common Migration Pitfalls

❌ **Don't:**

- Migrate without establishing comprehensive baseline tests
- Accept test differences without understanding root cause
- Skip testing edge cases (async, LINQ, properties)
- Ignore custom flow steps that may need adjustment
- Assume v1 and v2 semantics are identical
- Forget to update query metadata and documentation

✅ **Do:**

- Create extensive test coverage before migration
- Verify exact result equivalence after migration
- Test all C# language features (async, LINQ, properties, etc.)
- Review official migration guides and documentation
- Use TDD to catch regressions early
- Document migration decisions in code comments
- Format code consistently with `codeql_query_format`

## Quality Checklist

Before considering migration complete:

- [ ] Baseline test results captured from original v1 query
- [ ] Comprehensive test coverage (positive, negative, edge cases)
- [ ] All v1 imports replaced with v2 imports
- [ ] `DataFlow::Configuration` replaced with `DataFlow::ConfigSig`
- [ ] `isSanitizer` renamed to `isBarrier`
- [ ] `isAdditionalTaintStep` renamed to `isAdditionalFlowStep`
- [ ] `hasFlow`/`hasFlowPath` replaced with `flow`/`flowPath`
- [ ] Query compiles without errors or warnings
- [ ] All tests pass with exact result match to baseline
- [ ] No regressions in other queries (full test suite passes)
- [ ] Query properly formatted with `codeql_query_format`
- [ ] QLDoc comments updated to reflect v2 API
- [ ] C#-specific patterns properly migrated
- [ ] Performance is acceptable (similar to v1 query)

## Official Documentation

For detailed v2 API information, consult:

- [New dataflow API for writing custom CodeQL queries](https://github.blog/changelog/2023-08-14-new-dataflow-api-for-writing-custom-codeql-queries/) - Official announcement and migration guide
- [Analyzing data flow in C#](https://codeql.github.com/docs/codeql-language-guides/analyzing-data-flow-in-csharp/) - C#-specific dataflow documentation

## Related Skills

- [Create CodeQL Query Unit Test for C#](../create-codeql-query-unit-test-csharp/SKILL.md) - For creating comprehensive tests
- [Test-Driven CodeQL Query Development](../create-codeql-query-tdd-generic/SKILL.md) - TDD methodology for queries

## Success Criteria

Your dataflow migration is successful when:

1. ✅ All tests pass with exact result equivalence to v1 baseline
2. ✅ Query uses v2 API consistently (`ConfigSig`, `isBarrier`, `isAdditionalFlowStep`)
3. ✅ No deprecated v1 patterns remain
4. ✅ All C#-specific patterns properly migrated
5. ✅ Query compiles without warnings
6. ✅ Full test suite passes (no regressions)
7. ✅ Code is clean, formatted, and well-documented
8. ✅ Performance is acceptable for production use

Related Skills

[Updated] Sweep Through Your Contacts with Speed and Skill

16
from diegosouzapw/awesome-omni-skill

This Article Describes [Updated] Sweep Through Your Contacts with Speed and Skill

tanstack-query

16
from diegosouzapw/awesome-omni-skill

TanStack Query (React Query) for asynchronous server-state management with automatic caching, background refetching, optimistic updates, and pagination in React applications.

rule-updater

16
from diegosouzapw/awesome-omni-skill

Skill for programmatically reading, updating, and creating Cursor rules based on patterns and lessons learned

readme-updates

16
from diegosouzapw/awesome-omni-skill

Maintain README files with setup instructions, features, tech stack, and usage examples. Use when updating project documentation, adding new features, improving onboarding, or creating READMEs for new packages.

Quick Query

16
from diegosouzapw/awesome-omni-skill

Execute simple network status queries that require 1-2 commands. Use when user asks to "check device status", "show interface", "query routing table", "display BGP neighbors", or needs simple read-only information retrieval.

querying-gemini

16
from diegosouzapw/awesome-omni-skill

Queries Gemini 3 Flash for high-speed code analysis, generation, and complex coding questions. Provides P0-P3 prioritized analysis reports, architecture audits, and code generation with configurable thinking levels (minimal/low/medium/high). 1M context, 64K output. Pro-level intelligence at Flash pricing.

query-expert

16
from diegosouzapw/awesome-omni-skill

Master SQL and database queries across multiple systems. Generate optimized queries, analyze performance, design indexes, and troubleshoot slow queries for PostgreSQL, MySQL, MongoDB, and more.

N+1 Query Detection

16
from diegosouzapw/awesome-omni-skill

Detect N+1 query patterns in GORM repository and service code — identify loops that execute queries, missing preloads, and unbounded fetches

moai-lang-csharp

16
from diegosouzapw/awesome-omni-skill

Enterprise C# 13 development with .NET 9, async/await, LINQ, Entity Framework Core, ASP.NET Core, and Context7 MCP integration for modern backend and enterprise applications.

googlebigquery-automation

16
from diegosouzapw/awesome-omni-skill

Automate Google BigQuery tasks via Rube MCP (Composio): run SQL queries, explore datasets and metadata, execute MBQL queries via Metabase integration. Always search tools first for current schemas.

dataflow

16
from diegosouzapw/awesome-omni-skill

Kailash DataFlow - zero-config database framework with automatic model-to-node generation. Use when asking about 'database operations', 'DataFlow', 'database models', 'CRUD operations', 'bulk operations', 'database queries', 'database migrations', 'multi-tenancy', 'multi-instance', 'database transactions', 'PostgreSQL', 'MySQL', 'SQLite', 'MongoDB', 'pgvector', 'vector search', 'document database', 'RAG', 'semantic search', 'existing database', 'database performance', 'database deployment', 'database testing', or 'TDD with databases'. DataFlow is NOT an ORM - it generates 11 workflow nodes per SQL model, 8 nodes for MongoDB, and 3 nodes for vector operations.

database-query

16
from diegosouzapw/awesome-omni-skill

Natural language database queries with multi-database support, query optimization, and visual results