Skip to content

feat!: add C# structural support#69

Merged
boorad merged 6 commits intomainfrom
feat/csharp-support
May 5, 2026
Merged

feat!: add C# structural support#69
boorad merged 6 commits intomainfrom
feat/csharp-support

Conversation

@boorad
Copy link
Copy Markdown
Contributor

@boorad boorad commented May 5, 2026

Summary

Adds C# structural scanning for ASP.NET Core authorization patterns and wires C# into policy-import enforcement-point detection.

Changes

  • Adds tree-sitter C# parser support and .cs discovery.
  • Adds embedded C# rules for ASP.NET [Authorize], [AllowAnonymous], endpoint authorization, AuthorizeAsync, IsInRole, and HasClaim.
  • Adds shorthand [Authorize("PolicyName")] detection and fixes generated Rego for comma-separated roles and claim values.
  • Extends policy import/DI propagation to C# using aliases, constructor parameters, assignments, fields, and object initializers.
  • Updates docs and local/CI commands to run all-feature checks.

Testing

  • cargo check --all-features
  • cargo clippy --all-features -- -D warnings
  • cargo fmt --check
  • cargo test --all-features
  • cargo test
  • cargo run -- rules validate
  • cargo run -- rules test

Summary by CodeRabbit

  • New Features

    • Added C# support for ASP.NET Core authorization detection (11 new security rules covering Authorize attributes, roles, policies, claims, and endpoint protections).
    • Structural scanning extended to analyze C# dependency-injection and policy propagation.
  • Documentation

    • Docs and README updated to list C# support and include a C# corpus/report.
  • Chores

    • CI and contributor checks now run with full feature coverage and stricter linting/testing; added C# parsing dependency.

boorad added 3 commits May 5, 2026 11:26
Wire the C# tree-sitter grammar into structural scanning and add ASP.NET Core authorization rules for attributes, endpoint authorization, claims, roles, and IAuthorizationService checks.

Update language support docs so C# is listed as structurally supported.
@boorad boorad self-assigned this May 5, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8ba39fa5-b0f3-4757-9f5c-4d7168431ab0

📥 Commits

Reviewing files that changed from the base of the PR and between 813c355 and ad6c1f5.

📒 Files selected for processing (8)
  • README.md
  • docs/DESIGN.md
  • docs/corpus/README.md
  • docs/corpus/csharp.md
  • rules/csharp/aspnet-authorize-policy-shorthand.toml
  • rules/csharp/authorization-service-authorize-async.toml
  • src/rego/templates.rs
  • src/scanner/imports.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • rules/csharp/authorization-service-authorize-async.toml
  • README.md
  • docs/DESIGN.md
  • src/rego/templates.rs

📝 Walkthrough

Walkthrough

This PR adds C# structural language support and a set of ASP.NET Core authorization rules. It introduces the tree-sitter C# dependency, enables .cs detection and parsing, embeds multiple new TOML rule files (attributes, policies, roles, claims, endpoint/middleware patterns), extends import/propagation logic and matcher/template plumbing for C# semantics, and updates docs and developer tooling to run checks with --all-features.

Changes

C# Language Support & ASP.NET Core Authorization Rules

