From dd1a00e12b4ec4f9e72a685781cf4d87f3251858 Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Wed, 6 May 2026 11:39:47 -0400 Subject: [PATCH 1/2] feat: detect Cedar enforcement points Add externalized rule support and embedded detection rules for Cedar, AWS Verified Permissions, and Cedar Express middleware so scans count policy-engine call sites in externalization metrics. --- rules/csharp/aws-verified-permissions.toml | 38 ++++++++++++ rules/go/aws-verified-permissions.toml | 56 +++++++++++++++++ rules/go/cedar-eval.toml | 56 +++++++++++++++++ rules/java/aws-verified-permissions.toml | 51 +++++++++++++++ rules/java/cedar-eval.toml | 41 ++++++++++++ rules/python/aws-verified-permissions.toml | 41 ++++++++++++ .../typescript/aws-verified-permissions.toml | 42 +++++++++++++ .../typescript/cedar-express-middleware.toml | 36 +++++++++++ src/mcp/tools.rs | 1 + src/rules/embedded.rs | 32 ++++++++++ src/rules/mod.rs | 6 ++ src/scanner/imports.rs | 3 + src/scanner/mod.rs | 18 +++--- tests/scanner_enforcement_points.rs | 62 +++++++++++++++++++ 14 files changed, 475 insertions(+), 8 deletions(-) create mode 100644 rules/csharp/aws-verified-permissions.toml create mode 100644 rules/go/aws-verified-permissions.toml create mode 100644 rules/go/cedar-eval.toml create mode 100644 rules/java/aws-verified-permissions.toml create mode 100644 rules/java/cedar-eval.toml create mode 100644 rules/python/aws-verified-permissions.toml create mode 100644 rules/typescript/aws-verified-permissions.toml create mode 100644 rules/typescript/cedar-express-middleware.toml diff --git a/rules/csharp/aws-verified-permissions.toml b/rules/csharp/aws-verified-permissions.toml new file mode 100644 index 0000000..81b9131 --- /dev/null +++ b/rules/csharp/aws-verified-permissions.toml @@ -0,0 +1,38 @@ +[rule] +id = "csharp-aws-verified-permissions" +languages = ["csharp"] +category = "custom" +confidence = "high" +description = "AWS Verified Permissions authorization call in C#" +externalized = true +query = """ +(invocation_expression + function: (member_access_expression + expression: (_) @receiver + name: (identifier) @method_name) +) @match +""" + +[rule.predicates.method_name] +match = "^(IsAuthorizedAsync|IsAuthorizedWithTokenAsync)$" + +[rule.predicates.receiver] +match = "(?i)(verifiedpermissions|verified_permissions|avp|vp|client)" + +[[rule.tests]] +input = """ +var response = await client.IsAuthorizedAsync(request); +""" +expect_match = true + +[[rule.tests]] +input = """ +var response = await client.IsAuthorizedWithTokenAsync(request); +""" +expect_match = true + +[[rule.tests]] +input = """ +var response = await client.SendAsync(request); +""" +expect_match = false diff --git a/rules/go/aws-verified-permissions.toml b/rules/go/aws-verified-permissions.toml new file mode 100644 index 0000000..ee49d45 --- /dev/null +++ b/rules/go/aws-verified-permissions.toml @@ -0,0 +1,56 @@ +[rule] +id = "go-aws-verified-permissions" +languages = ["go"] +category = "custom" +confidence = "high" +description = "AWS Verified Permissions authorization call in Go" +externalized = true +query = """ +(call_expression + function: (selector_expression + operand: (_) @receiver + field: (field_identifier) @method_name) +) @match +""" + +[rule.predicates.method_name] +match = "^(IsAuthorized|IsAuthorizedWithToken)$" + +[rule.predicates.receiver] +match = "(?i)(verifiedpermissions|verified_permissions|avp|vp|client)" + +[[rule.tests]] +input = """ +package main + +import "github.com/aws/aws-sdk-go-v2/service/verifiedpermissions" + +func decide(client *verifiedpermissions.Client, ctx context.Context, input *verifiedpermissions.IsAuthorizedInput) { + out, err := client.IsAuthorized(ctx, input) + _ = out + _ = err +} +""" +expect_match = true + +[[rule.tests]] +input = """ +package main + +func decide(client *verifiedpermissions.Client, ctx context.Context, input *verifiedpermissions.IsAuthorizedWithTokenInput) { + out, err := client.IsAuthorizedWithToken(ctx, input) + _ = out + _ = err +} +""" +expect_match = true + +[[rule.tests]] +input = """ +package main + +func handle(client *http.Client, req *http.Request) { + client.Do(req) +} +""" +expect_match = false diff --git a/rules/go/cedar-eval.toml b/rules/go/cedar-eval.toml new file mode 100644 index 0000000..4ca76c8 --- /dev/null +++ b/rules/go/cedar-eval.toml @@ -0,0 +1,56 @@ +[rule] +id = "go-cedar-eval" +languages = ["go"] +category = "custom" +confidence = "high" +description = "Cedar policy evaluation in Go (cedar-go PolicySet/IsAuthorized calls)" +externalized = true +query = """ +(call_expression + function: (selector_expression + operand: (_) @receiver + field: (field_identifier) @method_name) +) @match +""" + +[rule.predicates.method_name] +match = "^(NewPolicySetFromBytes|IsAuthorized)$" + +[rule.predicates.receiver] +match = "(?i)(cedar|policyset|policy_set|ps|authorizer|authz)" + +[[rule.tests]] +input = """ +package main + +import "github.com/cedar-policy/cedar-go" + +func loadPolicySet(src []byte) { + ps, err := cedar.NewPolicySetFromBytes(src) + _ = ps + _ = err +} +""" +expect_match = true + +[[rule.tests]] +input = """ +package main + +func decide(ps *cedar.PolicySet, req cedar.Request) { + ok, diag := ps.IsAuthorized(req) + _ = ok + _ = diag +} +""" +expect_match = true + +[[rule.tests]] +input = """ +package main + +func handle(svc *Service) { + svc.Process(input) +} +""" +expect_match = false diff --git a/rules/java/aws-verified-permissions.toml b/rules/java/aws-verified-permissions.toml new file mode 100644 index 0000000..c6ac362 --- /dev/null +++ b/rules/java/aws-verified-permissions.toml @@ -0,0 +1,51 @@ +[rule] +id = "java-aws-verified-permissions" +languages = ["java"] +category = "custom" +confidence = "high" +description = "AWS Verified Permissions authorization call in Java" +externalized = true +query = """ +(method_invocation + object: (_) @receiver + name: (identifier) @method_name +) @match +""" + +[rule.predicates.method_name] +match = "^(isAuthorized|isAuthorizedWithToken)$" + +[rule.predicates.receiver] +match = "(?i)(verifiedpermissions|verified_permissions|avp|vp|client)" + +[[rule.tests]] +input = """ +import software.amazon.awssdk.services.verifiedpermissions.VerifiedPermissionsClient; + +class Handler { + void decide(VerifiedPermissionsClient client, IsAuthorizedRequest request) { + client.isAuthorized(request); + } +} +""" +expect_match = true + +[[rule.tests]] +input = """ +class Handler { + void decide(VerifiedPermissionsClient client, IsAuthorizedWithTokenRequest request) { + client.isAuthorizedWithToken(request); + } +} +""" +expect_match = true + +[[rule.tests]] +input = """ +class Handler { + void run(Service svc) { + svc.process(input); + } +} +""" +expect_match = false diff --git a/rules/java/cedar-eval.toml b/rules/java/cedar-eval.toml new file mode 100644 index 0000000..4ab819e --- /dev/null +++ b/rules/java/cedar-eval.toml @@ -0,0 +1,41 @@ +[rule] +id = "java-cedar-eval" +languages = ["java"] +category = "custom" +confidence = "high" +description = "Cedar policy evaluation in Java (AuthorizationEngine.isAuthorized)" +externalized = true +query = """ +(method_invocation + object: (_) @receiver + name: (identifier) @method_name +) @match +""" + +[rule.predicates.method_name] +eq = "isAuthorized" + +[rule.predicates.receiver] +match = "(?i)(authorizationengine|engine|authorizer|cedar|authz)" + +[[rule.tests]] +input = """ +import com.cedarpolicy.AuthorizationEngine; + +class Handler { + boolean decide(AuthorizationEngine engine, Request request) { + return engine.isAuthorized(request).isAllowed(); + } +} +""" +expect_match = true + +[[rule.tests]] +input = """ +class Handler { + void run(Service svc) { + svc.process(input); + } +} +""" +expect_match = false diff --git a/rules/python/aws-verified-permissions.toml b/rules/python/aws-verified-permissions.toml new file mode 100644 index 0000000..c212927 --- /dev/null +++ b/rules/python/aws-verified-permissions.toml @@ -0,0 +1,41 @@ +[rule] +id = "py-aws-verified-permissions" +languages = ["python"] +category = "custom" +confidence = "high" +description = "AWS Verified Permissions authorization call in Python" +externalized = true +query = """ +(call + function: (attribute + object: (_) @receiver + attribute: (identifier) @method_name) +) @match +""" + +[rule.predicates.method_name] +match = "^(is_authorized|is_authorized_with_token)$" + +[rule.predicates.receiver] +match = "(?i)(verifiedpermissions|verified_permissions|avp|vp|client)" + +[[rule.tests]] +input = """ +import boto3 + +client = boto3.client("verifiedpermissions") +client.is_authorized_with_token(**params) +""" +expect_match = true + +[[rule.tests]] +input = """ +client.is_authorized(policyStoreId=store_id) +""" +expect_match = true + +[[rule.tests]] +input = """ +cache.get("is_authorized") +""" +expect_match = false diff --git a/rules/typescript/aws-verified-permissions.toml b/rules/typescript/aws-verified-permissions.toml new file mode 100644 index 0000000..d603425 --- /dev/null +++ b/rules/typescript/aws-verified-permissions.toml @@ -0,0 +1,42 @@ +[rule] +id = "ts-aws-verified-permissions" +languages = ["typescript", "javascript"] +category = "custom" +confidence = "high" +description = "AWS Verified Permissions authorization call in JavaScript/TypeScript" +externalized = true +query = """ +(call_expression + function: (member_expression + object: (_) @receiver + property: (property_identifier) @method_name) +) @match +""" + +[rule.predicates.method_name] +match = "^(isAuthorized|isAuthorizedWithToken)$" + +[rule.predicates.receiver] +match = "(?i)(verifiedpermissions|verified_permissions|verifiedPermissionsClient|avp|vp|client)" + +[[rule.tests]] +input = """ +import { VerifiedPermissions } from "@aws-sdk/client-verifiedpermissions"; + +const verifiedpermissions = new VerifiedPermissions({}); +await verifiedpermissions.isAuthorizedWithToken(params); +""" +expect_match = true + +[[rule.tests]] +input = """ +const client = new VerifiedPermissionsClient({}); +await client.isAuthorized(params); +""" +expect_match = true + +[[rule.tests]] +input = """ +await user.isAuthorized(); +""" +expect_match = false diff --git a/rules/typescript/cedar-express-middleware.toml b/rules/typescript/cedar-express-middleware.toml new file mode 100644 index 0000000..716bc90 --- /dev/null +++ b/rules/typescript/cedar-express-middleware.toml @@ -0,0 +1,36 @@ +[rule] +id = "ts-cedar-express-middleware" +languages = ["typescript", "javascript"] +category = "middleware" +confidence = "high" +description = "Cedar Express authorization middleware registration" +externalized = true +query = """ +(call_expression + function: (member_expression + property: (property_identifier) @method_name) + arguments: (arguments + (call_expression + function: (identifier) @middleware_name)) +) @match +""" + +[rule.predicates.method_name] +eq = "use" + +[rule.predicates.middleware_name] +eq = "authorizationMiddleware" + +[[rule.tests]] +input = """ +import { authorizationMiddleware } from "@cedar-policy/authorization-for-expressjs"; + +app.use(authorizationMiddleware({ authorizer })); +""" +expect_match = true + +[[rule.tests]] +input = """ +app.use(cors()); +""" +expect_match = false diff --git a/src/mcp/tools.rs b/src/mcp/tools.rs index 46cdf48..eea8ab4 100644 --- a/src/mcp/tools.rs +++ b/src/mcp/tools.rs @@ -358,6 +358,7 @@ fn get_rule(ctx: &ServerContext, args: &Value) -> Result { "category": rule.category, "confidence": rule.confidence, "description": rule.description, + "externalized": rule.externalized, "query": rule.query_source, "predicates": predicates, "cross_predicates": cross_predicates, diff --git a/src/rules/embedded.rs b/src/rules/embedded.rs index b26ecc3..ef50d17 100644 --- a/src/rules/embedded.rs +++ b/src/rules/embedded.rs @@ -72,6 +72,14 @@ const EMBEDDED_RULES: &[(&str, &str)] = &[ "feature-gate-check", include_str!("../../rules/typescript/feature-gate-check.toml"), ), + ( + "ts-aws-verified-permissions", + include_str!("../../rules/typescript/aws-verified-permissions.toml"), + ), + ( + "ts-cedar-express-middleware", + include_str!("../../rules/typescript/cedar-express-middleware.toml"), + ), // -- Java -- ( "java-spring-preauthorize", @@ -157,6 +165,14 @@ const EMBEDDED_RULES: &[(&str, &str)] = &[ "java-custom-authz-call", include_str!("../../rules/java/custom-authz-call.toml"), ), + ( + "java-cedar-eval", + include_str!("../../rules/java/cedar-eval.toml"), + ), + ( + "java-aws-verified-permissions", + include_str!("../../rules/java/aws-verified-permissions.toml"), + ), // -- Python -- ( "py-django-permission-required", @@ -206,6 +222,10 @@ const EMBEDDED_RULES: &[(&str, &str)] = &[ "py-feature-gate-check", include_str!("../../rules/python/feature-gate-check.toml"), ), + ( + "py-aws-verified-permissions", + include_str!("../../rules/python/aws-verified-permissions.toml"), + ), // -- Go -- ( "go-has-role-call", @@ -243,6 +263,14 @@ const EMBEDDED_RULES: &[(&str, &str)] = &[ "go-opa-rego-eval", include_str!("../../rules/go/opa-rego-eval.toml"), ), + ( + "go-cedar-eval", + include_str!("../../rules/go/cedar-eval.toml"), + ), + ( + "go-aws-verified-permissions", + include_str!("../../rules/go/aws-verified-permissions.toml"), + ), ( "go-access-descriptor-builder", include_str!("../../rules/go/access-descriptor-builder.toml"), @@ -288,6 +316,10 @@ const EMBEDDED_RULES: &[(&str, &str)] = &[ "csharp-authorization-service-authorize-async", include_str!("../../rules/csharp/authorization-service-authorize-async.toml"), ), + ( + "csharp-aws-verified-permissions", + include_str!("../../rules/csharp/aws-verified-permissions.toml"), + ), ]; pub fn load_embedded_rules() -> Result> { diff --git a/src/rules/mod.rs b/src/rules/mod.rs index d10354c..45965bf 100644 --- a/src/rules/mod.rs +++ b/src/rules/mod.rs @@ -15,6 +15,7 @@ pub struct PatternRule { pub category: AuthCategory, pub confidence: Confidence, pub description: String, + pub externalized: bool, pub query_source: String, pub predicates: Vec<(String, Predicate)>, pub cross_predicates: Vec, @@ -100,6 +101,8 @@ struct RuleToml { category: AuthCategory, confidence: Confidence, description: String, + #[serde(default)] + externalized: bool, query: String, #[serde(default)] predicates: std::collections::HashMap, @@ -263,6 +266,7 @@ fn parse_rule(toml_str: &str, source: &str) -> Result { category: r.category, confidence: r.confidence, description: r.description, + externalized: r.externalized, query_source: r.query, predicates, cross_predicates, @@ -473,6 +477,7 @@ match = ".*" category: AuthCategory::Rbac, confidence: Confidence::High, description: "original".into(), + externalized: false, query_source: "".into(), predicates: vec![], cross_predicates: vec![], @@ -486,6 +491,7 @@ match = ".*" category: AuthCategory::Rbac, confidence: Confidence::Medium, description: "override".into(), + externalized: false, query_source: "".into(), predicates: vec![], cross_predicates: vec![], diff --git a/src/scanner/imports.rs b/src/scanner/imports.rs index 3b54aa5..b4412a6 100644 --- a/src/scanner/imports.rs +++ b/src/scanner/imports.rs @@ -10,6 +10,9 @@ const POLICY_INDICATORS: &[&str] = &[ "opa", "policy", "rego", + "cedar", + "verifiedpermissions", + "verified-permissions", "enforce", "open-policy-agent", ]; diff --git a/src/scanner/mod.rs b/src/scanner/mod.rs index f3accfc..7c55649 100644 --- a/src/scanner/mod.rs +++ b/src/scanner/mod.rs @@ -79,12 +79,12 @@ pub fn scan( // `enforce`, `open-policy-agent` — see `scanner::imports`). Those calls // are already routed through a policy engine, so we suppress the inline // finding and count them here instead — that's what feeds - // `summary.externalized_pct` in the JSON output. Import-statement - // detection is wired for TS/JS, Go, Python, and Java today; other - // languages (C#, Kotlin, Ruby, PHP) currently no-op the counter. Most - // open-source corpora we've tried also ship zero externalized policy, - // so a 0 here is usually correct rather than buggy. Pinned by - // `tests/scanner_enforcement_points.rs`. + // `summary.externalized_pct` in the JSON output. Some rules are + // explicitly marked `externalized = true` for known policy engines and + // managed services (OPA/Cedar/AWS Verified Permissions); those count + // directly because the matched API call is the external enforcement + // point. Import-statement detection remains the fallback for custom + // policy wrappers. Pinned by `tests/scanner_enforcement_points.rs`. let mut enforcement_points: usize = 0; let mut seen_enforcement: std::collections::HashSet<(std::path::PathBuf, usize)> = std::collections::HashSet::new(); @@ -131,11 +131,13 @@ pub fn scan( )?; // Separate enforcement points from inline auth findings - if policy_imports.is_empty() { + if policy_imports.is_empty() && !compiled.rule.externalized { all_findings.extend(findings); } else { for finding in findings { - if imports::is_enforcement_point(&finding.code_snippet, &policy_imports) { + if compiled.rule.externalized + || imports::is_enforcement_point(&finding.code_snippet, &policy_imports) + { let key = (finding.file.clone(), finding.line_start); if seen_enforcement.insert(key) { enforcement_points += 1; diff --git a/tests/scanner_enforcement_points.rs b/tests/scanner_enforcement_points.rs index 87b3b5b..5ec5750 100644 --- a/tests/scanner_enforcement_points.rs +++ b/tests/scanner_enforcement_points.rs @@ -335,3 +335,65 @@ public class OrderController { result.findings, ); } + +#[test] +fn externalized_rules_count_without_policy_import_shortcut() { + let cases = [ + ( + "handler.js", + r#" +async function decide(client, params) { + return client.isAuthorizedWithToken(params); +} +"#, + "ts-aws-verified-permissions", + ), + ( + "views.py", + r#" +def decide(client, params): + return client.is_authorized(**params) +"#, + "py-aws-verified-permissions", + ), + ( + "decide.go", + r#"package main + +func decide(ps *PolicySet, req Request) { + ok, diag := ps.IsAuthorized(req) + _, _ = ok, diag +} +"#, + "go-cedar-eval", + ), + ( + "Handler.cs", + r#" +public async Task Decide(Client client, Request request) { + var response = await client.IsAuthorizedAsync(request); + return response.Decision == Decision.Allow; +} +"#, + "csharp-aws-verified-permissions", + ), + ]; + + for (filename, contents, rule_id) in cases { + let result = scan_fixture(filename, contents); + assert_eq!( + result.enforcement_points, 1, + "expected {rule_id} in {filename} to count as an externalized enforcement point; \ + got {} (findings: {:?})", + result.enforcement_points, result.findings, + ); + assert!( + !result + .findings + .iter() + .any(|f| f.pattern_rule.as_deref() == Some(rule_id)), + "externalized rule {rule_id} leaked into embedded findings: {:?}", + result.findings, + ); + } +} From d206e0b9769accc7650e674072b87d5683a9ee41 Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Wed, 6 May 2026 12:03:33 -0400 Subject: [PATCH 2/2] fix: tighten externalized enforcement rules --- ...authorization-service-authorize-async.toml | 2 +- rules/csharp/aws-verified-permissions.toml | 12 +++++++--- rules/go/aws-verified-permissions.toml | 22 ++++++++++++++----- rules/go/cedar-eval.toml | 4 ++-- rules/java/aws-verified-permissions.toml | 20 ++++++++++++----- rules/python/aws-verified-permissions.toml | 14 ++++++++---- .../typescript/aws-verified-permissions.toml | 12 +++++++--- tests/scanner_enforcement_points.rs | 8 +++---- 8 files changed, 67 insertions(+), 27 deletions(-) diff --git a/rules/csharp/authorization-service-authorize-async.toml b/rules/csharp/authorization-service-authorize-async.toml index e0d513b..7d0d2f1 100644 --- a/rules/csharp/authorization-service-authorize-async.toml +++ b/rules/csharp/authorization-service-authorize-async.toml @@ -16,7 +16,7 @@ query = """ eq = "AuthorizeAsync" [rule.predicates.arguments] -match = "(Policy|Requirement|Operations\\.|\"[^\"]+\"|(?i:[A-Za-z_][A-Za-z0-9_]*?(policy|requirement)s?))" +match = "(Policy|Requirement|Operations\\.|\"[^\"]+\"|(?i:\\b[A-Za-z_]*(policy|requirement)[A-Za-z0-9_]*\\b))" [rule.rego_template] template = """ diff --git a/rules/csharp/aws-verified-permissions.toml b/rules/csharp/aws-verified-permissions.toml index 81b9131..67f6899 100644 --- a/rules/csharp/aws-verified-permissions.toml +++ b/rules/csharp/aws-verified-permissions.toml @@ -17,17 +17,17 @@ query = """ match = "^(IsAuthorizedAsync|IsAuthorizedWithTokenAsync)$" [rule.predicates.receiver] -match = "(?i)(verifiedpermissions|verified_permissions|avp|vp|client)" +match = "(?i)(verifiedpermissions|verified_permissions|avp|\\bvp\\b)" [[rule.tests]] input = """ -var response = await client.IsAuthorizedAsync(request); +var response = await avp.IsAuthorizedAsync(request); """ expect_match = true [[rule.tests]] input = """ -var response = await client.IsAuthorizedWithTokenAsync(request); +var response = await verifiedPermissions.IsAuthorizedWithTokenAsync(request); """ expect_match = true @@ -36,3 +36,9 @@ input = """ var response = await client.SendAsync(request); """ expect_match = false + +[[rule.tests]] +input = """ +var response = await client.IsAuthorizedAsync(request); +""" +expect_match = false diff --git a/rules/go/aws-verified-permissions.toml b/rules/go/aws-verified-permissions.toml index ee49d45..fb5109a 100644 --- a/rules/go/aws-verified-permissions.toml +++ b/rules/go/aws-verified-permissions.toml @@ -17,7 +17,7 @@ query = """ match = "^(IsAuthorized|IsAuthorizedWithToken)$" [rule.predicates.receiver] -match = "(?i)(verifiedpermissions|verified_permissions|avp|vp|client)" +match = "(?i)(verifiedpermissions|verified_permissions|avp|\\bvp\\b)" [[rule.tests]] input = """ @@ -25,8 +25,8 @@ package main import "github.com/aws/aws-sdk-go-v2/service/verifiedpermissions" -func decide(client *verifiedpermissions.Client, ctx context.Context, input *verifiedpermissions.IsAuthorizedInput) { - out, err := client.IsAuthorized(ctx, input) +func decide(avp *verifiedpermissions.Client, ctx context.Context, input *verifiedpermissions.IsAuthorizedInput) { + out, err := avp.IsAuthorized(ctx, input) _ = out _ = err } @@ -37,8 +37,8 @@ expect_match = true input = """ package main -func decide(client *verifiedpermissions.Client, ctx context.Context, input *verifiedpermissions.IsAuthorizedWithTokenInput) { - out, err := client.IsAuthorizedWithToken(ctx, input) +func decide(verifiedpermissions *verifiedpermissions.Client, ctx context.Context, input *verifiedpermissions.IsAuthorizedWithTokenInput) { + out, err := verifiedpermissions.IsAuthorizedWithToken(ctx, input) _ = out _ = err } @@ -54,3 +54,15 @@ func handle(client *http.Client, req *http.Request) { } """ expect_match = false + +[[rule.tests]] +input = """ +package main + +func decide(client *Authorizer, ctx context.Context, input Input) { + out, err := client.IsAuthorized(ctx, input) + _ = out + _ = err +} +""" +expect_match = false diff --git a/rules/go/cedar-eval.toml b/rules/go/cedar-eval.toml index 4ca76c8..e95cf47 100644 --- a/rules/go/cedar-eval.toml +++ b/rules/go/cedar-eval.toml @@ -14,7 +14,7 @@ query = """ """ [rule.predicates.method_name] -match = "^(NewPolicySetFromBytes|IsAuthorized)$" +eq = "IsAuthorized" [rule.predicates.receiver] match = "(?i)(cedar|policyset|policy_set|ps|authorizer|authz)" @@ -31,7 +31,7 @@ func loadPolicySet(src []byte) { _ = err } """ -expect_match = true +expect_match = false [[rule.tests]] input = """ diff --git a/rules/java/aws-verified-permissions.toml b/rules/java/aws-verified-permissions.toml index c6ac362..086a978 100644 --- a/rules/java/aws-verified-permissions.toml +++ b/rules/java/aws-verified-permissions.toml @@ -16,15 +16,15 @@ query = """ match = "^(isAuthorized|isAuthorizedWithToken)$" [rule.predicates.receiver] -match = "(?i)(verifiedpermissions|verified_permissions|avp|vp|client)" +match = "(?i)(verifiedpermissions|verified_permissions|avp|\\bvp\\b)" [[rule.tests]] input = """ import software.amazon.awssdk.services.verifiedpermissions.VerifiedPermissionsClient; class Handler { - void decide(VerifiedPermissionsClient client, IsAuthorizedRequest request) { - client.isAuthorized(request); + void decide(VerifiedPermissionsClient avp, IsAuthorizedRequest request) { + avp.isAuthorized(request); } } """ @@ -33,8 +33,8 @@ expect_match = true [[rule.tests]] input = """ class Handler { - void decide(VerifiedPermissionsClient client, IsAuthorizedWithTokenRequest request) { - client.isAuthorizedWithToken(request); + void decide(VerifiedPermissionsClient verifiedPermissions, IsAuthorizedWithTokenRequest request) { + verifiedPermissions.isAuthorizedWithToken(request); } } """ @@ -49,3 +49,13 @@ class Handler { } """ expect_match = false + +[[rule.tests]] +input = """ +class Handler { + void decide(Authorizer client, Request request) { + client.isAuthorized(request); + } +} +""" +expect_match = false diff --git a/rules/python/aws-verified-permissions.toml b/rules/python/aws-verified-permissions.toml index c212927..6d9f9d8 100644 --- a/rules/python/aws-verified-permissions.toml +++ b/rules/python/aws-verified-permissions.toml @@ -17,20 +17,20 @@ query = """ match = "^(is_authorized|is_authorized_with_token)$" [rule.predicates.receiver] -match = "(?i)(verifiedpermissions|verified_permissions|avp|vp|client)" +match = "(?i)(verifiedpermissions|verified_permissions|avp|\\bvp\\b)" [[rule.tests]] input = """ import boto3 -client = boto3.client("verifiedpermissions") -client.is_authorized_with_token(**params) +verifiedpermissions = boto3.client("verifiedpermissions") +verifiedpermissions.is_authorized_with_token(**params) """ expect_match = true [[rule.tests]] input = """ -client.is_authorized(policyStoreId=store_id) +avp.is_authorized(policyStoreId=store_id) """ expect_match = true @@ -39,3 +39,9 @@ input = """ cache.get("is_authorized") """ expect_match = false + +[[rule.tests]] +input = """ +client.is_authorized(policyStoreId=store_id) +""" +expect_match = false diff --git a/rules/typescript/aws-verified-permissions.toml b/rules/typescript/aws-verified-permissions.toml index d603425..d3a68d3 100644 --- a/rules/typescript/aws-verified-permissions.toml +++ b/rules/typescript/aws-verified-permissions.toml @@ -17,7 +17,7 @@ query = """ match = "^(isAuthorized|isAuthorizedWithToken)$" [rule.predicates.receiver] -match = "(?i)(verifiedpermissions|verified_permissions|verifiedPermissionsClient|avp|vp|client)" +match = "(?i)(verifiedpermissions|verified_permissions|verifiedPermissionsClient|avp|\\bvp\\b)" [[rule.tests]] input = """ @@ -30,8 +30,8 @@ expect_match = true [[rule.tests]] input = """ -const client = new VerifiedPermissionsClient({}); -await client.isAuthorized(params); +const verifiedPermissionsClient = new VerifiedPermissionsClient({}); +await verifiedPermissionsClient.isAuthorized(params); """ expect_match = true @@ -40,3 +40,9 @@ input = """ await user.isAuthorized(); """ expect_match = false + +[[rule.tests]] +input = """ +await client.isAuthorized(params); +""" +expect_match = false diff --git a/tests/scanner_enforcement_points.rs b/tests/scanner_enforcement_points.rs index 5ec5750..2eb5b0e 100644 --- a/tests/scanner_enforcement_points.rs +++ b/tests/scanner_enforcement_points.rs @@ -343,7 +343,7 @@ fn externalized_rules_count_without_policy_import_shortcut() { "handler.js", r#" async function decide(client, params) { - return client.isAuthorizedWithToken(params); + return avp.isAuthorizedWithToken(params); } "#, "ts-aws-verified-permissions", @@ -352,7 +352,7 @@ async function decide(client, params) { "views.py", r#" def decide(client, params): - return client.is_authorized(**params) + return avp.is_authorized(**params) "#, "py-aws-verified-permissions", ), @@ -370,8 +370,8 @@ func decide(ps *PolicySet, req Request) { ( "Handler.cs", r#" -public async Task Decide(Client client, Request request) { - var response = await client.IsAuthorizedAsync(request); +public async Task Decide(Client avp, Request request) { + var response = await avp.IsAuthorizedAsync(request); return response.Decision == Decision.Allow; } "#,