Skip to content

Feature/update ci cd and docs#51

Open
envrs wants to merge 15 commits intokhulnasoft:masterfrom
envrs:feature/update-ci-cd-and-docs
Open

Feature/update ci cd and docs#51
envrs wants to merge 15 commits intokhulnasoft:masterfrom
envrs:feature/update-ci-cd-and-docs

Conversation

@envrs
Copy link
Contributor

@envrs envrs commented Dec 3, 2025

PR Type

Enhancement, Bug fix, Tests, Documentation, Other


Description

  • Core Logic Enhancements: Enhanced ASL path parsing with wildcard support, added comprehensive IP CIDR validation functions (inCidr, inCidrIPv4, inCidrIPv6), and improved condition evaluation with new operators (LT, ISEMPTY)

  • Cloud Provider Integrations: Expanded AWS service map with 13 new services (ECR, Guard Duty, WorkSpaces, Transfer, AppFlow, Cognito, WAF, Glue, ConfigService, Firehose, SES, FSx, OpenSearch) and removed deprecated services (QLDB, Elastic Transcoder); expanded Azure services with Blob Service, Virtual Machines, Event Grid, Event Hubs

  • New Security Plugins: Added privilege analysis and network exposure plugins for AWS (EC2, EKS, Lambda), Azure (VM, Function Apps, AKS, Key Vault), and Google Cloud (Compute, Kubernetes, Cloud Functions)

  • Azure Authentication Modernization: Replaced deprecated ms-rest-azure with @azure/identity and request with axios for improved security and maintainability

  • Azure Terminology Updates: Comprehensive replacement of "Azure Active Directory (AAD)" with "Azure Entra ID" across multiple plugins and documentation

  • Plugin Enhancements:

    • S3 bucket tags check refactored to use direct bucket tagging API
    • EBS snapshots now support configurable age threshold
    • App Service and SCM site access restrictions enhanced with public network access checks
    • Private endpoints check extended to support Function Apps
  • SaaS Integration Support: Added metadata structure and _sendToSaaS method to collection output handler for external endpoint posting

  • CI/CD and Development: Updated GitHub Actions workflow with matrix testing for multiple Node.js versions, enhanced ESLint configuration with security rules, added comprehensive development documentation

  • Dependencies: Updated to latest versions with security improvements, added ESLint plugins, Prettier, and testing tools; updated Node.js engine requirement to >=16.0.0

  • Test Coverage: Added/updated tests for S3 bucket tagging, EBS snapshots, App Service restrictions, private endpoints, and webhook expiry with dynamic dates

  • Branding: Updated product name from CloudSploit to CloudExploit


Diagram Walkthrough

flowchart LR
  ASL["ASL Path Parsing<br/>& IP Validation"]
  AWS["AWS Service<br/>Expansion"]
  Azure["Azure Service<br/>Expansion"]
  Auth["Azure Auth<br/>Modernization"]
  Plugins["New Security<br/>Plugins"]
  Output["SaaS Integration<br/>Support"]
  CI["CI/CD & ESLint<br/>Enhancement"]
  Deps["Dependencies<br/>Update"]
  
  ASL -- "Enhanced logic" --> Plugins
  AWS -- "New services" --> Plugins
  Azure -- "New services" --> Plugins
  Auth -- "Modern libraries" --> Azure
  Plugins -- "Metadata & posting" --> Output
  CI -- "Matrix testing" --> Deps
  Deps -- "Security improvements" --> Output
Loading

File Walkthrough

Relevant files
Enhancement
11 files
asl-1.js
Enhanced path parsing, IP validation, and condition evaluation logic

helpers/asl/asl-1.js

  • Enhanced path splitting logic to properly handle wildcard [*] syntax
    as separate segments
  • Added new IP CIDR validation functions (inCidr, inCidrIPv4,
    inCidrIPv6, expandIPv6Simple) for IP range checking
  • Added transformToIpRange function to normalize IP addresses and CIDR
    notation
  • Refactored runValidation function to handle array results from
    wildcard paths and improved operator comparisons (added LT, ISEMPTY
    operators)
  • Added special handling for ResourceRecordSets[*].AliasTarget
    properties in runConditions
  • Improved compositeResult function with early exit logic and better
    default behavior handling
  • Simplified return values from parse function (removed array wrapping
    in most cases)
+904/-367
exports.js
New privilege analysis and network exposure plugins added

exports.js

  • Added new AWS plugin exports: ec2PrivilegeAnalysis,
    eksPrivilegeAnalysis, lambdaNetworkExposure, lambdaPrivilegeAnalysis
  • Added new Azure plugin exports: vmPrivilegeAnalysis,
    postgresqlServerPublicAccess, postgresqlFlexibleServerPublicAccess,
    functionPrivilegeAnalysis, functionAppNetworkExposure,
    aksPrivilegeAnalysis, keyVaultPublicAccess
  • Added new Google Cloud plugin exports: computePrivilegeAnalysis,
    kubernetesPrivilegeAnalysis, cloudFunctionNetworkExposure,
    cloudFunctionsPrivilegeAnalysis
  • Renamed Azure plugin directory from activedirectory to entraid for all
    related plugins
+26/-13 
output.js
Add SaaS integration support to collection output handler

postprocess/output.js

  • Refactored createCollection function to support SaaS integration
  • Added metadata structure with scan timestamp, ID, account ID, and
    cloud provider
  • Implemented _sendToSaaS method for posting data to external endpoints
  • Enhanced output formatting with summary information and resource
    tracking
+98/-6   
appServiceAccessRestriction.js
Enhance app service access restriction with public network check

plugins/azure/appservice/appServiceAccessRestriction.js

  • Updated more_info description to clarify public network access
    disabling
  • Added logic to check publicNetworkAccess property first before IP
    restrictions
  • Refactored condition checking to prioritize disabled public network
    access
  • Fixed typo: 'Khulnasoft' to 'KhulnaSoft'
+22/-13 
privateEndpointsEnabled.js
Extend private endpoints check to support function apps   

plugins/azure/appservice/privateEndpointsEnabled.js

  • Updated description and more_info to include Function Apps
  • Added getWebAppDetails to APIs list
  • Refactored logic to check privateEndpointConnections from detailed app
    data
  • Added differentiated messaging for Function Apps vs Web Apps
+34/-11 
s3BucketHasTags.js
Refactor S3 bucket tags check to use direct bucket tagging API

plugins/aws/s3/s3BucketHasTags.js

  • Changed API from ResourceGroupsTaggingAPI:getResources to
    S3:getBucketTagging
  • Refactored tag checking logic to query bucket-specific tags directly
  • Added fallback logic to check both bucket region and default region
  • Improved error handling for NoSuchTagSet errors
+34/-11 
ebsRecentSnapshots.js
Add configurable EBS snapshot age threshold setting           

plugins/aws/ec2/ebsRecentSnapshots.js

  • Added settings configuration object with ebs_recent_snapshot_days
    parameter
  • Updated description to reference configurable time period instead of
    hardcoded 7 days
  • Implemented dynamic threshold reading from settings with default
    fallback
  • Changed snapshot age comparison to use configurable threshold
+16/-5   
scmSiteAccessRestriction.js
Add public network access check to SCM site restrictions 

plugins/azure/appservice/scmSiteAccessRestriction.js

  • Added logic to check publicNetworkAccess property before IP
    restrictions
  • Refactored condition structure to prioritize disabled public network
    access
  • Maintained backward compatibility with IP-based restriction checking
+17/-9   
shared.js
Simplify integration processing and remove feature flag logic

helpers/shared.js

  • Removed identityServices array definition
  • Removed conditional logic checking for new inventory feature flag
  • Added cloud_account_identifier to local event object
  • Simplified integration processing logic
+2/-9     
collector.js
Enhance Azure throttling error detection with multiple patterns

collectors/azure/collector.js

  • Enhanced error filtering to handle multiple Azure throttling patterns
  • Added comprehensive list of throttling error patterns
    (case-insensitive)
  • Improved error message parsing to handle string and object error types
  • Added support for various throttling indicators like 'rate limit',
    'retry after'
+30/-1   
functionPrivilegeAnalysis.js
Add new Azure Function privilege analysis plugin                 

plugins/azure/appservice/functionPrivilegeAnalysis.js

  • New plugin file for analyzing Azure Function privileges
  • Implements basic structure with metadata and empty run function
  • Includes configuration for realtime triggers and API references
+24/-0   
Configuration changes
5 files
api.js
AWS service map expansion and deprecated service removal 

helpers/aws/api.js

  • Removed deprecated services: QLDB, Elastic Transcoder
  • Added new AWS services: ECR, Guard Duty, WorkSpaces, Transfer,
    AppFlow, Cognito, WAF, Glue, ConfigService, Firehose, SES, FSx,
    OpenSearch
  • Updated service map entries with proper bridge configurations and API
    call definitions
  • Added sendIntegration mappings for multiple services in postcalls
    section
  • Updated API call configurations and pagination settings for various
    services
+167/-65
api.js
Azure service expansion and API version updates                   

helpers/azure/api.js

  • Converted single service entries to arrays for CDN Profiles, Virtual
    Networks, Defender, Application Gateway, Entra ID
  • Added new Azure services: Blob Service, Virtual Machines, Event Grid,
    Event Hubs
  • Updated API versions for Key Vault and MySQL Flexible Server endpoints
  • Added new postcall configurations for blob containers, web app
    details, event hub network rules, and firewall rules
  • Added sendIntegration mappings for newly added services
+159/-19
api_multipart.js
Remove deprecated ElasticTranscoder and QLDB service configurations

helpers/aws/api_multipart.js

  • Removed ElasticTranscoder service configuration (listPipelines and
    listJobsByPipeline)
  • Removed QLDB service configuration (listLedgers and describeLedger)
  • Fixed comment typo: 'experimentally' instead of 'experimental'
+2/-32   
.eslintrc.json
Enhance ESLint configuration with security and formatting rules

.eslintrc.json

  • Expanded ESLint configuration with Babel parser and multiple plugin
    extensions
  • Added security, JSDoc, and Prettier plugin configurations
  • Updated parser options to ES2021 with module support
  • Added comprehensive rule set for code quality and security
  • Added overrides for test files with relaxed rules
+107/-62
scans_ci.yml
Modernize CI/CD pipeline with matrix testing and updated actions

.github/workflows/scans_ci.yml

  • Updated workflow name and trigger conditions (push, pull_request,
    schedule)
  • Added matrix strategy for testing on multiple Node.js versions (12.x,
    14.x, 16.x)
  • Replaced codespell with Khulnasoft codetypo-actions
  • Updated action versions and added npm caching
  • Reorganized steps with better naming and added build verification
+31/-12 
Dependencies
2 files
auth.js
Azure authentication library modernization and HTTP client upgrade

helpers/azure/auth.js

  • Replaced deprecated ms-rest-azure library with @azure/identity for
    authentication
  • Replaced request library with axios for HTTP requests
  • Refactored token acquisition to use ClientSecretCredential and
    explicit scope-based token retrieval
  • Updated error handling to work with axios response structure
  • Improved environment configuration for both commercial and government
    cloud deployments
+180/-98
package.json
Update dependencies, scripts, and project configuration   

package.json

  • Updated version from '2.0.1' to '2.1.0'
  • Added "type": "module" and Node.js engine requirement (>=16.0.0)
  • Reorganized and expanded npm scripts with new test coverage and
    linting commands
  • Updated all dependencies to latest versions with security improvements
  • Added comprehensive devDependencies including ESLint plugins,
    Prettier, and testing tools
  • Added lint-staged and Prettier configuration for code formatting
+80/-30 
Bug fix
1 files
kmsDefaultKeyUsage.js
Removed deprecated Elastic Transcoder service references 

plugins/aws/kms/kmsDefaultKeyUsage.js

  • Removed ElasticTranscoder:listPipelines from APIs list (deprecated
    service)
  • Removed Elastic Transcoder related triggers from realtime_triggers
    array
+2/-24   
Miscellaneous
2 files
index.js
Updated product branding name                                                       

index.js

  • Updated branding from CloudSploit to CloudExploit in console output
+1/-1     
cosmosdbManagedIdentity.spec.js
Replace test file with Cosmos DB managed identity plugin
implementation

plugins/azure/cosmosdb/cosmosdbManagedIdentity.spec.js

  • Replaced test file structure with actual plugin implementation code
  • Removed 137 lines of test cases and mock data
  • Added 56 lines of plugin logic for checking managed identity on Cosmos
    DB accounts
  • Changed from test-driven approach to plugin module export
+50/-131
Tests
11 files
s3BucketHasTags.spec.js
Update S3 bucket tags test to use direct bucket tagging API

plugins/aws/s3/s3BucketHasTags.spec.js

  • Updated createCache function parameters from rgData/rgDataErr to
    bucketTaggingData/bucketTaggingErr
  • Changed cache structure to use getBucketTagging API instead of
    resourcegroupstaggingapi
  • Updated test case for error handling to use direct bucket tagging
    errors
  • Added new test case for empty tag sets
+75/-25 
privateEndpointsEnabled.spec.js
Expand private endpoints test coverage for function apps 

plugins/azure/appservice/privateEndpointsEnabled.spec.js

  • Enhanced test data with privateEndpointConnections array structure
  • Added support for both web apps and function apps in test cases
  • Updated createCache to include getWebAppDetails API call structure
  • Added four new test cases covering function app scenarios
+74/-10 
appServiceAccessRestriction.spec.js
Add public network access tests for app service restrictions

plugins/azure/appservice/appServiceAccessRestriction.spec.js

  • Added publicNetworkAccess property to test configurations
  • Added new test configuration with disabled public network access
  • Added new test configuration with specific IP restrictions
  • Added two new test cases for public network access disabled and
    IP-specific restrictions
+42/-2   
ebsRecentSnapshots.spec.js
Add configurable snapshot age threshold tests                       

plugins/aws/ec2/ebsRecentSnapshots.spec.js

  • Added new snapshot test data with 15-day age
  • Added three new test cases for custom snapshot age thresholds
  • Tests cover custom threshold passing, failing, and default 7-day
    behavior
+50/-0   
automatedBackupsEnabled.spec.js
Update backup configuration test messages and formatting 

plugins/azure/appservice/automatedBackupsEnabled.spec.js

  • Fixed indentation in backupSchedule object
  • Updated test messages to include 'Custom' prefix for backup
    configuration
  • Changed two test case assertions to match updated message text
+9/-9     
scmSiteAccessRestriction.spec.js
Add public network access disabled tests for SCM site restrictions