Layer / File(s) Summary
Build & Dependency Setup
Cargo.toml, .githooks/pre-commit, .github/PULL_REQUEST_TEMPLATE.md, CONTRIBUTING.md, AGENTS.md
Add tree-sitter-c-sharp = "0.23" and change developer/CI commands to run cargo clippy --all-features -- -D warnings and cargo test --all-features.
Documentation Updates
README.md, docs/DESIGN.md, docs/corpus/*, AGENTS.md, CONTRIBUTING.md, CONTRIBUTING.md, src/deep/*.rs
Mark C# as shipping (v0.2), move C# into the appropriate milestone/priority tables, add a new C# corpus doc, and update various README/agent/contributor instructions to reference --all-features.
Embedded Rules Registration
src/rules/embedded.rs
Register a new "C# / ASP.NET Core" block and reference the new TOML rule files for embedding.
Rule Definitions (Tree-sitter + Rego + Tests)
rules/csharp/*.toml (multiple files)
Add ten new TOML-backed rules: csharp-aspnet-allow-anonymous, csharp-aspnet-authorize-attribute, csharp-aspnet-authorize-policy, csharp-aspnet-authorize-policy-shorthand, csharp-aspnet-authorize-roles, csharp-aspnet-endpoint-allow-anonymous, csharp-aspnet-require-authorization, csharp-authorization-service-authorize-async, csharp-has-claim-call, csharp-is-in-role-call. Each contains Tree-sitter queries, predicates, Rego templates, and unit-style tests.
Scanner: File Discovery & Parsing
src/scanner/discovery.rs, src/scanner/parser.rs
Recognize .cs extension as Language::CSharp and map Language::CSharp to tree_sitter_c_sharp::LANGUAGE; add unit tests for C# detection and parsing.
Scanner: Import / Propagation Analysis
src/scanner/imports.rs
Extend find_policy_imports to handle C# using directives (including aliasing) and add visit_csharp_edge to extract propagation edges from variable/field declarators, constructor DI parameters, and assignment expressions; add corresponding unit tests.
Matcher & Rego Stub Generation
src/scanner/matcher.rs
Derive additional template variables (notably roles_set) from captures before rendering Rego stubs; add helpers add_template_derived_values and comma_separated_rego_set_items; add tests asserting Rego content for roles, claims, and policy shorthand.
Rego Template Rendering
src/rego/templates.rs
Adjust render_template to special-case roles_set so its value is inserted without stripping inner quotes; add unit tests validating preserved item quoting and default stripping for other *_set names.
Integration / Behavior Tests
tests/scanner_enforcement_points.rs, scanner unit tests
Add enforcement_points_increments_for_csharp_policy_di and multiple C#-focused unit tests validating import detection, propagation, parsing, and Rego output behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • EnforceAuth/zift#3: Parallel language-add PR that touches Cargo dependencies, parser/discovery wiring, and embedded rule registration patterns.
  • EnforceAuth/zift#9: Related work extending find_policy_imports for additional import patterns; conceptually similar to this PR's C# import binding detection.
  • EnforceAuth/zift#29: Another structural-language support PR that modifies parser/discovery and embedded rule wiring, sharing the same integration surface.

Poem

🐰
I hopped through code in springtime light,
Found C# files now parsed just right,
ASP.NET rules stitched in a row,
Roles and claims and policies grow —
Hooray, the scanner's ready to go!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat!: add C# structural support' clearly and concisely summarizes the main objective: adding structural scanning support for C#, which is the primary focus of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/csharp-support

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

Copy link
Copy Markdown

@amazon-q-developer amazon-q-developer Bot left a comment

Choose a reason for hiding this comment

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

This PR successfully adds comprehensive C# structural scanning support following established patterns from other languages. The implementation includes tree-sitter parser integration, policy import detection with DI propagation, and complete test coverage for ASP.NET Core authorization patterns.

The code quality is high with proper error handling, comprehensive test coverage for import detection, propagation logic, and edge cases. No blocking defects identified.


You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 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 `@docs/DESIGN.md`:
- Line 217: The C# entry ("| C# | ASP.NET Core `[Authorize]`, policy-based
authorization, `ClaimsPrincipal` checks |") is incorrectly placed in Priority 2
(v0.2); move that table row into the Priority 1 (v0.1) section (or alternatively
add an explicit inline note next to the C# row clarifying it is available now)
so documentation matches shipped support; update the table row under the v0.1
heading or add a parenthetical status note to the existing C# line accordingly.

In `@rules/csharp/aspnet-authorize-policy-shorthand.toml`:
- Around line 23-24: The current not_match only excludes explicit Roles/Policy
named args but still allows any string that follows a named argument (e.g.,
AuthenticationSchemes = "Bearer") to be treated as a shorthand; update the
predicate to also exclude any named-argument pattern by expanding not_match to
include a generic named-argument regex (for example add "\\b\\w+\\s*=" to the
alternation) so strings that are values of named args are ignored; apply the
same change to the other rule block referenced (lines 44-57) and keep references
to the existing rule.predicates.match and its not_match key when making the
edits.

In `@rules/csharp/authorization-service-authorize-async.toml`:
- Around line 18-19: The rule in rule.predicates.arguments currently only
matches string literals, Operations.* and capitalized identifiers; update the
match regex to also accept variable-backed identifiers used in real
IAuthorizationService calls (e.g. AuthorizeAsync(User, resource, policyName) and
AuthorizeAsync(User, resource, requirements)) by adding an alternative that
matches identifier names containing "policy" or "requirement" (case-insensitive)
and their plural forms; modify the match value (the match = "...") to include
something like an additional branch:
|(?i:[a-zA-Z_][a-zA-Z0-9_]*?(policy|requirement)s?) so variable names like
policyName or requirements are captured by the rule.

In `@src/rego/templates.rs`:
- Around line 14-16: The current branch uses key.ends_with("_set") to allow raw
interpolation (variables key, caps, strip_quotes), which is too broad; instead,
restrict to an explicit allowlist of derived keys (e.g., "roles_set") by
replacing the condition with a check against a static/const list or a matches!
pattern (for example allowed_keys.contains(key.as_str()) or
matches!(key.as_str(), "roles_set")). Update the match arm that returns
val.to_string() to only trigger for those explicit keys and keep the other arms
unchanged so unknown "_set" keys still go through strip_quotes or return the
placeholder.

In `@src/scanner/imports.rs`:
- Around line 464-473: The code currently calls node.utf8_text(source) and tests
that whole `using` directive text with is_policy_path, causing false positives;
instead locate the right-hand-side target node (the aliased type/path) from the
`using` node (e.g. via node.child_by_field_name for the target/path/value node
or by traversing children) and call utf8_text(source) on that target node, then
pass that target text to is_policy_path; only insert alias into policy_names
when the RHS text matches is_policy_path (keep existing references to
alias_node, alias, is_policy_path, and policy_names).
- Around line 477-494: The code is incorrectly treating plain namespace using
directives as bindings; change the logic so you only insert a policy binding
when the qualified name comes from an alias or a type reference declaration
rather than a bare using namespace. Concretely, when walking the node (the
variable named `target` returned from node.named_children), first detect the
surrounding construct (e.g. check node.kind() / parent node kind) and only call
policy_names.insert(binding) if the node represents an alias using (a
using-alias directive) or if the qualified name is used as a type in
declarations/parameters/fields (not a plain using directive); update the branch
that currently calls trailing_qualified_name_segment(target, source) and
policy_names.insert(binding) to require that the original node is an alias or a
type reference before inserting, leaving is_policy_path(full_text) as an early
filter.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 78a0586c-1462-4a7e-9cf8-fd3ecfe2e7d9

📥 Commits

Reviewing files that changed from the base of the PR and between ac1c281 and 813c355.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (26)
  • .githooks/pre-commit
  • .github/PULL_REQUEST_TEMPLATE.md
  • AGENTS.md
  • CONTRIBUTING.md
  • Cargo.toml
  • README.md
  • docs/DESIGN.md
  • rules/csharp/aspnet-allow-anonymous.toml
  • rules/csharp/aspnet-authorize-attribute.toml
  • rules/csharp/aspnet-authorize-policy-shorthand.toml
  • rules/csharp/aspnet-authorize-policy.toml
  • rules/csharp/aspnet-authorize-roles.toml
  • rules/csharp/aspnet-endpoint-allow-anonymous.toml
  • rules/csharp/aspnet-require-authorization.toml
  • rules/csharp/authorization-service-authorize-async.toml
  • rules/csharp/has-claim-call.toml
  • rules/csharp/is-in-role-call.toml
  • src/deep/candidate.rs
  • src/deep/context.rs
  • src/rego/templates.rs
  • src/rules/embedded.rs
  • src/scanner/discovery.rs
  • src/scanner/imports.rs
  • src/scanner/matcher.rs
  • src/scanner/parser.rs
  • tests/scanner_enforcement_points.rs

Comment thread docs/DESIGN.md
Comment thread rules/csharp/aspnet-authorize-policy-shorthand.toml Outdated
Comment thread rules/csharp/authorization-service-authorize-async.toml Outdated
Comment thread src/rego/templates.rs Outdated
Comment thread src/scanner/imports.rs
Comment thread src/scanner/imports.rs Outdated
@boorad boorad merged commit ba06ba7 into main May 5, 2026
2 checks passed
@boorad boorad deleted the feat/csharp-support branch May 5, 2026 20:18
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.

1 participant