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.
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
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/update-codeql-query-dataflow-csharp/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How update-codeql-query-dataflow-csharp Compares
| Feature / Agent | update-codeql-query-dataflow-csharp | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/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 useRelated Skills
[Updated] Sweep Through Your Contacts with Speed and Skill
This Article Describes [Updated] Sweep Through Your Contacts with Speed and Skill
tanstack-query
TanStack Query (React Query) for asynchronous server-state management with automatic caching, background refetching, optimistic updates, and pagination in React applications.
rule-updater
Skill for programmatically reading, updating, and creating Cursor rules based on patterns and lessons learned
readme-updates
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
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
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
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
Detect N+1 query patterns in GORM repository and service code — identify loops that execute queries, missing preloads, and unbounded fetches
moai-lang-csharp
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
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
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
Natural language database queries with multi-database support, query optimization, and visual results