plugins/azure/appservice/scmSiteAccessRestriction.spec.js

  • Added two new test configurations with disabled public network access
  • Added two new test cases for public network access disabled scenarios
  • Tests verify passing results when public access is disabled
+40/-0   
bucketSecureTransportEnabled.spec.js
Update test bucket name in secure transport policy             

plugins/aws/s3/bucketSecureTransportEnabled.spec.js

  • Updated S3 bucket name in test policy from 'alqemy-upwork' to
    'cloudexploit-test-secure-transport'
+1/-1     
webAppsADEnabled.spec.js
Update web apps authentication test descriptions to Entra ID

plugins/azure/appservice/webAppsADEnabled.spec.js

  • Updated test descriptions to reference 'Azure Entra ID' instead of
    'Azure Active Directory'
  • Updated test assertions to match new Entra ID message text
+5/-5     
batchAccountsAADEnabled.spec.js
Update batch accounts authentication test descriptions to Entra ID

plugins/azure/batchAccounts/batchAccountsAADEnabled.spec.js

  • Updated test descriptions to reference 'Entra ID Authentication'
    instead of 'AAD Authentication'
  • Updated test assertions to match new Entra ID message text
+4/-4     
automationAcctExpiredWebhooks.spec.js
Update webhook expiry test data to use dynamic dates         

plugins/azure/automationAccounts/automationAcctExpiredWebhooks.spec.js

  • Updated webhook test data to use dynamic expiry time (1 year from now)
  • Added comment explaining the dynamic date calculation
+2/-1     
eksKubernetesVersion.spec.js
Update EKS Kubernetes version test data                                   

plugins/aws/eks/eksKubernetesVersion.spec.js

  • Updated Kubernetes version test data from '1.29' to '1.30'
+1/-1     
Documentation
12 files
webAppsADEnabled.js
Update web apps authentication to use Entra ID terminology

plugins/azure/appservice/webAppsADEnabled.js

  • Updated title from 'Web Apps Active Directory Enabled' to 'Web Apps
    Entra ID Enabled'
  • Replaced all 'Azure Active Directory' references with 'Azure Entra ID'
  • Updated description and more_info to use Entra ID terminology
  • Updated result messages to reference Entra ID instead of AAD
+7/-7     
batchAccountsAADEnabled.js
Update batch accounts authentication to use Entra ID terminology

plugins/azure/batchAccounts/batchAccountsAADEnabled.js

  • Updated title from 'Batch Account AAD Auth Enabled' to 'Batch Account
    Entra ID Auth Enabled'
  • Replaced 'Azure Active Directory (AAD)' with 'Azure Entra ID'
    throughout
  • Updated result messages to use Entra ID terminology
  • Updated recommended action to reference Entra ID
+6/-6     
appConfigAccessKeyAuthDisabled.js
Update app configuration to use Entra ID terminology         

plugins/azure/appConfigurations/appConfigAccessKeyAuthDisabled.js

  • Updated more_info to replace 'Azure Active Directory (Azure AD)' with
    'Azure Entra ID'
+2/-2     
automationAcctManagedIdentity.js
Update automation account managed identity to use Entra ID terminology

plugins/azure/automationAccounts/automationAcctManagedIdentity.js

  • Updated more_info to replace 'Azure Active Directory (Azure AD)' with
    'Azure Entra ID'
+2/-3     
apiInstanceManagedIdentity.js
Update API management instance to use Entra ID terminology

plugins/azure/apiManagement/apiInstanceManagedIdentity.js

  • Updated more_info to replace 'Azure Active Directory (Azure AD)' with
    'Azure Entra ID'
+2/-2     
authEnabled.js
Update app service authentication to use Entra ID terminology

plugins/azure/appservice/authEnabled.js

  • Updated more_info to replace 'Azure Active Directory' with 'Azure
    Entra ID'
+2/-2     
appConfigManagedIdentity.js
Update app configuration managed identity to use Entra ID terminology

plugins/azure/appConfigurations/appConfigManagedIdentity.js

  • Updated more_info to replace 'Azure Active Directory (Azure AD)' with
    'Azure Entra ID'
+2/-2     
acrManagedIdentityEnabled.js
Update container registry managed identity to use Entra ID terminology

plugins/azure/containerregistry/acrManagedIdentityEnabled.js

  • Updated more_info to replace 'Azure Active Directory (Azure AD)' with
    'Azure Entra ID'
+2/-2     
cosmosdbLocalAuth.js
Update Cosmos DB local auth to use Entra ID terminology   

plugins/azure/cosmosdb/cosmosdbLocalAuth.js

  • Updated more_info to replace 'Azure Active Directory (Azure AD)' with
    'Azure Entra ID'
+1/-1     
batchAccountsManagedIdentity.js
Update batch accounts managed identity to use Entra ID terminology

plugins/azure/batchAccounts/batchAccountsManagedIdentity.js

  • Updated more_info to replace 'Azure Active Directory (Azure AD)' with
    'Azure Entra ID'
  • Fixed spacing issue in the text
+1/-1     
containerAppManagedIdentity.js
Update container app managed identity to use Entra ID terminology

plugins/azure/containerapps/containerAppManagedIdentity.js

  • Updated more_info to replace 'Azure Active Directory (Azure AD)' with
    'Azure Entra ID'
+1/-1     
README.md
Add development, testing, and CI/CD documentation               

README.md

  • Added comprehensive development and testing section
  • Documented test running, coverage, and linting commands
  • Added CI/CD workflow documentation
  • Added pull request requirements and guidelines
  • Improved code block formatting with bash syntax highlighting
+55/-1   
Additional files
2 files
.env.example +27/-0   
.prettierrc +11/-0   

Summary by CodeRabbit

Release Notes

  • New Features

    • Added privilege analysis checks for EC2, EKS, Lambda, Azure VMs, Functions, AKS, Google Compute, and Kubernetes services
    • Added network exposure detection for Lambda and Google Cloud Functions
    • Added public access checks for Azure Key Vault and PostgreSQL servers
    • Introduced configurable EBS snapshot retention threshold for custom assessment periods
    • Extended AWS service coverage with ECR, GuardDuty, WorkSpaces, Transfer, AppFlow, Cognito, WAF, Glue, Config Service, Firehose, FSx, and OpenSearch
    • Enhanced IP validation with CIDR and IPv6 support
  • Bug Fixes

    • Improved Azure error detection and handling for throttling scenarios
    • Enhanced App Service access restriction analysis with public network settings
    • Better S3 bucket tagging detection accuracy
  • Chores

    • Rebranded to CloudExploit
    • Updated Azure terminology across security checks
    • Removed deprecated AWS services

NeoPilot added 2 commits December 3, 2025 21:45
- Update Azure and AWS security settings
- Modify managed identity configurations
- Update test cases for security features
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Sorry @envrs, your pull request is larger than the review limit of 150000 diff characters

@coderabbitai
Copy link

coderabbitai bot commented Dec 3, 2025

Warning

Rate limit exceeded

@khulnasoft-bot has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 15 minutes and 17 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Walkthrough

This PR introduces multiple enhancements and refactoring across the codebase: removes ESLint configuration, upgrades CI/CD workflows with newer action versions and additional checks, expands AWS/Azure/Google service coverage with new privilege analysis and network exposure plugins, refactors authentication and validation helpers with modern SDK patterns, systematically replaces "Azure AD" terminology with "Azure Entra ID", rebrands the tool from "CloudSploit" to "CloudExploit", and introduces SaaS-based output delivery alongside structured scan data formatting.

Changes

Cohort / File(s) Summary
Configuration & CI/CD
.eslintrc.json, .github/workflows/scans_ci.yml
Removed ESLint config file; upgraded GitHub Actions to v6, added npm ci, codetypo check, and explicit lint/test/build steps.
Core Export Registry
exports.js
Added 15 new privilege analysis and network exposure plugins across AWS (EC2, EKS, Lambda), Azure (VMs, Functions, AKS, Key Vault, PostgreSQL), and Google Cloud (Compute, Kubernetes, Functions). Updated Azure AD references to Entra ID equivalents.
AWS Service Infrastructure
helpers/aws/api.js, helpers/aws/api_multipart.js
Added 12 new public services (ECR, GuardDuty, WorkSpaces, Transfer, AppFlow, Cognito, WAF, Glue, ConfigService, Firehose, FSx, OpenSearch variants). Removed QLDB and Elastic Transcoder. Updated postcall mappings and rate-limit comments.
Azure Infrastructure Refactoring
helpers/azure/api.js
Converted singular service mappings to arrays for multi-entry support (CDN Profiles, Virtual Networks, Blob Service, VMs, Event Grid, Event Hubs, Defender, Application Gateway, Entra ID). Updated API version endpoints and array-indexed sendIntegration references.
Azure Authentication Modernization
helpers/azure/auth.js
Replaced ms-rest-azure with @azure/identity ClientSecretCredential. Refactored token fetching for GovCloud/public Azure via getToken helper. Rewrote HTTP calls using axios with improved error parsing and handling.
ASL Validation Engine
helpers/asl/asl-1.js
Added IPRANGE transformation with IPv4/IPv6 CIDR support (inCidr, inCidrIPv4, inCidrIPv6, expandIPv6Simple). Enhanced wildcard array traversal ([\*]), AliasTarget nested resolution, and per-item EACH evaluation. Expanded compositeResult aggregation logic.
Shared Infrastructure
helpers/shared.js
Removed identity-service gating logic for new_inventory_enabled. Added cloud_account_identifier assignment from settings.
Branding Update
index.js
Updated ASCII banner from "CloudSploit" to "CloudExploit".
Azure Terminology Updates
plugins/azure/apiManagement/apiInstanceManagedIdentity.js, plugins/azure/appConfigurations/*, plugins/azure/appservice/authEnabled.js, plugins/azure/appservice/webAppsADEnabled.js, plugins/azure/automationAccounts/automationAcctManagedIdentity.js, plugins/azure/batchAccounts/batchAccountsAADEnabled.js, plugins/azure/batchAccounts/batchAccountsManagedIdentity.js, plugins/azure/containerapps/containerAppManagedIdentity.js, plugins/azure/containerregistry/acrManagedIdentityEnabled.js, plugins/azure/cosmosdb/cosmosdbLocalAuth.js
Systematically replaced "Azure Active Directory (AD)" with "Azure Entra ID" across plugin metadata and user-facing messages. No functional logic changes.
Azure App Service Enhancements
plugins/azure/appservice/appServiceAccessRestriction.js, plugins/azure/appservice/appServiceAccessRestriction.spec.js, plugins/azure/appservice/scmSiteAccessRestriction.js, plugins/azure/appservice/scmSiteAccessRestriction.spec.js
Added publicNetworkAccess disabled state detection. Refactored access restriction logic to check disabled status first, then fallback to IP-based Deny All rules. Extended test coverage.
Azure App Service Networking
plugins/azure/appservice/privateEndpointsEnabled.js, plugins/azure/appservice/privateEndpointsEnabled.spec.js
Added getWebAppDetails API call to fetch private endpoint connection details. Distinguished Function Apps from App Services in result messaging. Updated test scaffolding to support privateEndpointConnections per app.
Azure App Service Backup
plugins/azure/appservice/automatedBackupsEnabled.spec.js
Updated test assertion messages to prefix "Custom Backups" instead of "Backups".
New Azure Plugins
plugins/azure/appservice/functionPrivilegeAnalysis.js, plugins/azure/cosmosdb/cosmosdbManagedIdentity.spec.js
Added two new privilege analysis plugins with metadata and initialization scaffolding (functionPrivilegeAnalysis); replaced old test structure in cosmosdbManagedIdentity.spec.js with new plugin implementation.
AWS S3 Bucket Tagging Logic
plugins/aws/s3/s3BucketHasTags.js, plugins/aws/s3/s3BucketHasTags.spec.js
Replaced ResourceGroupsTaggingAPI with S3:getBucketTagging. Removed per-region bucket grouping; now fetches tagging per bucket in bucket's region with fallback. Updated test fixtures and error handling paths.
AWS S3 Secure Transport
plugins/aws/s3/bucketSecureTransportSpec.js
Updated test bucket policy from "alqemy-upwork" to "cloudexploit-test-secure-transport".
AWS EC2 EBS Snapshots
plugins/aws/ec2/ebsRecentSnapshots.js, plugins/aws/ec2/ebsRecentSnapshots.spec.js
Added configurable ebs_recent_snapshot_days setting (default 7). Updated plugin to use setting instead of hard-coded threshold. Added test cases for custom thresholds and default behavior.
AWS KMS Default Key Usage
plugins/aws/kms/kmsDefaultKeyUsage.js
Removed ElasticTranscoder API calls and realtime triggers from KMS plugin.
Output & SaaS Integration
postprocess/output.js
Restructured output format into scanData with metadata, resources, and summary sections. Added SaaS endpoint delivery via _sendToSaaS helper with HTTPS POST and Bearer token auth. Computes scan_duration and conditionally publishes results.

Sequence Diagrams

sequenceDiagram
    participant App as Application
    participant Output as Output Handler
    participant FileSystem as File System
    participant SaaS as SaaS Endpoint
    participant Logger as Logger

    App->>Output: write(collection)
    Output->>Output: Populate scanData.resources
    Output->>Output: Update scanData.summary

    App->>Output: close(error, settings)
    Output->>Output: Compute scan_duration
    Output->>FileSystem: Write scanData JSON
    FileSystem-->>Output: Written
    Output->>Logger: Log file location

    alt SaaS Endpoint Configured
        Output->>Output: Build HTTPS POST request
        Output->>SaaS: POST scanData (with Bearer token)
        alt Success (2xx Response)
            SaaS-->>Output: 200 OK
            Output->>Logger: Log successful delivery
        else Error
            SaaS-->>Output: Error/Non-2xx
            Output->>Logger: Log delivery failure
        end
    end
Loading
sequenceDiagram
    participant Validator as ASL Validator
    participant Transform as Transform Engine
    participant CIDR as CIDR Helper
    participant Result as Result Aggregator

    Validator->>Validator: Parse condition with runValidation
    
    alt Wildcard Path [*]
        Validator->>Validator: Iterate array items
        loop Each Item
            Validator->>Transform: Apply transformations
            alt IPRANGE Transformation
                Transform->>Transform: Normalize IP/CIDR
                Transform->>CIDR: Check IP in CIDR range
                CIDR-->>Transform: IPv4/IPv6 match result
            end
            Validator->>Validator: Evaluate per-item condition
            Validator->>Result: Collect item result
        end
    else AliasTarget Property
        Validator->>Validator: Resolve nested AliasTarget
        Validator->>Transform: Apply transformations
        Validator->>Validator: Evaluate condition
    else Standard Path
        Validator->>Transform: Apply transformations
        Validator->>Validator: Evaluate condition
    end
    
    Result->>Result: Aggregate per-item results
    Result-->>Validator: Composite result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

azure-entra-id-terminology-update, aws-service-expansion, helper-refactoring, new-plugins, saas-integration, authentication-modernization, ci-cd-improvements

Poem

🐰 CloudExploit hops along with newfound might,
Azure speaks Entra ID in the bright daylight,
AWS services expand with every bound,
While SaaS delivery spreads scans around,
A rabbit's refactor, thoroughly sound! 🌙

🚥 Pre-merge checks | ✅ 2 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'Feature/update ci cd and docs' is vague and non-descriptive; it lacks specificity about the main changes and uses generic terms that don't convey meaningful information about the primary changeset. Revise the title to be more specific about the main changes, such as 'Add privilege analysis plugins and enhance cloud provider coverage' or 'Refactor ASL path parsing and expand service integrations'. Current title is too generic to clearly convey primary intent.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into master

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@qodo-code-review
Copy link

qodo-code-review bot commented Dec 3, 2025

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Generic errors: Functions like inCidr, inCidrIPv4, and inCidrIPv6 return the ambiguous error string
'Malformed IP' for many distinct failure cases and sometimes coerce values with
Number() without validating NaN, leading to silent or unclear failures.

Referred Code
var inCidrIPv4 = function(ip, cidr) {
    var cidrMatch = cidr.match(/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/(\d{1,2})$/);
    if (!cidrMatch) {
        return { result: false, error: 'Malformed IP' };
    }

    var cidrIp = cidrMatch[1];
    var prefixLength = parseInt(cidrMatch[2]);

    var cidrParts = cidrIp.split('.').map(function(part) { return parseInt(part); });
    if (cidrParts.some(function(part) { return isNaN(part) || part < 0 || part > 255; }) || prefixLength < 0 || prefixLength > 32) {
        return { result: false, error: 'Malformed IP' };
    }

    var ipMatch = ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})(\/\d{1,2})?$/);
    if (!ipMatch) {
        return { result: false, error: 'Malformed IP' };
    }

    var ipParts = ipMatch.slice(1, 5).map(function(part) { return parseInt(part); });
    if (ipParts.some(function(part) { return isNaN(part) || part < 0 || part > 255; })) {


 ... (clipped 64 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing auditing: New validation, parsing, and IP/CIDR logic execute critical evaluations without any added
logging of actions, inputs, or outcomes, making it unclear whether critical decisions are
audit-trailed.

Referred Code
var inCidr = function(ip, cidr) {
    if (!ip || !cidr || typeof ip !== 'string' || typeof cidr !== 'string') {
        return { result: false, error: 'Malformed IP' };
    }

    ip = ip.trim();
    cidr = cidr.trim();

    var isIpv6Cidr = cidr.includes(':');
    var isIpv6Ip = ip.includes(':');

    if (isIpv6Cidr && !isIpv6Ip) {
        return { result: false, error: 'Cannot check IPv4 address against IPv6 CIDR' };
    }
    if (!isIpv6Cidr && isIpv6Ip) {
        return { result: false, error: 'Cannot check IPv6 address against IPv4 CIDR' };
    }

    if (isIpv6Cidr && isIpv6Ip) {
        return inCidrIPv6(ip, cidr);
    } else {


 ... (clipped 116 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status:
Abbreviated names: Identifiers like ip, cidr, obj, and generic result/message in broad scopes reduce clarity;
consider more descriptive names or comments for complex logic paths (e.g., AliasTarget
handling, wildcard parsing).

Referred Code
var inCidr = function(ip, cidr) {
    if (!ip || !cidr || typeof ip !== 'string' || typeof cidr !== 'string') {
        return { result: false, error: 'Malformed IP' };
    }

    ip = ip.trim();
    cidr = cidr.trim();

    var isIpv6Cidr = cidr.includes(':');
    var isIpv6Ip = ip.includes(':');

    if (isIpv6Cidr && !isIpv6Ip) {
        return { result: false, error: 'Cannot check IPv4 address against IPv6 CIDR' };
    }
    if (!isIpv6Cidr && isIpv6Ip) {
        return { result: false, error: 'Cannot check IPv6 address against IPv4 CIDR' };
    }

    if (isIpv6Cidr && isIpv6Ip) {
        return inCidrIPv6(ip, cidr);
    } else {


 ... (clipped 117 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
No structured logs: New evaluation and parsing paths add significant decision logic but introduce no
structured logging, which may hinder auditing and monitoring though it avoids leaking
sensitive data.

Referred Code
var compositeResult = function(inputResultsArr, resource, region, results, logical) {
    let failingResults = [];
    let passingResults = [];

    // No results to process, exit early
    if (!inputResultsArr || !inputResultsArr.length) {
        results.push({
            status: 2,
            resource: resource,
            message: 'No results to evaluate',
            region: region
        });
        return;
    }

    // If only one result, always use its status and message
    if (inputResultsArr.length === 1) {
        results.push({
            status: inputResultsArr[0].status,
            resource: resource,
            message: inputResultsArr[0].message,


 ... (clipped 493 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Regex risks: User-provided condition.value is passed directly to RegExp without try/catch or
sanitization in MATCHES/NOTMATCHES, which can throw on invalid patterns and lacks timeouts
to mitigate ReDoS risks.

Referred Code
if (condition.op === 'MATCHES' || condition.op === 'NOTMATCHES') {
    userRegex = new RegExp(condition.value);
}

// Handle arrays returned by parse function (from wildcard paths)
if (Array.isArray(condition.parsed)) {
    let anyMatch = false;
    let anyNotSet = false;
    let allNotSet = true;
    let arrayMessages = [];
    condition.parsed.forEach(function(item, index) {
        let itemMatch = false;
        if (item === 'not set') {
            arrayMessages.push(`Item ${index}: not set`);
            anyNotSet = true;
        } else {
            allNotSet = false;
        }
        if (condition.op && item !== 'not set') {
            if (condition.op == 'EQ') {
                itemMatch = (item == condition.value);


 ... (clipped 26 lines)

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

qodo-code-review bot commented Dec 3, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Avoid reinventing IP validation logic

The PR adds custom functions for IP and CIDR validation. It is recommended to
replace this custom logic with a well-tested, standard library like ip-address
or netmask to ensure correctness and simplify maintenance.

Examples:

helpers/asl/asl-1.js [77-213]
var inCidr = function(ip, cidr) {
    if (!ip || !cidr || typeof ip !== 'string' || typeof cidr !== 'string') {
        return { result: false, error: 'Malformed IP' };
    }
    
    ip = ip.trim();
    cidr = cidr.trim();
    
    var isIpv6Cidr = cidr.includes(':');
    var isIpv6Ip = ip.includes(':');

 ... (clipped 127 lines)

Solution Walkthrough:

Before:

// helpers/asl/asl-1.js

var inCidrIPv4 = function(ip, cidr) {
    // ... custom bitwise logic ...
    var cidrInt = ((cidrParts[0] << 24) + ...) >>> 0;
    var ipInt = ((ipParts[0] << 24) + ...) >>> 0;
    var mask = (0xFFFFFFFF << (32 - prefixLength)) >>> 0;
    // ... more logic ...
    return { result: isInRange, ... };
};

var inCidrIPv6 = function(ip, cidr) {
    // ... custom string manipulation and prefix matching ...
    var expandedCidr = expandIPv6Simple(cidrIp);
    var expandedIp = expandIPv6Simple(ip);
    // ... more logic ...
    return { result: isInRange, ... };
};

var runValidation = function(...) {
    // ...
    var cidrResult = inCidr(condition.value, item);
    // ...
}

After:

// helpers/asl/asl-1.js
// Add dependency: const { Netmask } = require('netmask');

var inCidr = function(ip, cidr) {
    try {
        const block = new Netmask(cidr);
        const isInRange = block.contains(ip);
        return { result: isInRange, error: null, message: isInRange ? 'IP in range' : 'IP not in range' };
    } catch (e) {
        return { result: false, error: 'Malformed IP or CIDR' };
    }
};

// Remove inCidrIPv4, inCidrIPv6, expandIPv6Simple functions

var runValidation = function(...) {
    // ...
    var cidrResult = inCidr(condition.value, item);
    // ...
}
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies that the PR reinvents complex IP/CIDR validation, which is a significant security risk; using a dedicated library is a critical best practice for correctness and maintainability.

High
Security
Mitigate potential ReDoS vulnerability

Add an input length check to expandIPv6Simple to mitigate a potential regular
expression denial of service (ReDoS) vulnerability.

helpers/asl/asl-1.js [188-213]

 var expandIPv6Simple = function(ip) {
+    // Mitigate ReDoS by limiting input length. Max IPv6 length is 39 chars.
+    if (typeof ip !== 'string' || ip.length > 45) {
+        return null;
+    }
     try {
         // Handle :: notation (simplified)
         if (ip.includes('::')) {
             var parts = ip.split('::');
             if (parts.length > 2) return null;
             
             var left = parts[0] ? parts[0].split(':') : [];
             var right = parts[1] ? parts[1].split(':') : [];
             
             var totalParts = left.length + right.length;
             var missingParts = 8 - totalParts;
             
             if (missingParts < 0) return null;
             
             var expanded = left.concat(Array(missingParts).fill('0000')).concat(right);
             return expanded.map(function(part) { return part.padStart(4, '0'); }).join('');
         } else {
             var ipParts = ip.split(':');
             if (ipParts.length !== 8) return null;
             return ipParts.map(function(part) { return part.padStart(4, '0'); }).join('');
         }
     } catch (e) {
         return null;
     }
 };
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a potential denial-of-service vulnerability from processing overly long, malformed IPv6 strings and proposes a simple, effective mitigation by adding an input length check.

Medium
General
Refactor nested callbacks with Promise.all

Refactor the nested callback structure for fetching tokens into a parallel
execution using Promise.all and async/await to improve code clarity and
performance.

helpers/azure/auth.js [57-101]

-if (azureConfig.Govcloud) {
-    const armScope = 'https://management.usgovcloudapi.net/.default';
-    const graphScope = 'https://graph.microsoft.us/.default';
-    const vaultScope = 'https://vault.azure.us/.default';
-
-    getToken(credential, [armScope], function(err, armToken) {
-        if (err) return callback(err);
-        getToken(credential, [graphScope], function(graphErr, graphToken) {
-            if (graphErr) return callback(graphErr);
-            getToken(credential, [vaultScope], function(vaultErr, vaultToken) {
-                if (vaultErr) console.log('No vault');
-                callback(null, {
-                    environment: {
-                        name: 'AzureUSGovernment',
-                        portalUrl: 'https://portal.azure.us'
-                    },
-                    token: armToken,
-                    graphToken: graphToken,
-                    vaultToken: vaultToken
-                });
-            });
+// Update getToken to return a promise
+function getToken(credential, scopes) {
+    return credential.getToken(scopes)
+        .then(response => response.token)
+        .catch(error => {
+            // For vault scope, a failure is not critical, so we can return null.
+            if (scopes[0].includes('vault.azure')) {
+                console.log('No vault token obtained:', error.message);
+                return null;
+            }
+            // For other scopes, re-throw the error.
+            throw error;
         });
-    });
-} else {
-    const armScope = 'https://management.azure.com/.default';
-    const graphScope = 'https://graph.microsoft.com/.default';
-    const vaultScope = 'https://vault.azure.net/.default';
-
-    getToken(credential, [armScope], function(err, armToken) {
-        if (err) return callback(err);
-        getToken(credential, [graphScope], function(graphErr, graphToken) {
-            if (graphErr) return callback(graphErr);
-            getToken(credential, [vaultScope], function(vaultErr, vaultToken) {
-                if (vaultErr) return callback(vaultErr);
-                callback(null, {
-                    environment: {
-                        name: 'AzureCloud',
-                        portalUrl: 'https://portal.azure.com'
-                    },
-                    token: armToken,
-                    graphToken: graphToken,
-                    vaultToken: vaultToken
-                });
-            });
-        });
-    });
 }
 
+try {
+    const isGov = azureConfig.Govcloud;
+    const armScope = isGov ? 'https://management.usgovcloudapi.net/.default' : 'https://management.azure.com/.default';
+    const graphScope = isGov ? 'https://graph.microsoft.us/.default' : 'https://graph.microsoft.com/.default';
+    const vaultScope = isGov ? 'https://vault.azure.us/.default' : 'https://vault.azure.net/.default';
+
+    const [armToken, graphToken, vaultToken] = await Promise.all([
+        getToken(credential, [armScope]),
+        getToken(credential, [graphScope]),
+        getToken(credential, [vaultScope])
+    ]);
+
+    callback(null, {
+        environment: {
+            name: isGov ? 'AzureUSGovernment' : 'AzureCloud',
+            portalUrl: isGov ? 'https://portal.azure.us' : 'https://portal.azure.com'
+        },
+        token: armToken,
+        graphToken: graphToken,
+        vaultToken: vaultToken
+    });
+} catch (err) {
+    return callback(err);
+}
+

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies nested callbacks ("callback hell") and proposes a modern solution using Promise.all and async/await. This improves code readability, maintainability, and performance by running independent token requests in parallel.

Medium
Possible issue
Remove duplicated error handling logic

Refactor the handleErrorResponse function by removing the large, duplicated
block of error handling logic to improve code maintainability.

helpers/azure/auth.js [163-266]

 function handleErrorResponse(body, response, callback) {
     if (body) {
         try {
             body = JSON.parse(body);
         } catch (e) {
-            return callback(`Error parsing error response from Azure API: ${e}`);
+            // Ignore parsing error, body might not be JSON
         }
 
-        if (typeof body == 'string') {
-            // Need to double parse it
+        if (typeof body === 'string') {
+            // Need to double parse it in some cases
             try {
                 body = JSON.parse(body);
             } catch (e) {
-                return callback(`Error parsing error response string from Azure API: ${e}`);
+                // Ignore if it's not a JSON string
             }
         }
 
-        if (response && ((response.statusCode && response.statusCode === 429) || (response.status && response.status === 429)) &&
-            body &&
-            body.error &&
-            body.error.message &&
-            typeof body.error.message == 'string') {
-            var errorMessage = `TooManyRequests: ${body.error.message}`;
+        const isTooManyRequests = response && ((response.statusCode && response.statusCode === 429) || (response.status && response.status === 429));
+
+        if (isTooManyRequests && body && body.error && typeof body.error.message === 'string') {
+            const errorMessage = `TooManyRequests: ${body.error.message}`;
             return callback(errorMessage, null, response);
-        } else if (body &&
-            body.error &&
-            body.error.message &&
-            typeof body.error.message == 'string') {
+        } else if (body && body.error && typeof body.error.message === 'string') {
             return callback(body.error.message);
-        } else if (body &&
-            body['odata.error'] &&
-            body['odata.error'].message &&
-            body['odata.error'].message.value &&
-            typeof body['odata.error'].message.value == 'string') {
+        } else if (body && body['odata.error'] && body['odata.error'].message && typeof body['odata.error'].message.value === 'string') {
             if (body['odata.error'].requestId) {
                 body['odata.error'].message.value += ` RequestId: ${body['odata.error'].requestId}`;
             }
             return callback(body['odata.error'].message.value);
-        } else if (body &&
-            body.message &&
-            typeof body.message == 'string') {
-            if (body.code && typeof body.code == 'string') {
-                body.message = (body.code + ': ' + body.message);
+        } else if (body && typeof body.message === 'string') {
+            if (body.code && typeof body.code === 'string') {
+                body.message = `${body.code}: ${body.message}`;
             }
             return callback(body.message);
-        } else if (body &&
-            body.Message &&
-            typeof body.Message == 'string') {
-            if (body.Code && typeof body.Code == 'string') {
-                body.Message = (body.Code + ': ' + body.Message);
-            }
-            return callback(body.Message);
-        }
-        if (typeof body == 'string') {
-            // Need to double parse it
-            try {
-                body = JSON.parse(body);
-            } catch (e) {
-                return callback(`Error parsing error response string from Azure API: ${e}`);
-            }
-        }
-        if (response && ((response.statusCode && response.statusCode === 429) || (response.status && response.status === 429)) &&
-            body &&
-            body.error &&
-            body.error.message &&
-            typeof body.error.message == 'string') {
-            errorMessage = `TooManyRequests: ${body.error.message}`;
-            return callback(errorMessage, null, response);
-        } else if (body &&
-            body.error &&
-            body.error.message &&
-            typeof body.error.message == 'string') {
-            return callback(body.error.message);
-        } else if (body &&
-            body['odata.error'] &&
-            body['odata.error'].message &&
-            body['odata.error'].message.value &&
-            typeof body['odata.error'].message.value == 'string') {
-            if (body['odata.error'].requestId) {
-                body['odata.error'].message.value += ` RequestId: ${body['odata.error'].requestId}`;
-            }
-            return callback(body['odata.error'].message.value);
-        } else if (body &&
-            body.message &&
-            typeof body.message == 'string') {
-            if (body.code && typeof body.code == 'string') {
-                body.message = (body.code + ': ' + body.message);
-            }
-            return callback(body.message);
-        } else if (body &&
-            body.Message &&
-            typeof body.Message == 'string') {
-            if (body.Code && typeof body.Code == 'string') {
-                body.Message = (body.Code + ': ' + body.Message);
+        } else if (body && typeof body.Message === 'string') {
+            if (body.Code && typeof body.Code === 'string') {
+                body.Message = `${body.Code}: ${body.Message}`;
             }
             return callback(body.Message);
         }
 
         console.log(`[ERROR] Unhandled error from Azure API: Body: ${JSON.stringify(body)}`);
     }
 
     console.log('[ERROR] Unhandled error from Azure API');
     return callback('Unknown error occurred while calling the Azure API');
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a large block of duplicated code within the handleErrorResponse function. Removing this redundancy significantly improves code maintainability and reduces the chance of inconsistent error handling logic.

Medium
  • Update

Copy link

@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: 14

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
helpers/asl/asl-1.js (1)

45-66: Potential null reference error when processing ARN templates without placeholders.

The placeholders variable is assigned from .match() which returns null when there are no matches. However, line 59 calls placeholders.forEach() without a null check, which will throw a TypeError if the ARN template has no {...} placeholders.

Apply this diff to add a null guard:

                 if (placeholders) {
                     extracted_values = placeholders.map(placeholder => {
                         const key = placeholder.slice(1, -1);
                         if (key === 'value') return [obj][0];
                         else return obj[key];
                     });
-                }
-                // Replace other variables
-                let converted_string = template_string
-                    .replace(/\{region\}/g, region)
-                    .replace(/\{cloudAccount\}/g, accountId)
-                    .replace(/\{resourceId\}/g, resourceId);
-                placeholders.forEach((placeholder, index) => {
+                    // Replace other variables
+                    let converted_string = template_string
+                        .replace(/\{region\}/g, region)
+                        .replace(/\{cloudAccount\}/g, accountId)
+                        .replace(/\{resourceId\}/g, resourceId);
+                    placeholders.forEach((placeholder, index) => {
helpers/shared.js (1)

18-42: Guard against missing settings.identifier before reading cloud_account_identifier

At Line 30, settings.identifier.cloud_account_identifier will throw if settings.identifier is undefined. This function later defensively initializes localSettings.identifier, but that happens after this access and on localSettings, not settings.

Consider guarding the access (or initializing identifier) before using it, e.g.:

-    localEvent.cloud_account_identifier = settings.identifier.cloud_account_identifier;
+    if (!settings.identifier) {
+        settings.identifier = {};
+    }
+
+    if (settings.identifier.cloud_account_identifier) {
+        localEvent.cloud_account_identifier = settings.identifier.cloud_account_identifier;
+    }

This keeps the new field populated when available but avoids runtime errors when identifier is absent.

collectors/azure/collector.js (1)

98-141: Harden errorFilter against non-object errors and simplify throttling detection

Two issues in the new throttling detection:

  1. err isn’t guarded:

    • const errorMessage = typeof err === 'string' ? err : err.message || err.toString();
    • If err is null/undefined (or lacks message/toString), this can throw inside the retry handler.
  2. Case handling is inconsistent:

    • You maintain both upper- and lower-case variants in throttlingPatterns but still do a case-sensitive .includes, which is fragile and harder to maintain.

A safer, simpler implementation:

-                    errorFilter: function(err) {
-                        const errorMessage = typeof err === 'string' ? err : err.message || err.toString();                        
-                        
-                        // Azure throttling patterns
-                        const throttlingPatterns = [
-                            'TooManyRequests',
-                            'RateLimitExceeded',
-                            'Throttling',
-                            'Throttled',
-                            'RequestThrottled',
-                            'RequestLimitExceeded',
-                            'ServerBusy',
-                            'ServiceBusy',
-                            'toomanyrequests',
-                            'ratelimitexceeded',
-                            'throttling',
-                            'throttled',
-                            'requestthrottled',
-                            'requestlimitexceeded',
-                            'serverbusy',
-                            'servicebusy',
-                            'too many requests',
-                            'rate limit',
-                            'retry after',
-                            'the request is being throttled',
-                            'request rate is large',
-                            'rate exceeded'
-                        ];
-                        
-                        const errorMatch = throttlingPatterns.some(pattern => errorMessage.includes(pattern));                        
-                        return errorMatch;
-                    }
+                    errorFilter: function(err) {
+                        const rawErrorMessage =
+                            typeof err === 'string'
+                                ? err
+                                : (err && err.message) ||
+                                  (err && err.toString && err.toString()) ||
+                                  '';
+                        const errorMessage = rawErrorMessage.toLowerCase();
+
+                        // Azure throttling patterns (lowercased)
+                        const throttlingPatterns = [
+                            'toomanyrequests',
+                            'ratelimitexceeded',
+                            'throttling',
+                            'throttled',
+                            'requestthrottled',
+                            'requestlimitexceeded',
+                            'serverbusy',
+                            'servicebusy',
+                            'too many requests',
+                            'rate limit',
+                            'retry after',
+                            'the request is being throttled',
+                            'request rate is large',
+                            'rate exceeded'
+                        ];
+
+                        return throttlingPatterns.some(pattern =>
+                            errorMessage.includes(pattern)
+                        );
+                    }

This avoids crashes in the retry path and keeps throttling detection robust with a single, normalized list. If you want to address Sonar’s nesting complaint later, errorFilter and throttlingPatterns would also be good candidates to lift into a top-level helper.

🟡 Minor comments (10)
plugins/azure/apiManagement/apiInstanceManagedIdentity.js-10-10 (1)

10-10: Inconsistent terminology: both "Azure AD" and "Azure Entra ID" in the same sentence.

The text references both "Azure AD" (first part) and "Azure Entra ID" (second part), which is confusing. Since this PR updates terminology from Azure AD to Azure Entra ID, both occurrences should use the new terminology consistently.

Additionally, "eliminate" should be "eliminates" for subject-verb agreement.

Apply this diff to fix the inconsistent terminology and grammar:

-    more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Entra ID tokens.',
+    more_info: 'Enabling managed identities eliminates the need for developers having to manage credentials by providing an identity for the Azure resource in Azure Entra ID and using it to obtain Azure Entra ID tokens.',
plugins/azure/containerapps/containerAppManagedIdentity.js-10-10 (1)

10-10: Fix inconsistent terminology and grammar.

The more_info text contains mixed terminology, using both "Azure AD" and "Azure Entra ID" in the same sentence. Additionally, there's a subject-verb agreement issue with "eliminate."

Apply this diff to use consistent terminology and correct grammar:

-    more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Entra ID tokens.',
+    more_info: 'Enabling managed identities eliminates the need for developers having to manage credentials by providing an identity for the Azure resource in Microsoft Entra ID and using it to obtain Microsoft Entra ID tokens.',
plugins/azure/automationAccounts/automationAcctManagedIdentity.js-10-10 (1)

10-10: Incomplete terminology migration in documentation text.

The more_info field contains inconsistent terminology, referencing both "Azure AD" and "Azure Entra ID" in the same sentence. Since this PR updates Azure AD references to Azure Entra ID, this line should be fully migrated for consistency.

Apply this diff to complete the terminology update:

-    more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Entra ID tokens.',
+    more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure Entra ID and using it to obtain Azure Entra ID tokens.',
plugins/azure/cosmosdb/cosmosdbManagedIdentity.spec.js-10-10 (1)

10-10: Terminology inconsistency: mixes "Azure AD" and "Azure Entra ID" in the same sentence.

Consider using consistent terminology. Since Azure AD has been rebranded to Microsoft Entra ID, update to use the new name throughout.

-    more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Entra ID tokens.',
+    more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Microsoft Entra ID and using it to obtain tokens.',
plugins/aws/kms/kmsDefaultKeyUsage.js-24-24 (1)

24-24: Fix typo in EFS delete realtime trigger identifier

The last trigger is ':efs:DeleteFileSystem' (leading colon), which likely prevents it from ever matching an efs:DeleteFileSystem event. This looks like a small typo and should be corrected to keep EFS delete events covered in realtime.

Suggested change:

-    realtime_triggers: ['cloudtrail:CreateTrail','cloudtrail:UpdateTrail','cloudtrail:DeleteTrail','ec2:CreateVolume','ec2:DeleteVolume','rds:CreateDBInstance','rds:ModifyDBInstance','rds:DeleteDBInstance','redshift:CreateCluster','redshift:ModifyCluster','redshift:DeleteCluster','s3:CreateBucket','s3:DeleteBucket','s3:PutBucketEncryption','ses:CreateReceiptRule','ses:DeleteReceiptRule','ses:UpdateReceiptRule','workspaces:CreateWorkspaces','workspaces:TerminateWorkspaces','lambda:UpdateFunctionConfiguration','lambda:CreateFunction','lambda:DeleteFunction','cloudwatchlogs:CreateLogGroup','cloudwatchlogs:DeleteLogGroup','cloudwatchlogs:AssociateKmsKey','efs:CreateFileSystem',':efs:DeleteFileSystem'],
+    realtime_triggers: ['cloudtrail:CreateTrail','cloudtrail:UpdateTrail','cloudtrail:DeleteTrail','ec2:CreateVolume','ec2:DeleteVolume','rds:CreateDBInstance','rds:ModifyDBInstance','rds:DeleteDBInstance','redshift:CreateCluster','redshift:ModifyCluster','redshift:DeleteCluster','s3:CreateBucket','s3:DeleteBucket','s3:PutBucketEncryption','ses:CreateReceiptRule','ses:DeleteReceiptRule','ses:UpdateReceiptRule','workspaces:CreateWorkspaces','workspaces:TerminateWorkspaces','lambda:UpdateFunctionConfiguration','lambda:CreateFunction','lambda:DeleteFunction','cloudwatchlogs:CreateLogGroup','cloudwatchlogs:DeleteLogGroup','cloudwatchlogs:AssociateKmsKey','efs:CreateFileSystem','efs:DeleteFileSystem'],
plugins/azure/appConfigurations/appConfigManagedIdentity.js-10-10 (1)

10-10: Fix inconsistent Azure terminology.

The text mixes old and new Azure terminology in the same sentence: "identity for the Azure resource in Azure AD and using it to obtain Azure Entra ID tokens." Since this PR is migrating to Azure Entra ID terminology, both references should use the new naming.

-    more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Entra ID tokens.',
+    more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure Entra ID and using it to obtain Azure Entra ID tokens.',
plugins/azure/containerregistry/acrManagedIdentityEnabled.js-10-10 (1)

10-10: Inconsistent terminology: mixes "Azure AD" and "Azure Entra ID" in the same sentence.

The more_info text references both "Azure AD" and "Azure Entra ID" which is inconsistent with the broader terminology migration in this PR.

-    more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Entra ID tokens.',
+    more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure Entra ID and using it to obtain Azure Entra ID tokens.',
plugins/azure/appservice/functionPrivilegeAnalysis.js-10-10 (1)

10-10: Invalid apis configuration.

The apis array contains an empty string [''] which is likely incorrect. This should either list the actual Azure APIs needed for this plugin or be an empty array [] if no APIs are required yet.

-    apis: [''],
+    apis: [],
exports.js-1044-1051 (1)

1044-1051: Typo in Entra ID export key and filename (appOrgnaizationalDirectoryAccess)

Both the export key and required module use appOrgnaizationalDirectoryAccess (missing the second “i” in “Organizational”). This is easy to miss in consumers and in docs.

Recommend correcting the spelling everywhere:

-        'appOrgnaizationalDirectoryAccess'         : require(__dirname + '/plugins/azure/entraid/appOrgnaizationalDirectoryAccess.js'),
+        'appOrganizationalDirectoryAccess'         : require(__dirname + '/plugins/azure/entraid/appOrganizationalDirectoryAccess.js'),

…and renaming the actual plugin file accordingly.

helpers/azure/auth.js-62-79 (1)

62-79: GovCloud vault token error silently logs instead of failing.

On line 67, when vault token fetch fails for GovCloud, it only logs 'No vault' but still proceeds successfully. This differs from the public Azure path (line 90) which returns the error via callback. Consider consistent error handling.

                     getToken(credential, [vaultScope], function(vaultErr, vaultToken) {
-                        if (vaultErr) console.log('No vault');
+                        if (vaultErr) {
+                            console.log('Warning: Could not obtain vault token for GovCloud:', vaultErr.message || vaultErr);
+                        }
                         callback(null, {
🧹 Nitpick comments (24)
plugins/aws/eks/eksKubernetesVersion.spec.js (1)

79-87: Test data update to 1.30 looks good; consider centralizing the “current” version string

Bumping the mocked cluster version to "1.30" in the “current” scenario is consistent with the intent of this test and doesn’t introduce any behavioral risk.

To reduce future churn when EKS moves to the next minor, you could optionally extract a shared constant for the “current” version (e.g. at the top of this spec or in a common test helper) and use it in all related tests instead of hard‑coding "1.30" here and elsewhere.

plugins/aws/ec2/ebsRecentSnapshots.js (2)

14-21: Well-defined settings schema with clear validation.

The regex ^[1-9]{1}[0-9]{0,2}$ allows values from 1 to 999 days, which provides substantial flexibility. While 999 days (nearly 3 years) is quite generous for snapshot recency, this wide range accommodates various organizational backup policies.

If you want to enforce a more reasonable upper bound (e.g., 90 or 180 days), consider tightening the regex. Otherwise, the current implementation is sound.


25-27: Prefer Number.parseInt over global parseInt.

The config parsing logic is correct, but using Number.parseInt is the modern best practice as it's more explicit and avoids potential global scope issues.

Apply this diff:

-        var config = {
-            ebs_recent_snapshot_days: parseInt(settings.ebs_recent_snapshot_days || this.settings.ebs_recent_snapshot_days.default)
-        };
+        var config = {
+            ebs_recent_snapshot_days: Number.parseInt(settings.ebs_recent_snapshot_days || this.settings.ebs_recent_snapshot_days.default)
+        };
postprocess/output.js (1)

339-357: SaaS delivery is fire-and-forget.

The _sendToSaaS call after stream.end() means close() returns before the SaaS delivery completes. The caller won't be notified if delivery fails. If this is intentional (non-blocking), consider documenting it; otherwise, you may want to return a Promise or callback for completion status.

plugins/azure/batchAccounts/batchAccountsManagedIdentity.js (1)

10-10: Standardize "Azure Entra ID" capitalization.

The text uses "Azure Entra Id" but other files in this PR use "Azure Entra ID" (with uppercase "ID"). For consistency across the codebase, standardize the capitalization to "Azure Entra ID".

-    more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure  and using it to obtain Azure Entra Id tokens.',
+    more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure and using it to obtain Azure Entra ID tokens.',

Note: This also removes the extra space before "and".

plugins/azure/appservice/scmSiteAccessRestriction.js (1)

48-70: Consider optional chaining for cleaner code.

The refactored logic correctly prioritizes checking publicNetworkAccess before evaluating IP restrictions. The implementation is sound.

As suggested by SonarCloud, you could simplify lines 56-61 using optional chaining:

-                        let denyAllIp;
-                        if (config.scmIpSecurityRestrictions && config.scmIpSecurityRestrictions.length) {
-                            denyAllIp = config.scmIpSecurityRestrictions.find(ipSecurityRestriction =>
+                        const denyAllIp = config.scmIpSecurityRestrictions?.find(ipSecurityRestriction =>
                                 ipSecurityRestriction.ipAddress && ipSecurityRestriction.ipAddress.toUpperCase() === 'ANY' &&
                                 ipSecurityRestriction.action && ipSecurityRestriction.action.toUpperCase() === 'DENY'
                             );
-                        }
plugins/azure/appservice/appServiceAccessRestriction.js (1)

52-76: Consider optional chaining for consistency.

The refactored logic correctly prioritizes publicNetworkAccess being disabled before checking for explicit deny rules. The implementation aligns well with the companion changes in scmSiteAccessRestriction.js.

Similar to the pattern in scmSiteAccessRestriction.js, you could use optional chaining for cleaner code:

-                        let denyAllIp;
-                        if (config.ipSecurityRestrictions && config.ipSecurityRestrictions.length) {
-                            denyAllIp = config.ipSecurityRestrictions.find(ipSecurityRestriction =>
+                        const denyAllIp = config.ipSecurityRestrictions?.find(ipSecurityRestriction =>
                                 ipSecurityRestriction.ipAddress && ipSecurityRestriction.ipAddress.toUpperCase() === 'ANY' &&
                                 ipSecurityRestriction.action && ipSecurityRestriction.action.toUpperCase() === 'DENY'
                             );
-                        }
plugins/azure/appservice/privateEndpointsEnabled.js (1)

55-67: Use optional chaining for cleaner conditionals.

SonarCloud correctly flags that optional chaining would be more concise.

-                if (webApp.kind && webApp.kind.toLowerCase().includes('functionapp')) {
+                if (webApp.kind?.toLowerCase().includes('functionapp')) {
                     helpers.addResult(results, 0, 'Function App has Private Endpoints configured', location, webApp.id);
                 } else {
                     helpers.addResult(results, 0, 'App Service has Private Endpoints configured', location, webApp.id);
                 }
             } else {
                 // No private endpoints configured
-                if (webApp.kind && webApp.kind.toLowerCase().includes('functionapp')) {
+                if (webApp.kind?.toLowerCase().includes('functionapp')) {
                     helpers.addResult(results, 2, 'Function App does not have Private Endpoints configured', location, webApp.id);
                 } else {
                     helpers.addResult(results, 2, 'App Service does not have Private Endpoints configured', location, webApp.id);
                 }
plugins/azure/appservice/privateEndpointsEnabled.spec.js (1)

41-69: createCache correctly builds getWebAppDetails; consider minor readability tweak

The createCache helper matches the expected webApps.getWebAppDetails[location][id].data shape and ties privateEndpointConnections[index] to each app, which should exercise the implementation path accurately. As a small readability polish, you could replace if (webApp && webApp.id) with optional chaining:

-            if (webApp && webApp.id) {
+            if (webApp?.id) {

This keeps the intent while aligning with the static analysis suggestion.

helpers/asl/asl-1.js (7)

510-542: Duplicate branch logic can be consolidated.

The branches at lines 510-517 (allNotSet) and 526-533 (anyNotSet) produce identical result objects. As flagged by static analysis, these can be merged to reduce duplication.

-                if (condition.parsed.length === 0 || allNotSet) {
-                    message.push(`${condition.property}: ${arrayMessages.join(', ')}`);
-                    let resultObj = {
-                        status: 2, // FAIL if array is empty or all items are not set (property missing everywhere)
-                        message: message.join(', ')
-                    };
-                    inputResultsArr.push(resultObj);
-                    return resultObj;
-                } else if (anyMatch) {
+                if (anyMatch) {
                     message.push(`${condition.property}: ${arrayMessages.join(', ')}`);
                     let resultObj = {
                         status: 0, // PASS if any item matches and at least one is set
                         message: message.join(', ')
                     };
                     inputResultsArr.push(resultObj);
                     return resultObj;
-                } else if (anyNotSet) {
+                } else {
+                    // FAIL if: array is empty, all items are not set, any item is not set, or no matches
                     message.push(`${condition.property}: ${arrayMessages.join(', ')}`);
                     let resultObj = {
-                        status: 2, // FAIL if any item is not set
-                        message: message.join(', ')
-                    };
-                    inputResultsArr.push(resultObj);
-                    return resultObj;
-                } else {
-                    message.push(`${condition.property}: ${arrayMessages.join(', ')}`);
-                    let resultObj = {
-                        status: 2, // FAIL if none match and all are set
+                        status: 2,
                         message: message.join(', ')
                     };
                     inputResultsArr.push(resultObj);
                     return resultObj;
                 }

366-366: Function has 8 parameters; nestedResultArr appears unused.

Static analysis flags this function for having too many parameters (8 vs recommended max of 7). Additionally, nestedResultArr is never used within the function body.

Consider removing the unused parameter and grouping related parameters into an options object:

-var runValidation = function(obj, condition, inputResultsArr, nestedResultArr, region, cloud, accountId, resourceId) {
+var runValidation = function(obj, condition, inputResultsArr, context) {
+    var { region, cloud, accountId, resourceId } = context;

Then update call sites to pass a context object:

runValidation(data, condition, inputResultsArr, { region, cloud, accountId, resourceId: resourceName });

77-77: Use const/let instead of var and prefer Number.* methods.

Static analysis flagged several modernization opportunities throughout the file. Consider updating for consistency:

  1. Replace var with const/let at lines 21, 77, 102, 135, 144, 176, 188, 198, 206, 215, 225, etc.

  2. Prefer Number.parseInt over global parseInt:

-    var prefixLength = parseInt(cidrMatch[2]);
+    var prefixLength = Number.parseInt(cidrMatch[2], 10);
  1. Prefer Number.isNaN over global isNaN:
-    if (cidrParts.some(function(part) { return isNaN(part) || part < 0 || part > 255; }))
+    if (cidrParts.some(function(part) { return Number.isNaN(part) || part < 0 || part > 255; }))
  1. Use optional chaining at line 284:
-    if (!inputResultsArr || !inputResultsArr.length) {
+    if (!inputResultsArr?.length) {

210-212: Empty catch block silently swallows errors.

The catch block returns null without logging or preserving any error information, making debugging difficult if the IPv6 expansion fails.

     } catch (e) {
+        // IPv6 parsing failed - return null to indicate invalid format
+        console.debug && console.debug('IPv6 expansion failed:', e.message);
         return null;
     }

544-544: Redundant condition check.

The trailing && condition in the if statement is always truthy since condition is a required object parameter. This appears to be leftover code.

-            if (condition.transform && condition.transform == 'EACH' && condition) {
+            if (condition.transform && condition.transform == 'EACH') {

480-482: Variable userRegex shadows outer declaration.

userRegex is declared at line 436-438 and then re-declared at line 481 within the forEach callback, shadowing the outer variable. While intentional, this can cause confusion.

Consider renaming the inner variable for clarity:

                         } else if (condition.op == 'MATCHES') {
-                            let userRegex = RegExp(condition.value);
-                            itemMatch = userRegex.test(item);
+                            let itemRegex = new RegExp(condition.value);
+                            itemMatch = itemRegex.test(item);
                         }

808-1059: Large code block duplicates operator logic from runValidation.

This 250-line block (lines 808-1059) duplicates most of the operator handling logic (CONTAINS, EQ, NE, GT, LT, MATCHES, etc.) that already exists in runValidation. This duplication makes maintenance difficult—any bug fix or new operator must be updated in both places.

Consider extracting the comparison logic into a shared helper function:

function evaluateCondition(propValue, operator, conditionValue) {
    if (operator === 'EQ') return propValue === conditionValue;
    if (operator === 'NE') return propValue !== conditionValue;
    if (operator === 'CONTAINS') {
        return (typeof propValue === 'string' || Array.isArray(propValue)) && 
               propValue.includes(conditionValue);
    }
    // ... other operators
}

Then both runConditions (for AliasTarget) and runValidation can use this shared helper.

.env.example (1)

1-27: dotenv-linter ordering warnings are purely cosmetic

The current example values look safe (all clear placeholders). The reported dotenv-linter warnings are only about key ordering (e.g., AWS_REGION before AWS_SECRET_ACCESS_KEY, LOG_LEVEL before NODE_ENV).

If you rely on dotenv-linter in CI and want a clean run, you can reorder the keys as suggested; otherwise this can be safely ignored.

plugins/aws/s3/s3BucketHasTags.js (1)

39-39: Use const instead of var for bucketArn.

Static analysis flagged this line. Since bucketArn is not reassigned, use const for immutability.

-            var bucketArn = `arn:${awsOrGov}:s3:::${bucket.Name}`;
+            const bucketArn = `arn:${awsOrGov}:s3:::${bucket.Name}`;
plugins/aws/s3/s3BucketHasTags.spec.js (1)

127-168: Consider extracting shared callback for "no tags" tests.

SonarCloud flagged duplicate callback implementations. While acceptable for test code, you could extract a shared callback for tests that verify status 2 with "S3 bucket does not have any tags" message.

// At the top of the describe block, add:
const expectNoTagsResult = (done) => (err, results) => {
    expect(results.length).to.equal(1);
    expect(results[0].status).to.equal(2);
    expect(results[0].message).to.include('S3 bucket does not have any tags');
    done();
};

// Then use in tests:
// s3BucketHasTags.run(cache, {}, expectNoTagsResult(done));
plugins/azure/appservice/functionPrivilegeAnalysis.js (1)

18-23: Use const instead of var and clarify stub implementation.

Static analysis flagged the var usage. Also, consider adding a TODO comment to clarify this is a placeholder.

     run: function(cache, settings, callback) {
-        var results = [];
-        var source = {};
+        // TODO: Implement privilege analysis for Azure Functions
+        const results = [];
+        const source = {};

         callback(null, results, source);
     },
.eslintrc.json (1)

38-46: Test files are ignored, so overrides for them will never run

ignorePatterns excludes *.test.js and *.spec.js, but you also define test-specific overrides for those globs. As written, ESLint will skip these files entirely and the overrides are dead code. Consider dropping the test patterns from ignorePatterns and relying on the overrides block instead.

Also applies to: 99-109

README.md (1)

85-137: New dev/testing section triggers markdownlint (MD003/MD014); consider minor cleanups

The added commands use $ prompts without showing output, and the new headings are ATX style where the repo’s markdownlint config expects setext. If you care about passing markdownlint, either:

  • Drop the leading $ (or add example output), and/or
  • Switch these headings to the repo’s preferred style, or relax the markdownlint rules for this file/section.
helpers/aws/api.js (1)

663-680: OpenSearch/OpenSearchServerless mapping via array index is a bit brittle

serviceMap.OpenSearch is an array where index 0 is the domain and index 1 is the serverless collection; postcalls then reference these by index. This works but couples call‑site correctness to array ordering.

If you touch this again, consider using separate named entries (e.g. OpenSearchDomain, OpenSearchServerless) or an object with explicit keys instead of relying on [0]/[1].

Also applies to: 2340-2347, 3224-3236

helpers/azure/auth.js (1)

2-2: Use const instead of var for imports.

As flagged by static analysis, module imports should use const since they are not reassigned.

-var axios = require('axios');
+const axios = require('axios');
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b15bb09 and e2e25cc.

📒 Files selected for processing (48)
  • .env.example (1 hunks)
  • .eslintrc.json (1 hunks)
  • .github/pull_request_templates/pull_request_template.md (1 hunks)
  • .github/workflows/scans_ci.yml (1 hunks)
  • .gitignore (1 hunks)
  • .prettierrc (1 hunks)
  • README.md (1 hunks)
  • collectors/azure/collector.js (1 hunks)
  • exports.js (13 hunks)
  • helpers/asl/asl-1.js (10 hunks)
  • helpers/aws/api.js (17 hunks)
  • helpers/aws/api_multipart.js (2 hunks)
  • helpers/azure/api.js (24 hunks)
  • helpers/azure/auth.js (5 hunks)
  • helpers/shared.js (2 hunks)
  • index.js (1 hunks)
  • package.json (2 hunks)
  • plugins/aws/ec2/ebsRecentSnapshots.js (3 hunks)
  • plugins/aws/ec2/ebsRecentSnapshots.spec.js (3 hunks)
  • plugins/aws/eks/eksKubernetesVersion.spec.js (1 hunks)
  • plugins/aws/kms/kmsDefaultKeyUsage.js (2 hunks)
  • plugins/aws/s3/bucketSecureTransportEnabled.spec.js (1 hunks)
  • plugins/aws/s3/s3BucketHasTags.js (2 hunks)
  • plugins/aws/s3/s3BucketHasTags.spec.js (5 hunks)
  • plugins/azure/apiManagement/apiInstanceManagedIdentity.js (2 hunks)
  • plugins/azure/appConfigurations/appConfigAccessKeyAuthDisabled.js (2 hunks)
  • plugins/azure/appConfigurations/appConfigManagedIdentity.js (2 hunks)
  • plugins/azure/appservice/appServiceAccessRestriction.js (4 hunks)
  • plugins/azure/appservice/appServiceAccessRestriction.spec.js (6 hunks)
  • plugins/azure/appservice/authEnabled.js (2 hunks)
  • plugins/azure/appservice/automatedBackupsEnabled.spec.js (3 hunks)
  • plugins/azure/appservice/functionPrivilegeAnalysis.js (1 hunks)
  • plugins/azure/appservice/privateEndpointsEnabled.js (2 hunks)
  • plugins/azure/appservice/privateEndpointsEnabled.spec.js (4 hunks)
  • plugins/azure/appservice/scmSiteAccessRestriction.js (1 hunks)
  • plugins/azure/appservice/scmSiteAccessRestriction.spec.js (2 hunks)
  • plugins/azure/appservice/webAppsADEnabled.js (3 hunks)
  • plugins/azure/appservice/webAppsADEnabled.spec.js (1 hunks)
  • plugins/azure/automationAccounts/automationAcctExpiredWebhooks.spec.js (1 hunks)
  • plugins/azure/automationAccounts/automationAcctManagedIdentity.js (2 hunks)
  • plugins/azure/batchAccounts/batchAccountsAADEnabled.js (2 hunks)
  • plugins/azure/batchAccounts/batchAccountsAADEnabled.spec.js (1 hunks)
  • plugins/azure/batchAccounts/batchAccountsManagedIdentity.js (1 hunks)
  • plugins/azure/containerapps/containerAppManagedIdentity.js (1 hunks)
  • plugins/azure/containerregistry/acrManagedIdentityEnabled.js (2 hunks)
  • plugins/azure/cosmosdb/cosmosdbLocalAuth.js (1 hunks)
  • plugins/azure/cosmosdb/cosmosdbManagedIdentity.spec.js (1 hunks)
  • postprocess/output.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
helpers/shared.js (1)
index.js (1)
  • settings (83-83)
plugins/azure/appservice/privateEndpointsEnabled.spec.js (3)
plugins/azure/appservice/appServiceAccessRestriction.spec.js (2)
  • createCache (63-82)
  • webApps (4-9)
plugins/azure/appservice/webAppsADEnabled.spec.js (2)
  • createCache (39-49)
  • webApps (4-37)
plugins/azure/appservice/privateEndpointsEnabled.js (1)
  • webApps (22-23)
plugins/azure/appservice/appServiceAccessRestriction.spec.js (3)
plugins/azure/appservice/scmSiteAccessRestriction.spec.js (10)
  • cache (112-112)
  • cache (123-123)
  • cache (134-134)
  • cache (145-145)
  • cache (156-156)
  • cache (167-167)
  • cache (178-178)
  • createCache (63-82)
  • webApps (4-9)
  • configurations (11-61)
plugins/azure/appservice/disableFTPDeployments.spec.js (2)
  • createCache (22-41)
  • configurations (11-20)
plugins/azure/appservice/appServiceAccessRestriction.js (1)
  • webApps (27-28)
plugins/azure/appservice/functionPrivilegeAnalysis.js (4)
plugins/azure/appservice/authEnabled.js (2)
  • results (35-35)
  • source (36-36)
plugins/azure/automationAccounts/automationAcctManagedIdentity.js (2)
  • results (17-17)
  • source (18-18)
plugins/azure/cosmosdb/cosmosdbLocalAuth.js (2)
  • results (17-17)
  • source (18-18)
plugins/azure/cosmosdb/cosmosdbManagedIdentity.spec.js (2)
  • results (17-17)
  • source (18-18)
plugins/azure/appservice/appServiceAccessRestriction.js (3)
plugins/azure/appservice/scmSiteAccessRestriction.js (2)
  • config (48-48)
  • webConfigs (39-41)
plugins/azure/appservice/http20Enabled.js (2)
  • webConfigs (46-48)
  • helpers (2-2)
plugins/azure/appservice/tlsVersionCheck.js (1)
  • webConfigs (51-53)
plugins/aws/ec2/ebsRecentSnapshots.js (1)
plugins/aws/ec2/ebsRecentSnapshots.spec.js (2)
  • settings (156-156)
  • settings (168-168)
plugins/azure/appservice/privateEndpointsEnabled.js (4)
plugins/azure/appservice/authEnabled.js (3)
  • helpers (2-2)
  • source (36-36)
  • results (35-35)
plugins/azure/automationAccounts/automationAcctManagedIdentity.js (3)
  • helpers (2-2)
  • source (18-18)
  • results (17-17)
plugins/azure/cosmosdb/cosmosdbLocalAuth.js (3)
  • helpers (2-2)
  • source (18-18)
  • results (17-17)
plugins/azure/cosmosdb/cosmosdbManagedIdentity.spec.js (3)
  • helpers (2-2)
  • source (18-18)
  • results (17-17)
🪛 actionlint (1.7.9)
.github/workflows/scans_ci.yml

19-19: the runner of "actions/checkout@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


22-22: the runner of "actions/setup-node@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🪛 dotenv-linter (4.0.0)
.env.example

[warning] 4-4: [UnorderedKey] The AWS_REGION key should go before the AWS_SECRET_ACCESS_KEY key

(UnorderedKey)


[warning] 8-8: [UnorderedKey] The AZURE_CLIENT_ID key should go before the AZURE_TENANT_ID key

(UnorderedKey)


[warning] 9-9: [UnorderedKey] The AZURE_CLIENT_SECRET key should go before the AZURE_TENANT_ID key

(UnorderedKey)


[warning] 10-10: [UnorderedKey] The AZURE_SUBSCRIPTION_ID key should go before the AZURE_TENANT_ID key

(UnorderedKey)


[warning] 17-17: [UnorderedKey] The GITHUB_ORG key should go before the GITHUB_TOKEN key

(UnorderedKey)


[warning] 21-21: [UnorderedKey] The LOG_LEVEL key should go before the NODE_ENV key

(UnorderedKey)

🪛 GitHub Check: SonarCloud Code Analysis
plugins/azure/appservice/privateEndpointsEnabled.spec.js

[warning] 57-57: Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxfKDnQ4yCTHoX0E&open=AZrlMxfKDnQ4yCTHoX0E&pullRequest=51

collectors/azure/collector.js

[failure] 139-139: Refactor this code to not nest functions more than 4 levels deep.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxkiDnQ4yCTHoX13&open=AZrlMxkiDnQ4yCTHoX13&pullRequest=51

plugins/azure/appservice/functionPrivilegeAnalysis.js

[failure] 19-19: Unexpected var, use let or const instead.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxdyDnQ4yCTHoX0A&open=AZrlMxdyDnQ4yCTHoX0A&pullRequest=51

plugins/aws/s3/s3BucketHasTags.spec.js

[warning] 150-150: Update this function so that its implementation is not identical to the one on line 128.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxbCDnQ4yCTHoXz4&open=AZrlMxbCDnQ4yCTHoXz4&pullRequest=51

plugins/aws/s3/s3BucketHasTags.js

[failure] 39-39: Unexpected var, use let or const instead.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxbjDnQ4yCTHoXz5&open=AZrlMxbjDnQ4yCTHoXz5&pullRequest=51

plugins/aws/ec2/ebsRecentSnapshots.js

[warning] 26-26: Prefer Number.parseInt over parseInt.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxXsDnQ4yCTHoXz2&open=AZrlMxXsDnQ4yCTHoXz2&pullRequest=51

helpers/azure/auth.js

[failure] 2-2: Unexpected var, use let or const instead.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxhxDnQ4yCTHoX0L&open=AZrlMxhxDnQ4yCTHoX0L&pullRequest=51


[warning] 231-233: Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxhxDnQ4yCTHoX0V&open=AZrlMxhxDnQ4yCTHoX0V&pullRequest=51


[warning] 185-185: Consider moving declaration of 'errorMessage' as it is referenced outside current binding context.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxhxDnQ4yCTHoX0T&open=AZrlMxhxDnQ4yCTHoX0T&pullRequest=51

plugins/azure/appservice/scmSiteAccessRestriction.js

[warning] 56-56: Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxggDnQ4yCTHoX0K&open=AZrlMxggDnQ4yCTHoX0K&pullRequest=51

helpers/asl/asl-1.js

[failure] 21-21: Unexpected var, use let or const instead.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj4DnQ4yCTHoX0c&open=AZrlMxj4DnQ4yCTHoX0c&pullRequest=51


[warning] 122-122: Prefer Number.isNaN over isNaN.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX0s&open=AZrlMxj5DnQ4yCTHoX0s&pullRequest=51


[failure] 144-144: Unexpected var, use let or const instead.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX00&open=AZrlMxj5DnQ4yCTHoX00&pullRequest=51


[failure] 206-206: Unexpected var, use let or const instead.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX1K&open=AZrlMxj5DnQ4yCTHoX1K&pullRequest=51


[failure] 135-135: Unexpected var, use let or const instead.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX0z&open=AZrlMxj5DnQ4yCTHoX0z&pullRequest=51


[warning] 121-121: Prefer Number.parseInt over parseInt.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX0r&open=AZrlMxj5DnQ4yCTHoX0r&pullRequest=51


[warning] 210-212: Handle this exception or don't catch it at all.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX1L&open=AZrlMxj5DnQ4yCTHoX1L&pullRequest=51


[failure] 225-225: Unexpected var, use let or const instead.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX1R&open=AZrlMxj5DnQ4yCTHoX1R&pullRequest=51


[failure] 198-198: Unexpected var, use let or const instead.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX1G&open=AZrlMxj5DnQ4yCTHoX1G&pullRequest=51


[warning] 112-112: Prefer Number.isNaN over isNaN.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX0o&open=AZrlMxj5DnQ4yCTHoX0o&pullRequest=51


[failure] 77-77: Unexpected var, use let or const instead.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj4DnQ4yCTHoX0e&open=AZrlMxj4DnQ4yCTHoX0e&pullRequest=51


[warning] 111-111: Prefer Number.parseInt over parseInt.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX0n&open=AZrlMxj5DnQ4yCTHoX0n&pullRequest=51


[warning] 284-284: Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX1W&open=AZrlMxj5DnQ4yCTHoX1W&pullRequest=51


[warning] 366-366: Function has too many parameters (8). Maximum allowed is 7.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX1a&open=AZrlMxj5DnQ4yCTHoX1a&pullRequest=51


[warning] 526-534: This branch's code block is the same as the block for the branch on line 510.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX1o&open=AZrlMxj5DnQ4yCTHoX1o&pullRequest=51


[warning] 891-891: Prefer Number.isNaN over isNaN.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxj5DnQ4yCTHoX1z&open=AZrlMxj5DnQ4yCTHoX1z&pullRequest=51

plugins/azure/appservice/privateEndpointsEnabled.js

[warning] 56-56: Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxflDnQ4yCTHoX0H&open=AZrlMxflDnQ4yCTHoX0H&pullRequest=51

postprocess/output.js

[warning] 364-364: Prefer node:https over https.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxlMDnQ4yCTHoX17&open=AZrlMxlMDnQ4yCTHoX17&pullRequest=51

🪛 LanguageTool
.github/pull_request_templates/pull_request_template.md

[style] ~10-~10: Consider using a different verb for a more formal wording.
Context: ...- [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaki...

(FIX_RESOLVE)

🪛 markdownlint-cli2 (0.18.1)
README.md

81-81: Dollar signs used before commands without showing output

(MD014, commands-show-output)


82-82: Dollar signs used before commands without showing output

(MD014, commands-show-output)


85-85: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


87-87: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


95-95: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


103-103: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


111-111: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


119-119: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


128-128: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)

Comment on lines +584 to +609
return 0;
} else if (conditionStringified && conditionStringified.length){
message.push(`${condition.value} found in ${conditionStringified}`);
return 2;
} else {
message.push(`${condition.parsed} is not the right property type for this operation`);
return 2;
}
} else {
// Recurse into the same function
var subProcessed = [];
if (!condition.parsed.length) {
conditionResult = 2;
message.push(`${property}: is not iterable using EACH transformation`);
} else {
condition.parsed.forEach(function(parsed) {
subProcessed.push(runValidation(parsed, condition, inputResultsArr, null, region, cloud, accountId, resourceId));
});
subProcessed.forEach(function(sub) {
if (sub.status) conditionResult = sub.status;
if (sub.message) message.push(sub.message);
});
}
}
} else if (condition.op == 'EQ') {
if (condition.parsed == condition.value) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Inconsistent return values: returns raw numbers instead of result objects.

The NOTCONTAINS branch within the EACH transform returns raw status numbers (0 or 2) at lines 577, 580, 584, 587, and 590. All other branches in runValidation return result objects with { status, message }. This inconsistency will cause errors when calling code attempts to access .status or .message properties.

Apply this diff to return consistent result objects:

                     if (conditionStringified.includes(conditionKey) && !conditionStringified.includes(conditionValue)){
                         message.push(`${property}: ${condition.value} not found in ${conditionStringified}`);
-                        return 0;
+                        let resultObj = { status: 0, message: message.join(', ') };
+                        inputResultsArr.push(resultObj);
+                        return resultObj;
                     } else {
                         message.push(`${condition.value} found in ${conditionStringified}`);
-                        return 2;
+                        let resultObj = { status: 2, message: message.join(', ') };
+                        inputResultsArr.push(resultObj);
+                        return resultObj;
                     }
                 } else if (conditionStringified && !conditionStringified.includes(condition.value)) {
                     message.push(`${property}: ${condition.value} not found in ${conditionStringified}`);
-                    return 0;
+                    let resultObj = { status: 0, message: message.join(', ') };
+                    inputResultsArr.push(resultObj);
+                    return resultObj;
                 } else if (conditionStringified && conditionStringified.length){
                     message.push(`${condition.value} found in ${conditionStringified}`);
-                    return 2;
+                    let resultObj = { status: 2, message: message.join(', ') };
+                    inputResultsArr.push(resultObj);
+                    return resultObj;
                 } else {
                     message.push(`${condition.parsed} is not the right property type for this operation`);
-                    return 2;
+                    let resultObj = { status: 2, message: message.join(', ') };
+                    inputResultsArr.push(resultObj);
+                    return resultObj;
                 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In helpers/asl/asl-1.js around lines 568 to 591, the NOTCONTAINS branch
currently returns raw numbers (0 or 2) instead of result objects; change each
return to return an object of the form { status: <number>, message } where
message is the same string pushed into the message array so callers can access
.status and .message consistently; ensure all five return points are updated to
return the object rather than the raw number.

package.json Outdated
"ali-oss": "^6.17.0",
"argparse": "^2.0.1",
"async": "^3.2.5",
"aws-sdk": "^2.1574.0",
Copy link

@coderabbitai coderabbitai bot Dec 3, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🌐 Web query:

AWS SDK for JavaScript v2 maintenance mode status 2025

💡 Result:

As of Dec 3, 2025 the AWS SDK for JavaScript v2 is past maintenance and has reached end-of-support: it entered maintenance mode on September 8, 2024 and reached end-of-support on September 8, 2025. [1][2]

Sources:

  • AWS Developer Tools blog announcement. [1]
  • AWS SDK for JavaScript v2 README / docs. [2]

🌐 Web query:

AWS SDK v2 vs v3 migration guide JavaScript 2025

💡 Result:

Summary—what changed and why migrate

  • v3 is a ground-up, TypeScript-first rewrite that is modular (one @aws-sdk/client-XXX package per service), uses a middleware stack, and drops the single monolithic aws-sdk package used by v2. Migrate for smaller bundles, better tree-shaking, first-class TypeScript, performance, and continued support (v2 is EoS Sep 8, 2025). [1][2][3]

Quick migration checklist (minimal, actionable)

  1. Read the official migration guide. [1]
  2. Run the codemod to convert imports/usage at scale:
    • Dry-run: npx aws-sdk-js-codemod@latest --dry --print -t v2-to-v3 PATH...
    • Apply: npx aws-sdk-js-codemod@latest -t v2-to-v3 PATH...
      (package: aws-sdk-js-codemod). [4][1]
  3. Replace aws-sdk imports with modular clients and Commands:
    • v2: import AWS from "aws-sdk"; const s3 = new AWS.S3(); await s3.getObject(params).promise();
    • v3: import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3"; const client = new S3Client(); await client.send(new GetObjectCommand(params));
      (Note: .promise() is removed; use client.send(...)). [1][5]
  4. Migrate higher-level helpers:
    • DynamoDB DocumentClient -> @aws-sdk/lib-dynamodb (marshall/unmarshall differences).
    • S3 multipart helpers -> @aws-sdk/lib-storage (Upload). [5]
  5. Update paginators & waiters to v3 APIs (they are separate helpers/commands). See v3 docs for service-specific changes. [1][5]
  6. Migrate custom request hooks to the v3 middleware stack (more explicit than v2 request event listeners). [1][5]
  7. Test thoroughly: unit + integration tests; validate streaming APIs (GetObject.Body handling differs between runtimes). [5]
  8. Update Node runtime if needed: v3 dropped Node.js 16.x support (effective Jan 6, 2025); target an Active LTS (Node 20+ recommended). [6]
  9. Remove aws-sdk from package.json and install only required @aws-sdk packages to reduce bundle size. [5]

Useful commands / packages

  • Codemod (recommended): npx aws-sdk-js-codemod -t v2-to-v3 PATH...
  • Common v3 packages:
    • Core client: @aws-sdk/client-s3, @aws-sdk/client-dynamodb, etc.
    • Helpers: @aws-sdk/lib-dynamodb, @aws-sdk/lib-storage, @aws-sdk/smithy-client (if needed).
  • v2 package (for reference only): aws-sdk (EoS Sep 8, 2025). [2][3]

Where to read more (official)

  • v3 migration guide (developer guide): [1]
  • v2 README / EoS announcement: [2][3]
  • Codemod npm + repo: [4]
  • v3 repo & README (modular design, examples): [5]
  • Node.js 16.x end-of-support announcement for v3: [6]

If you want, I can:

  • run the codemod on a sample file you paste, or
  • produce a small before/after conversion for specific services (S3, DynamoDB, Lambda).

Sources

  1. AWS SDK for JavaScript v3 — Migrate from v2.x to v3.x (Developer Guide). [AWS Docs].
  2. AWS SDK for JavaScript (v2) README — maintenance/EoS details. [AWS Docs / GitHub].
  3. AWS Developer Blog — Announcing end-of-support for AWS SDK for JavaScript v2 (Sep 8, 2025).
  4. aws-sdk-js-codemod (npm + GitHub) — v2-to-v3 codemod usage.
  5. aws-sdk-js-v3 GitHub README / Developer Guide (modular packages, middleware, helpers).
  6. AWS Developer Blog — v3 end of support for Node.js 16.x (effective Jan 6, 2025).

AWS SDK v2 has reached end-of-support as of September 8, 2025 and must be migrated.

The project uses aws-sdk v2, which is no longer maintained. Migrate to @aws-sdk/* v3 modular packages immediately for continued support, improved tree-shaking, performance, and TypeScript compatibility.

AWS provides an automated codemod for migration:

npx aws-sdk-js-codemod@latest -t v2-to-v3 <path>

See the official migration guide for details on API changes and higher-level helper migrations.

🤖 Prompt for AI Agents
In package.json around line 62, the project currently depends on the deprecated
"aws-sdk" v2; migrate to AWS SDK v3 by replacing that dependency with the
modular @aws-sdk/* packages required by your code (e.g., @aws-sdk/client-s3,
@aws-sdk/client-dynamodb, etc.), run the automated codemod to convert imports
and usages (npx aws-sdk-js-codemod@latest -t v2-to-v3 <path>), then update code
to use the new client constructors, command objects, and async send() calls or
higher-level helpers, adjust any changed option names and error handling, remove
the old aws-sdk entry from package.json, run npm install and full test suite /
linting to fix remaining call-signature or import errors, and commit the updated
dependencies and code changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
"aws-sdk": "^2.1574.0",
"aws-sdk": "^2.1574.0",

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Choose a reason for hiding this comment

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

Question:

suggestion aws-sdk: ^2.1574.0,

Answer:

If you want Qodo Merge to stop proposing “dependency bumps” like aws-sdk: ^2... (and instead focus on code-level issues in the PR diff), add tighter guidance to the /improve prompt:

[pr_code_suggestions]
extra_instructions = """\
- Do NOT suggest dependency version bumps in package.json/yarn.lock/pnpm-lock.yaml unless the PR is explicitly about dependency maintenance.
- Do NOT suggest migrations/replacements of major libraries (e.g., aws-sdk v2 -> v3) unless the PR already touches that dependency or the code changes clearly introduce a bug/security issue that requires it.
- Treat external “EOL/EOS” statements and web lookups as out of scope; base suggestions only on the PR diff and repository context.
- Prefer actionable, local code fixes over ecosystem-wide refactors.
"""

Optional (if you also want to reduce suggestions that touch config/metadata files):

[ignore]
glob = ["package.json", "*lock*", "*.toml"]

(Use this only if you’re comfortable excluding those files from analysis entirely; otherwise rely on extra_instructions.)

Relevant Sources:

Comment on lines 1 to 56
const async = require('async');
const helpers = require('../../../helpers/azure');

module.exports = {
title: 'Cosmos DB Managed Identity',
category: 'Cosmos DB',
domain: 'Databases',
severity: 'Medium',
description: 'Ensures that Azure Cosmos DB accounts have managed identity enabled.',
more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Entra ID tokens.',
link: 'https://learn.microsoft.com/en-us/azure/cosmos-db/managed-identity-based-authentication',
recommended_action: 'Enable system or user-assigned identities for all Azure Cosmos DB accounts.',
apis: ['databaseAccounts:list'],
realtime_triggers: ['microsoftdocumentdb:databaseaccounts:write','microsoftdocumentdb:databaseaccounts:delete'],

run: function(cache, settings, callback) {
const results = [];
const source = {};
const locations = helpers.locations(settings.govcloud);

async.each(locations.databaseAccounts, function(location, rcb) {
var databaseAccounts = helpers.addSource(cache, source,
['databaseAccounts', 'list', location]);

if (!databaseAccounts) return rcb();

if (databaseAccounts.err || !databaseAccounts.data) {
helpers.addResult(results, 3,
'Unable to query for Cosmos DB accounts: ' + helpers.addError(databaseAccounts), location);
return rcb();
}
}
}
};

describe('cosmosdbManagedIdentity', function() {
describe('run', function() {
it('should give passing result if no Cosmos DB accounts found', function(done) {
const callback = (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('No Cosmos DB accounts found');
expect(results[0].region).to.equal('eastus');
done()
};

const cache = createCache(
[]
);

cosmosdbManagedIdentity.run(cache, {}, callback);
});

it('should give passing result if Cosmos db has managed identity', function(done) {
const callback = (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('Cosmos DB account has managed identity enabled');
expect(results[0].region).to.equal('eastus');
done()
};

const cache = createCache(
[databaseAccounts[0]]
);

cosmosdbManagedIdentity.run(cache, {}, callback);
});

it('should give failing result if Azure Cosmos db does not have managed identity', function(done) {
const callback = (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(2);
expect(results[0].message).to.include('Cosmos DB account does not have managed identity enabled');
expect(results[0].region).to.equal('eastus');
done()
};

const cache = createCache(
[databaseAccounts[1]],
);

cosmosdbManagedIdentity.run(cache, {}, callback);
});
if (!databaseAccounts.data.length) {
helpers.addResult(results, 0, 'No Cosmos DB accounts found', location);
return rcb();
}

it('should give unknown result if unable to query for Cosmos DB accounts', function(done) {
const callback = (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(3);
expect(results[0].message).to.include('Unable to query for Cosmos DB accounts');
expect(results[0].region).to.equal('eastus');
done()
};
databaseAccounts.data.forEach(account => {
if (!account.id) return;

const cache = createCache(
[],
{ message: 'Unable to query Cosmos DB accounts'}
);
if (account.identity && account.identity.type &&
(account.identity.type.toLowerCase() === 'systemassigned' || account.identity.type.toLowerCase() === 'userassigned')) {
helpers.addResult(results, 0,
'Cosmos DB account has managed identity enabled', location, account.id);
} else {
helpers.addResult(results, 2,
'Cosmos DB account does not have managed identity enabled', location, account.id);
}
});

cosmosdbManagedIdentity.run(cache, {}, callback);
rcb();
}, function() {
callback(null, results, source);
});
})
});
}
}; No newline at end of file
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

File appears to be misnamed: .spec.js suffix typically indicates a test file.

This file contains the plugin implementation rather than tests. The .spec.js naming convention is universally used for test/specification files. Either:

  1. Rename this file to cosmosdbManagedIdentity.js and place it alongside other plugin implementations, or
  2. Restore test scaffolding to this file and move the implementation to a separate file.
#!/bin/bash
# Verify if there's a separate implementation file or if other plugins follow this pattern
fd -e js 'cosmosdbManagedIdentity' plugins/azure/cosmosdb/

# Check naming conventions of other Cosmos DB plugins
ls -la plugins/azure/cosmosdb/ | head -20

Comment on lines +363 to 405
_sendToSaaS: function(data, settings) {
const https = require('https');
const url = require('url');

const saasUrl = url.parse(settings.saas.endpoint);
const postData = JSON.stringify(data);

const options = {
hostname: saasUrl.hostname,
port: saasUrl.port || 443,
path: saasUrl.path,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData),
'Authorization': settings.saas.apiKey ? `Bearer ${settings.saas.apiKey}` : ''
}
};

const req = https.request(options, (res) => {
let responseData = '';

res.on('data', (chunk) => {
responseData += chunk;
});

res.on('end', () => {
if (res.statusCode >= 200 && res.statusCode < 300) {
log('INFO: Successfully sent data to SaaS platform', settings);
} else {
log(`WARN: Failed to send data to SaaS platform: ${res.statusCode} - ${responseData}`, settings);
}
});
});

req.on('error', (e) => {
log(`ERROR: Failed to send data to SaaS platform: ${e.message}`, settings);
});

// Write data to request body
req.write(postData);
req.end();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Multiple issues with the HTTP request implementation.

  1. No timeout: The request could hang indefinitely if the SaaS endpoint is unresponsive, potentially blocking process exit.
  2. Deprecated API: url.parse() is deprecated since Node.js 11; use new URL() instead.
  3. Empty Authorization header: Sending an empty Authorization header when no API key is configured may cause some servers to reject the request.
  4. Per static analysis: prefer node:https over https for clarity.

Apply this diff to address these issues:

         _sendToSaaS: function(data, settings) {
-            const https = require('https');
-            const url = require('url');
+            const https = require('node:https');
             
-            const saasUrl = url.parse(settings.saas.endpoint);
+            const saasUrl = new URL(settings.saas.endpoint);
             const postData = JSON.stringify(data);
             
+            const headers = {
+                'Content-Type': 'application/json',
+                'Content-Length': Buffer.byteLength(postData)
+            };
+            
+            if (settings.saas.apiKey) {
+                headers['Authorization'] = `Bearer ${settings.saas.apiKey}`;
+            }
+            
             const options = {
                 hostname: saasUrl.hostname,
                 port: saasUrl.port || 443,
-                path: saasUrl.path,
+                path: saasUrl.pathname + saasUrl.search,
                 method: 'POST',
-                headers: {
-                    'Content-Type': 'application/json',
-                    'Content-Length': Buffer.byteLength(postData),
-                    'Authorization': settings.saas.apiKey ? `Bearer ${settings.saas.apiKey}` : ''
-                }
+                headers: headers,
+                timeout: 30000 // 30 second timeout
             };
             
             const req = https.request(options, (res) => {
                 // ... existing response handling
             });
+            
+            req.on('timeout', () => {
+                req.destroy();
+                log('ERROR: SaaS request timed out', settings);
+            });
             
             req.on('error', (e) => {
                 log(`ERROR: Failed to send data to SaaS platform: ${e.message}`, settings);
             });
🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis

[warning] 364-364: Prefer node:https over https.

See more on https://sonarcloud.io/project/issues?id=khulnasoft_cloudexploit&issues=AZrlMxlMDnQ4yCTHoX17&open=AZrlMxlMDnQ4yCTHoX17&pullRequest=51

Comment on lines 77 to 83
## Installation
Ensure that NodeJS is installed. If not, install it from [here](https://nodejs.org/download/).

```
```bash
$ git clone git@github.com:cloudexploit/scans.git
$ npm install
```
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat README.md

Repository: khulnasoft/cloudexploit

Length of output: 190


🏁 Script executed:

# Search for git clone commands in common documentation files
fd -e md | head -20 | xargs rg "git clone" -A 2 2>/dev/null | head -50

Repository: khulnasoft/cloudexploit

Length of output: 190


Clone URL in Installation section is incorrect and will lead users to the wrong repository

The Installation section uses git@github.com:cloudexploit/scans.git, but the canonical repository is khulnasoft/cloudexploit (as shown in the Quick Start section). This mismatch will cause users to clone the wrong repository.

Align the Installation block with the Quick Start example:

-```bash
-$ git clone git@github.com:cloudexploit/scans.git
-$ npm install
-```
+```bash
+$ git clone https://github.com/khulnasoft/cloudexploit.git
+$ cd cloudexploit
+$ npm install
+```
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

77-77: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


78-78: Link text should be descriptive

(MD059, descriptive-link-text)


81-81: Dollar signs used before commands without showing output

(MD014, commands-show-output)


82-82: Dollar signs used before commands without showing output

(MD014, commands-show-output)

🤖 Prompt for AI Agents
In README.md around lines 77 to 83, the Installation section uses the wrong git
URL and missing cd step; update the clone line to the canonical repository URL
(https://github.com/khulnasoft/cloudexploit.git), add a step to change into the
cloned directory (cd cloudexploit), and keep the npm install step, ensuring the
fenced code block uses bash language tag and closes correctly.

envrs added 7 commits December 4, 2025 01:45
Signed-off-by: envrs <dr.lizadmf@gmail.com>
Signed-off-by: envrs <dr.lizadmf@gmail.com>
Signed-off-by: envrs <dr.lizadmf@gmail.com>
Signed-off-by: envrs <dr.lizadmf@gmail.com>
Signed-off-by: envrs <dr.lizadmf@gmail.com>
Signed-off-by: envrs <dr.lizadmf@gmail.com>
Signed-off-by: envrs <dr.lizadmf@gmail.com>
khulnasoft-bot and others added 4 commits February 17, 2026 01:19
Co-authored-by: envrs <230240030+envrs@users.noreply.github.com>
Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com>
Copy link

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/scans_ci.yml (1)

29-30: ⚠️ Potential issue | 🟠 Major

Add ESLint configuration to replace removed .eslintrc.json.

The .eslintrc.json has been removed, but no replacement ESLint configuration exists in the repository. While npm run lint will execute, it will run with ESLint's default rules instead of the project's intended standards. Either restore the configuration file or add an eslint.config.js (flat config format) or eslintConfig field in package.json.

🤖 Fix all issues with AI agents
In @.github/workflows/scans_ci.yml:
- Line 11: The workflow is missing the required GitHub Actions job hierarchy so
the steps (including the actions/checkout@v6 entry) are invalid; wrap the
existing steps under a jobs block (e.g., jobs: -> build: -> runs-on:
ubuntu-latest -> strategy: matrix: node-version: [18.x,20.x] -> steps:) so that
actions/checkout@v6 and subsequent step entries are nested under the steps:
array, and remove trailing spaces and fix spacing in branch arrays to satisfy
yamllint; update any step names or uses entries (like actions/setup-node@v6) as
needed to fit under the new job structure.

In `@helpers/asl/asl-1.js`:
- Around line 618-619: The equality semantics are inconsistent: when
condition.op is 'EQ' the code uses loose equality (condition.parsed ==
condition.value) while 'NE' uses strict !==; update the 'EQ' branch to use
strict equality so both operators are consistent. Locate the branches that check
condition.op === 'EQ' and condition.op === 'NE' and change the comparison to use
strict operators (use === for EQ and keep !== for NE) comparing condition.parsed
and condition.value.
- Around line 1072-1078: The call site shows parse(data, condition.property,
...) mutates condition.property (via shift), causing runValidation(data,
condition, ...) to operate on corrupted data; fix by making parse non-mutating:
inside the parse function (the parse(...) implementation) copy any array
arguments (e.g., property) before using shift/pop so the original
condition.property is not mutated, or as a quicker patch change this callsite to
pass a shallow copy (parse(data, Array.isArray(condition.property) ?
[...condition.property] : condition.property, region, cloud, accountId,
resourceName)); ensure runValidation(...) continues to receive the intact
condition.property and that parsedResource parsing still works.
- Around line 126-131: The mask calculation fails for prefixLength === 0 due to
JS shift wrapping; in the block that computes mask/networkInt/broadcastInt
(variables mask, prefixLength, networkInt, broadcastInt, cidrInt), guard the
shift by handling prefixLength === 0 explicitly (set mask to 0) or compute using
a branch that avoids shifting by 32, then recompute networkInt and broadcastInt
from that mask so a /0 CIDR yields mask 0 and the correct network/broadcast
values.
- Around line 1-11: The parse function is mutating caller-supplied path arrays
via path.shift(), corrupting callers like runConditions that pass
condition.property into parse and later call runValidation; fix by making a
shallow copy of path when it is already an array (e.g., path = path.slice() or
Array.from(path)) at the start of parse to ensure subsequent shifts operate on
the local copy, leaving condition.property (and other caller arrays)
intact—update parse() accordingly and verify callers runConditions and
runValidation no longer observe mutated property arrays.

In `@plugins/azure/cosmosdb/cosmosdbManagedIdentity.spec.js`:
- Line 10: The string assigned to more_info in the
cosmosdbManagedIdentity.spec.js test contains mixed terminology ("Azure AD" and
"Azure Entra ID"); update the more_info value so it consistently uses "Azure
Entra ID" throughout (modify the more_info property in the existing spec object)
to match the repo-wide rebranding.
🧹 Nitpick comments (2)
.github/workflows/scans_ci.yml (1)

19-24: Pin codetypo-actions to a specific version or commit SHA instead of @master.

Using @master means any breaking change pushed to that branch will immediately affect your CI. Pin to a release tag or commit SHA for reproducibility and supply-chain safety.

helpers/asl/asl-1.js (1)

610-616: if (sub.status) treats status 0 (PASS) as falsy — only failures propagate.

On line 613, sub.status of 0 is falsy in JavaScript, so passing sub-results never update conditionResult. While the initial value is 0 (pass), the intent seems to be "last status wins," which makes the truthiness check misleading. If a failing sub (status 2) is followed by a passing sub (status 0), the failure is silently retained — this may or may not be intended.

Consider using an explicit check:

-                            if (sub.status) conditionResult = sub.status;
+                            conditionResult = Math.max(conditionResult, sub.status);

or if "any fail → fail" is the intent, add a comment clarifying the behavior.

node-version: [12.x, 14.x, 16.x] # Test on multiple Node.js versions
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v6
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the full file with line numbers to see actual structure
cat -n .github/workflows/scans_ci.yml

Repository: khulnasoft/cloudexploit

Length of output: 1452


🏁 Script executed:

#!/bin/bash
# Validate YAML syntax
pip install yamllint -q 2>/dev/null
yamllint .github/workflows/scans_ci.yml 2>&1 || true

Repository: khulnasoft/cloudexploit

Length of output: 917


The workflow file is missing the required jobs: block structure and will not execute.

The file jumps directly from the on: trigger block (lines 1–9) to step definitions (lines 11–36) without the required jobs: / build: / runs-on: / strategy: / steps: hierarchy. This breaks the GitHub Actions YAML schema entirely.

YAMLlint confirms the syntax error at line 11:7: expected <block end>, but found '-'. The workflow will fail to parse.

Required fix: Wrap all steps (lines 11–36) within a proper job structure:

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18.x, 20.x]  # use supported LTS versions
    steps:
      - uses: actions/checkout@v6
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v6
        ...

Also address yamllint errors: remove trailing spaces (lines 12, 18, 25, 28, 31, 34) and fix spacing in branch arrays (lines 5, 7).

🧰 Tools
🪛 YAMLlint (1.38.0)

[error] 11-11: syntax error: expected , but found '-'

(syntax)

🤖 Prompt for AI Agents
In @.github/workflows/scans_ci.yml at line 11, The workflow is missing the
required GitHub Actions job hierarchy so the steps (including the
actions/checkout@v6 entry) are invalid; wrap the existing steps under a jobs
block (e.g., jobs: -> build: -> runs-on: ubuntu-latest -> strategy: matrix:
node-version: [18.x,20.x] -> steps:) so that actions/checkout@v6 and subsequent
step entries are nested under the steps: array, and remove trailing spaces and
fix spacing in branch arrays to satisfy yamllint; update any step names or uses
entries (like actions/setup-node@v6) as needed to fit under the new job
structure.

Comment on lines 1 to +11
var parse = function(obj, path, region, cloud, accountId, resourceId) {
//(Array.isArray(obj)) return [obj];
if (typeof path == 'string' && path.includes('.')) path = path.split('.');
if (Array.isArray(path) && path.length && typeof obj === 'object') {
// Enhanced path splitting: ensure [*] is always its own segment
if (typeof path === 'string') {
// Split on . but keep [*] as its own segment
// Example: networkAcls.ipRules[*].value => ['networkAcls', 'ipRules', '[*]', 'value']
path = path
.replace(/\[\*\]/g, '.[$*].') // temporarily mark wildcards
.split('.')
.filter(Boolean)
.map(seg => seg === '[$*]' ? '[*]' : seg); // restore wildcard
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

parse() mutates the path array via shift(), corrupting callers that pass arrays.

When path is already an array (not a string), line 14's path.shift() mutates it in place. This affects callers like runConditions (line 1074) where condition.property is passed directly — after parse() returns, condition.property is partially or fully emptied, causing the subsequent runValidation call on line 1076 to operate on a corrupted property path.

🐛 Proposed fix: copy the array before mutating
     if (typeof path === 'string') {
         // Split on . but keep [*] as its own segment
         // Example: networkAcls.ipRules[*].value => ['networkAcls', 'ipRules', '[*]', 'value']
         path = path
             .replace(/\[\*\]/g, '.[$*].') // temporarily mark wildcards
             .split('.')
             .filter(Boolean)
             .map(seg => seg === '[$*]' ? '[*]' : seg); // restore wildcard
+    } else if (Array.isArray(path)) {
+        path = path.slice(); // avoid mutating caller's array
     }
🤖 Prompt for AI Agents
In `@helpers/asl/asl-1.js` around lines 1 - 11, The parse function is mutating
caller-supplied path arrays via path.shift(), corrupting callers like
runConditions that pass condition.property into parse and later call
runValidation; fix by making a shallow copy of path when it is already an array
(e.g., path = path.slice() or Array.from(path)) at the start of parse to ensure
subsequent shifts operate on the local copy, leaving condition.property (and
other caller arrays) intact—update parse() accordingly and verify callers
runConditions and runValidation no longer observe mutated property arrays.

Comment on lines +618 to +619
} else if (condition.op == 'EQ') {
if (condition.parsed == condition.value) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Inconsistent equality semantics: EQ uses loose ==, NE uses strict !==.

Line 619 uses == (loose) for EQ, but line 664 uses !== (strict) for NE. This means EQ would consider "0" equal to 0, but NE would also consider them not-equal — both operators would simultaneously be true for the same pair. Use consistent comparison semantics.

♻️ Proposed fix: use strict equality for both
-                if (condition.parsed == condition.value) {
+                if (condition.parsed === condition.value) {

Also applies to: 663-664

🤖 Prompt for AI Agents
In `@helpers/asl/asl-1.js` around lines 618 - 619, The equality semantics are
inconsistent: when condition.op is 'EQ' the code uses loose equality
(condition.parsed == condition.value) while 'NE' uses strict !==; update the
'EQ' branch to use strict equality so both operators are consistent. Locate the
branches that check condition.op === 'EQ' and condition.op === 'NE' and change
the comparison to use strict operators (use === for EQ and keep !== for NE)
comparing condition.parsed and condition.value.

Comment on lines +1072 to +1078
} else if (condition.property && condition.property.includes('[*]')) {
// For wildcard properties, parse once and validate the result
const parseResult = parse(data, condition.property, region, cloud, accountId, resourceName);
condition.parsed = parseResult;
condition.validated = runValidation(data, condition, inputResultsArr, null, region, cloud, accountId, resourceName);
parsedResource = parse(data, resourcePath, region, cloud, accountId, resourceName);
if (typeof parsedResource !== 'string' || parsedResource === 'not set') parsedResource = resourceName;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

parse() on line 1074 mutates condition.property, breaking the subsequent runValidation call.

For wildcard properties, parse(data, condition.property, ...) is called on line 1074 which mutates the array via shift(). Then runValidation(data, condition, ...) on line 1076 receives the same condition object with a now-empty or truncated property array. Inside runValidation, checks against condition.property (e.g., line 415) and the second parse() call (line 410) will operate on corrupted data.

This is the downstream effect of the parse() mutation issue flagged at lines 1-11. If the proposed fix to copy the array inside parse() is applied, this call site is automatically fixed.

🤖 Prompt for AI Agents
In `@helpers/asl/asl-1.js` around lines 1072 - 1078, The call site shows
parse(data, condition.property, ...) mutates condition.property (via shift),
causing runValidation(data, condition, ...) to operate on corrupted data; fix by
making parse non-mutating: inside the parse function (the parse(...)
implementation) copy any array arguments (e.g., property) before using shift/pop
so the original condition.property is not mutated, or as a quicker patch change
this callsite to pass a shallow copy (parse(data,
Array.isArray(condition.property) ? [...condition.property] :
condition.property, region, cloud, accountId, resourceName)); ensure
runValidation(...) continues to receive the intact condition.property and that
parsedResource parsing still works.

khulnasoft-bot and others added 2 commits February 17, 2026 01:32
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com>
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot
19.3% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants