Compare commits

4 Commits

Author SHA1 Message Date
Henrik Jess Nielsen
b8eb1d8085 feat(bicep): add all 682 Azure roles from rbaclookup module
All checks were successful
Build and Deploy iLSP / test (push) Successful in 23s
Build and Deploy iLSP / build-and-deploy (push) Successful in 1m32s
Replaces hardcoded 38 roles with complete list extracted from
bicep/lookup/rbaclookup:2.x module.

Changes:
- Add scripts/extract_roles_from_rbaclookup.py to parse rbacLookup.bicep
- Generate ilsp/bicep_lsp/azure_roles.json with 682 role names
- Load roles dynamically in modules.py from JSON file
- Now supports ALL Azure built-in roles for autocomplete

Benefits:
- Complete Azure RBAC coverage (682 vs 38 roles)
- Easy to update when new roles are added to rbaclookup module
- Cleaner code (no giant hardcoded list in modules.py)

Usage to update roles:
  python3 scripts/extract_roles_from_rbaclookup.py /path/to/rbacLookup.bicep

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-19 14:27:00 +02:00
Henrik Jess Nielsen
578f88a0e8 fix(bicep): support multi-line array completion for roles and other enums
All checks were successful
Build and Deploy iLSP / test (push) Successful in 22s
Build and Deploy iLSP / build-and-deploy (push) Successful in 1m35s
Adds support for autocomplete in multi-line array syntax like:

    roles: [
      'KEY_VAULT_  ← cursor triggers completion here
    ]

Previously only worked on same line as opening bracket:
    roles: ['KEY_VAULT_  ← only this worked

Changes:
- Walk backwards up to 10 lines to find array opening (e.g. "roles: [")
- Detect if cursor is inside array based on indentation and quotes
- Stop lookback if closing bracket found (not in array anymore)
- Add test case for nested multi-line array completion
- Improve lsp_bridge.py error handling with traceback logging
- Add lsp_bridge_debug.sh wrapper for easier IntelliJ debugging
- Update EDITOR_SETUP.md with correct IntelliJ LSP4IJ config

Fixes autocomplete for deeply nested structures like:
    assignments: [{ roles: ['APP_CONFIGURATION_...'] }]

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-19 13:51:17 +02:00
Henrik Jess Nielsen
d4cb9ae8fb Roles
All checks were successful
Build and Deploy iLSP / test (push) Successful in 21s
Build and Deploy iLSP / build-and-deploy (push) Successful in 48s
2026-05-19 11:46:54 +02:00
Henrik Jess Nielsen
aa37c259ad Roles
All checks were successful
Build and Deploy iLSP / test (push) Successful in 23s
Build and Deploy iLSP / build-and-deploy (push) Successful in 3m13s
2026-05-19 10:28:22 +02:00
8 changed files with 988 additions and 14 deletions

View File

@@ -14,17 +14,49 @@ supports LSP WebSocket transport.
## IntelliJ IDEA setup (LSP4IJ) ## IntelliJ IDEA setup (LSP4IJ)
Install the [LSP4IJ](https://plugins.jetbrains.com/plugin/23257-lsp4ij) plugin, then: Install the [LSP4IJ](https://plugins.jetbrains.com/plugin/23257-lsp4ij) plugin, then add language servers:
### Bicep
1. **Settings → Languages & Frameworks → LSP → Language Servers → +** 1. **Settings → Languages & Frameworks → LSP → Language Servers → +**
- Name: `iLSP Bicep` - Name: `iLSP Bicep`
- Server type: `WebSocket` - Server type: `Command` (not WebSocket — see note below)
- URL: `wss://ilsp.i80.dk/bicep` - Command: `/Users/lrihni/Projects/iLSP/scripts/lsp_bridge_debug.sh wss://ilsp.i80.dk/bicep`
- Arguments: (leave blank)
- File pattern: `*.bicep;*.bicepparam`
2. **Add a file-type mapping** under the new server entry: ### YAML (Azure DevOps + GitHub Actions)
- File type: `Bicep` (or pattern `*.bicep`)
3. **Disable Azure Toolkit Bicep completions** — this is critical if you have the 2. **Settings → Languages & Frameworks → LSP → Language Servers → +**
- Name: `iLSP YAML`
- Server type: `Command`
- Command: `/Users/lrihni/Projects/iLSP/scripts/lsp_bridge_debug.sh wss://ilsp.i80.dk/yaml`
- Arguments: (leave blank)
- File pattern: `*.yaml;*.yml;azure-pipelines.yml`
### Python (optional)
3. **Settings → Languages & Frameworks → LSP → Language Servers → +**
- Name: `iLSP Python`
- Server type: `Command`
- Command: `/Users/lrihni/Projects/iLSP/scripts/lsp_bridge_debug.sh wss://ilsp.i80.dk/python`
- Arguments: (leave blank)
- File pattern: `*.py`
> **Note**: LSP4IJ's WebSocket mode doesn't handle LSP Content-Length framing correctly,
> causing "starting..." to hang or "Stream closed" errors. Use `lsp_bridge_debug.sh` wrapper
> which calls `lsp_bridge.py` and logs errors to `/tmp/lsp_bridge_debug.log` for debugging.
### Troubleshooting
If the language server doesn't start, check the debug log:
```bash
tail -f /tmp/lsp_bridge_debug.log
```
### Disable conflicting plugins
**Disable Azure Toolkit Bicep completions** — this is critical if you have the
Azure Toolkit plugin installed. Without this step, IDEA merges completions from Azure Toolkit plugin installed. Without this step, IDEA merges completions from
both LSP4IJ and Azure Toolkit, resulting in noisy suggestions (`resource`, both LSP4IJ and Azure Toolkit, resulting in noisy suggestions (`resource`,
`projectName`, Bicep schema types, etc.) appearing alongside iLSP results. `projectName`, Bicep schema types, etc.) appearing alongside iLSP results.

View File

@@ -0,0 +1,684 @@
[
"ACCESS_REVIEW_OPERATOR_SERVICE_ROLE",
"ACRDELETE",
"ACRIMAGESIGNER",
"ACRPULL",
"ACRPUSH",
"ACRQUARANTINEREADER",
"ACRQUARANTINEWRITER",
"ADVISOR_RECOMMENDATIONS_CONTRIBUTOR_ASSESSMENTS_AND_REVIEWS",
"ADVISOR_REVIEWS_CONTRIBUTOR",
"ADVISOR_REVIEWS_READER",
"AGENTLESS_SCANNING_FOR_SERVERLESS_SCANNER_SERVICE_ROLE",
"AGFOOD_PLATFORM_DATASET_ADMIN",
"AGFOOD_PLATFORM_SENSOR_PARTNER_CONTRIBUTOR",
"AGFOOD_PLATFORM_SERVICE_ADMIN",
"AGFOOD_PLATFORM_SERVICE_CONTRIBUTOR",
"AGFOOD_PLATFORM_SERVICE_READER",
"ANYBUILD_BUILDER",
"API_MANAGEMENT_DEVELOPER_PORTAL_CONTENT_EDITOR",
"API_MANAGEMENT_SERVICE_CONTRIBUTOR",
"API_MANAGEMENT_SERVICE_OPERATOR_ROLE",
"API_MANAGEMENT_SERVICE_READER_ROLE",
"API_MANAGEMENT_SERVICE_WORKSPACE_API_DEVELOPER",
"API_MANAGEMENT_SERVICE_WORKSPACE_API_PRODUCT_MANAGER",
"API_MANAGEMENT_WORKSPACE_API_DEVELOPER",
"API_MANAGEMENT_WORKSPACE_API_PRODUCT_MANAGER",
"API_MANAGEMENT_WORKSPACE_CONTRIBUTOR",
"API_MANAGEMENT_WORKSPACE_READER",
"APPGW_FOR_CONTAINERS_CONFIGURATION_MANAGER",
"APPLICATION_GROUP_CONTRIBUTOR",
"APPLICATION_INSIGHTS_COMPONENT_CONTRIBUTOR",
"APPLICATION_INSIGHTS_SNAPSHOT_DEBUGGER",
"APP_COMPLIANCE_AUTOMATION_ADMINISTRATOR",
"APP_COMPLIANCE_AUTOMATION_READER",
"APP_CONFIGURATION_CONTRIBUTOR",
"APP_CONFIGURATION_DATA_OWNER",
"APP_CONFIGURATION_DATA_READER",
"APP_CONFIGURATION_DATA_SAS_USER",
"APP_CONFIGURATION_READER",
"APP_SERVICE_ENVIRONMENT_CONTRIBUTOR",
"ARC_GATEWAY_MANAGER",
"ATTESTATION_CONTRIBUTOR",
"ATTESTATION_READER",
"AUTOMATION_CONTRIBUTOR",
"AUTOMATION_JOB_OPERATOR",
"AUTOMATION_OPERATOR",
"AUTOMATION_RUNBOOK_OPERATOR",
"AUTONOMOUS_DEVELOPMENT_PLATFORM_DATA_CONTRIBUTOR_PREVIEW",
"AUTONOMOUS_DEVELOPMENT_PLATFORM_DATA_OWNER_PREVIEW",
"AUTONOMOUS_DEVELOPMENT_PLATFORM_DATA_READER_PREVIEW",
"AUTO_ACTIONS_CONTRIBUTOR",
"AVERE_CONTRIBUTOR",
"AVERE_OPERATOR",
"AVS_ON_FLEET_VIS_ROLE",
"AVS_ORCHESTRATOR_ROLE",
"AZUREML_COMPUTE_OPERATOR",
"AZUREML_DATA_SCIENTIST",
"AZUREML_METRICS_WRITER_PREVIEW",
"AZUREML_REGISTRY_USER",
"AZURE_AI_ACCOUNT_OWNER",
"AZURE_AI_ADMINISTRATOR",
"AZURE_AI_DEVELOPER",
"AZURE_AI_ENTERPRISE_NETWORK_CONNECTION_APPROVER",
"AZURE_AI_INFERENCE_DEPLOYMENT_OPERATOR",
"AZURE_AI_PROJECT_MANAGER",
"AZURE_AI_SAFETY_EVALUATOR",
"AZURE_AI_USER",
"AZURE_API_CENTER_COMPLIANCE_MANAGER",
"AZURE_API_CENTER_CREDENTIAL_ACCESS_READER",
"AZURE_API_CENTER_DATA_READER",
"AZURE_API_CENTER_SERVICE_CONTRIBUTOR",
"AZURE_API_CENTER_SERVICE_READER",
"AZURE_ARC_ENABLED_KUBERNETES_CLUSTER_USER_ROLE",
"AZURE_ARC_KUBERNETES_ADMIN",
"AZURE_ARC_KUBERNETES_CLUSTER_ADMIN",
"AZURE_ARC_KUBERNETES_VIEWER",
"AZURE_ARC_KUBERNETES_WRITER",
"AZURE_ARC_SCVMM_ADMINISTRATOR_ROLE",
"AZURE_ARC_SCVMM_PRIVATE_CLOUDS_ONBOARDING",
"AZURE_ARC_SCVMM_PRIVATE_CLOUD_USER",
"AZURE_ARC_SCVMM_VM_CONTRIBUTOR",
"AZURE_ARC_VMWARE_ADMINISTRATOR_ROLE",
"AZURE_ARC_VMWARE_PRIVATE_CLOUDS_ONBOARDING",
"AZURE_ARC_VMWARE_PRIVATE_CLOUD_USER",
"AZURE_ARC_VMWARE_VM_CONTRIBUTOR",
"AZURE_AUTOMANAGE_CONTRIBUTOR",
"AZURE_BACKUP_SNAPSHOT_CONTRIBUTOR",
"AZURE_BATCH_ACCOUNT_CONTRIBUTOR",
"AZURE_BATCH_ACCOUNT_READER",
"AZURE_BATCH_DATA_CONTRIBUTOR",
"AZURE_BATCH_JOB_SUBMITTER",
"AZURE_BATCH_SERVICE_ORCHESTRATION_ROLE",
"AZURE_BOT_SERVICE_CONTRIBUTOR_ROLE",
"AZURE_CENTER_FOR_SAP_SOLUTIONS_ADMINISTRATOR",
"AZURE_CENTER_FOR_SAP_SOLUTIONS_MANAGEMENT_ROLE",
"AZURE_CENTER_FOR_SAP_SOLUTIONS_READER",
"AZURE_CENTER_FOR_SAP_SOLUTIONS_SERVICE_ROLE",
"AZURE_CENTER_FOR_SAP_SOLUTIONS_SERVICE_ROLE_FOR_MANAGEMENT",
"AZURE_CONNECTED_MACHINE_ONBOARDING",
"AZURE_CONNECTED_MACHINE_RESOURCE_ADMINISTRATOR",
"AZURE_CONNECTED_MACHINE_RESOURCE_MANAGER",
"AZURE_CONNECTED_SQL_SERVER_ONBOARDING",
"AZURE_CONTAINERAPPS_SESSION_EXECUTOR",
"AZURE_CONTAINER_INSTANCES_CONTRIBUTOR_ROLE",
"AZURE_CONTAINER_REGISTRY_SECURE_SUPPLY_CHAIN_OPERATOR_SERVICE_ROLE",
"AZURE_CONTAINER_STORAGE_CONTRIBUTOR",
"AZURE_CONTAINER_STORAGE_OPERATOR",
"AZURE_CONTAINER_STORAGE_OWNER",
"AZURE_CUSTOMER_LOCKBOX_APPROVER_FOR_SUBSCRIPTION",
"AZURE_DEPLOYMENT_STACK_CONTRIBUTOR",
"AZURE_DEPLOYMENT_STACK_OWNER",
"AZURE_DEVICE_ONBOARDING_DISCOVERY_CONTRIBUTOR",
"AZURE_DEVICE_UPDATE_AGENT",
"AZURE_DIGITAL_TWINS_DATA_OWNER",
"AZURE_DIGITAL_TWINS_DATA_READER",
"AZURE_EDGE_HARDWARE_CENTER_ADMINISTRATOR",
"AZURE_EDGE_ON_SITE_DEPLOYMENT_ENGINEER",
"AZURE_EVENT_HUBS_DATA_OWNER",
"AZURE_EVENT_HUBS_DATA_RECEIVER",
"AZURE_EVENT_HUBS_DATA_SENDER",
"AZURE_EXTENSION_FOR_SQL_SERVER_DEPLOYMENT",
"AZURE_FILE_SYNC_ADMINISTRATOR",
"AZURE_FILE_SYNC_READER",
"AZURE_FRONT_DOOR_DOMAIN_CONTRIBUTOR",
"AZURE_FRONT_DOOR_DOMAIN_READER",
"AZURE_FRONT_DOOR_PROFILE_READER",
"AZURE_FRONT_DOOR_SECRET_CONTRIBUTOR",
"AZURE_FRONT_DOOR_SECRET_READER",
"AZURE_HYBRID_DATABASE_ADMINISTRATOR_READ_ONLY_SERVICE_ROLE",
"AZURE_IMPACT_INSIGHT_READER",
"AZURE_KUBERNETES_FLEET_MANAGER_CONTRIBUTOR_ROLE",
"AZURE_KUBERNETES_FLEET_MANAGER_HUB_AGENT_ROLE",
"AZURE_KUBERNETES_FLEET_MANAGER_RBAC_ADMIN",
"AZURE_KUBERNETES_FLEET_MANAGER_RBAC_CLUSTER_ADMIN",
"AZURE_KUBERNETES_FLEET_MANAGER_RBAC_CLUSTER_READER",
"AZURE_KUBERNETES_FLEET_MANAGER_RBAC_CLUSTER_WRITER",
"AZURE_KUBERNETES_FLEET_MANAGER_RBAC_READER",
"AZURE_KUBERNETES_FLEET_MANAGER_RBAC_WRITER",
"AZURE_KUBERNETES_SERVICE_AGENT_POOL_MANAGER_ROLE",
"AZURE_KUBERNETES_SERVICE_ARC_CLUSTER_ADMIN_ROLE",
"AZURE_KUBERNETES_SERVICE_ARC_CLUSTER_USER_ROLE",
"AZURE_KUBERNETES_SERVICE_ARC_CONTRIBUTOR_ROLE",
"AZURE_KUBERNETES_SERVICE_CLUSTER_ADMIN_ROLE",
"AZURE_KUBERNETES_SERVICE_CLUSTER_MONITORING_USER",
"AZURE_KUBERNETES_SERVICE_CLUSTER_USER_ROLE",
"AZURE_KUBERNETES_SERVICE_CONTRIBUTOR_ROLE",
"AZURE_KUBERNETES_SERVICE_HYBRID_CLUSTER_ADMIN_ROLE",
"AZURE_KUBERNETES_SERVICE_HYBRID_CLUSTER_USER_ROLE",
"AZURE_KUBERNETES_SERVICE_HYBRID_CONTRIBUTOR_ROLE",
"AZURE_KUBERNETES_SERVICE_POLICY_ADD_ON_DEPLOYMENT",
"AZURE_KUBERNETES_SERVICE_RBAC_ADMIN",
"AZURE_KUBERNETES_SERVICE_RBAC_CLUSTER_ADMIN",
"AZURE_KUBERNETES_SERVICE_RBAC_READER",
"AZURE_KUBERNETES_SERVICE_RBAC_WRITER",
"AZURE_MACHINE_LEARNING_WORKSPACE_CONNECTION_SECRETS_READER",
"AZURE_MANAGED_GRAFANA_WORKSPACE_CONTRIBUTOR",
"AZURE_MAPS_CONTRIBUTOR",
"AZURE_MAPS_DATA_CONTRIBUTOR",
"AZURE_MAPS_DATA_READER",
"AZURE_MAPS_DATA_READ_AND_BATCH_ROLE",
"AZURE_MAPS_SEARCH_AND_RENDER_DATA_READER",
"AZURE_MESSAGING_CATALOG_DATA_OWNER",
"AZURE_MESSAGING_CONNECTORS_OWNER",
"AZURE_MONITOR_DASHBOARDS_WITH_GRAFANA_CONTRIBUTOR",
"AZURE_PROGRAMMABLE_CONNECTIVITY_GATEWAY_DATAPLANE_USER",
"AZURE_PROGRAMMABLE_CONNECTIVITY_GATEWAY_USER",
"AZURE_RED_HAT_OPENSHIFT_CLOUD_CONTROLLER_MANAGER",
"AZURE_RED_HAT_OPENSHIFT_CLUSTER_INGRESS_OPERATOR",
"AZURE_RED_HAT_OPENSHIFT_DISK_STORAGE_OPERATOR",
"AZURE_RED_HAT_OPENSHIFT_FEDERATED_CREDENTIAL",
"AZURE_RED_HAT_OPENSHIFT_FILE_STORAGE_OPERATOR",
"AZURE_RED_HAT_OPENSHIFT_HOSTED_CONTROL_PLANES_CLUSTER_API_PROVIDER",
"AZURE_RED_HAT_OPENSHIFT_HOSTED_CONTROL_PLANES_CONTROL_PLANE_OPERATOR",
"AZURE_RED_HAT_OPENSHIFT_HOSTED_CONTROL_PLANES_SERVICE_MANAGED_IDENTITY",
"AZURE_RED_HAT_OPENSHIFT_IMAGE_REGISTRY_OPERATOR",
"AZURE_RED_HAT_OPENSHIFT_MACHINE_API_OPERATOR",
"AZURE_RED_HAT_OPENSHIFT_NETWORK_OPERATOR",
"AZURE_RED_HAT_OPENSHIFT_SERVICE_OPERATOR",
"AZURE_RELAY_LISTENER",
"AZURE_RELAY_OWNER",
"AZURE_RELAY_SENDER",
"AZURE_RESOURCE_BRIDGE_DEPLOYMENT_ROLE",
"AZURE_RESOURCE_NOTIFICATIONS_SYSTEM_TOPICS_SUBSCRIBER",
"AZURE_SERVICE_BUS_DATA_OWNER",
"AZURE_SERVICE_BUS_DATA_RECEIVER",
"AZURE_SERVICE_BUS_DATA_SENDER",
"AZURE_SPHERE_CONTRIBUTOR",
"AZURE_SPHERE_OWNER",
"AZURE_SPHERE_PUBLISHER",
"AZURE_SPHERE_READER",
"AZURE_SPRING_APPS_APPLICATION_CONFIGURATION_SERVICE_CONFIG_FILE_PATTERN_READER_ROLE",
"AZURE_SPRING_APPS_APPLICATION_CONFIGURATION_SERVICE_LOG_READER_ROLE",
"AZURE_SPRING_APPS_CONNECT_ROLE",
"AZURE_SPRING_APPS_JOB_EXECUTION_INSTANCE_LIST_ROLE",
"AZURE_SPRING_APPS_JOB_LOG_READER_ROLE",
"AZURE_SPRING_APPS_MANAGED_COMPONENTS_LOG_READER_ROLE",
"AZURE_SPRING_APPS_REMOTE_DEBUGGING_ROLE",
"AZURE_SPRING_APPS_SPRING_CLOUD_CONFIG_SERVER_LOG_READER_ROLE",
"AZURE_SPRING_APPS_SPRING_CLOUD_GATEWAY_LOG_READER_ROLE",
"AZURE_SPRING_CLOUD_CONFIG_SERVER_CONTRIBUTOR",
"AZURE_SPRING_CLOUD_CONFIG_SERVER_READER",
"AZURE_SPRING_CLOUD_DATA_READER",
"AZURE_SPRING_CLOUD_SERVICE_REGISTRY_CONTRIBUTOR",
"AZURE_SPRING_CLOUD_SERVICE_REGISTRY_READER",
"AZURE_STACK_HCI_ADMINISTRATOR",
"AZURE_STACK_HCI_CONNECTED_INFRAVMS",
"AZURE_STACK_HCI_DEVICE_MANAGEMENT_ROLE",
"AZURE_STACK_HCI_EDGE_MACHINE_CONTRIBUTOR_ROLE",
"AZURE_STACK_HCI_VM_CONTRIBUTOR",
"AZURE_STACK_HCI_VM_READER",
"AZURE_STACK_REGISTRATION_OWNER",
"AZURE_USAGE_BILLING_DATA_SENDER",
"AZURE_VM_MANAGED_IDENTITIES_RESTORE_CONTRIBUTOR",
"BACKUP_CONTRIBUTOR",
"BACKUP_MUA_ADMIN",
"BACKUP_MUA_OPERATOR",
"BACKUP_OPERATOR",
"BACKUP_READER",
"BAYER_AG_POWERED_SERVICES_CROP_ID_SOLUTION_USER_ROLE",
"BAYER_AG_POWERED_SERVICES_CWUM_SOLUTION",
"BAYER_AG_POWERED_SERVICES_FIELD_IMAGERY_SOLUTION_SERVICE_ROLE",
"BAYER_AG_POWERED_SERVICES_GDU_SOLUTION",
"BAYER_AG_POWERED_SERVICES_HISTORICAL_WEATHER_DATA_SOLUTION_USER_ROLE",
"BAYER_AG_POWERED_SERVICES_IMAGERY_SOLUTION",
"BAYER_AG_POWERED_SERVICES_SMART_BOUNDARY_SOLUTION_USER_ROLE",
"BILLING_READER",
"BIZTALK_CONTRIBUTOR",
"BLOCKCHAIN_MEMBER_NODE_ACCESS_PREVIEW",
"BLUEPRINT_CONTRIBUTOR",
"BLUEPRINT_OPERATOR",
"CARBON_OPTIMIZATION_READER",
"CDN_ENDPOINT_CONTRIBUTOR",
"CDN_ENDPOINT_READER",
"CDN_PROFILE_CONTRIBUTOR",
"CDN_PROFILE_READER",
"CHAOS_STUDIO_EXPERIMENT_CONTRIBUTOR",
"CHAOS_STUDIO_OPERATOR",
"CHAOS_STUDIO_READER",
"CHAOS_STUDIO_TARGET_CONTRIBUTOR",
"CLASSIC_NETWORK_CONTRIBUTOR",
"CLASSIC_STORAGE_ACCOUNT_CONTRIBUTOR",
"CLASSIC_STORAGE_ACCOUNT_KEY_OPERATOR_SERVICE_ROLE",
"CLASSIC_VIRTUAL_MACHINE_CONTRIBUTOR",
"CLEARDB_MYSQL_DB_CONTRIBUTOR",
"CLOUDTEST_CONTRIBUTOR_ROLE",
"COGNITIVE_SEARCH_SERVERLESS_DATA_CONTRIBUTOR_DEPRECATED",
"COGNITIVE_SEARCH_SERVERLESS_DATA_READER_DEPRECATED",
"COGNITIVE_SERVICES_CONTRIBUTOR",
"COGNITIVE_SERVICES_CUSTOM_VISION_CONTRIBUTOR",
"COGNITIVE_SERVICES_CUSTOM_VISION_DEPLOYMENT",
"COGNITIVE_SERVICES_CUSTOM_VISION_LABELER",
"COGNITIVE_SERVICES_CUSTOM_VISION_READER",
"COGNITIVE_SERVICES_CUSTOM_VISION_TRAINER",
"COGNITIVE_SERVICES_DATA_CONTRIBUTOR_PREVIEW",
"COGNITIVE_SERVICES_DATA_READER",
"COGNITIVE_SERVICES_FACE_CONTRIBUTOR",
"COGNITIVE_SERVICES_FACE_RECOGNIZER",
"COGNITIVE_SERVICES_IMMERSIVE_READER_USER",
"COGNITIVE_SERVICES_LANGUAGE_OWNER",
"COGNITIVE_SERVICES_LANGUAGE_READER",
"COGNITIVE_SERVICES_LANGUAGE_WRITER",
"COGNITIVE_SERVICES_LUIS_OWNER",
"COGNITIVE_SERVICES_LUIS_READER",
"COGNITIVE_SERVICES_LUIS_WRITER",
"COGNITIVE_SERVICES_METRICS_ADVISOR_ADMINISTRATOR",
"COGNITIVE_SERVICES_METRICS_ADVISOR_USER",
"COGNITIVE_SERVICES_OPENAI_CONTRIBUTOR",
"COGNITIVE_SERVICES_OPENAI_USER",
"COGNITIVE_SERVICES_QNA_MAKER_EDITOR",
"COGNITIVE_SERVICES_QNA_MAKER_READER",
"COGNITIVE_SERVICES_SPEECH_CONTRIBUTOR",
"COGNITIVE_SERVICES_SPEECH_USER",
"COGNITIVE_SERVICES_USAGES_READER",
"COGNITIVE_SERVICES_USER",
"COLLABORATIVE_DATA_CONTRIBUTOR",
"COLLABORATIVE_RUNTIME_OPERATOR",
"COMMUNICATION_AND_EMAIL_SERVICE_OWNER",
"COMMUNITY_CONTRIBUTOR_ROLE",
"COMMUNITY_OWNER_ROLE",
"COMMUNITY_READER_ROLE",
"COMPUTE_DIAGNOSTICS_ROLE",
"COMPUTE_FLEET_CONTRIBUTOR",
"COMPUTE_GALLERY_ARTIFACTS_PUBLISHER",
"COMPUTE_GALLERY_IMAGE_READER",
"COMPUTE_GALLERY_SHARING_ADMIN",
"COMPUTE_RECOMMENDATIONS_ROLE",
"CONNECTED_CLUSTER_MANAGED_IDENTITY_CHECKACCESS_READER",
"CONNECTOR_READER",
"CONTAINERAPP_READER",
"CONTAINER_APPS_CONNECTEDENVIRONMENTS_CONTRIBUTOR",
"CONTAINER_APPS_CONNECTEDENVIRONMENTS_READER",
"CONTAINER_APPS_CONTRIBUTOR",
"CONTAINER_APPS_JOBS_CONTRIBUTOR",
"CONTAINER_APPS_JOBS_OPERATOR",
"CONTAINER_APPS_JOBS_READER",
"CONTAINER_APPS_MANAGEDENVIRONMENTS_CONTRIBUTOR",
"CONTAINER_APPS_MANAGEDENVIRONMENTS_READER",
"CONTAINER_APPS_OPERATOR",
"CONTAINER_APPS_SESSIONPOOLS_CONTRIBUTOR",
"CONTAINER_APPS_SESSIONPOOLS_READER",
"CONTAINER_INSTANCES_CONTRIBUTOR",
"CONTAINER_REGISTRY_CACHE_RULE_ADMINISTRATOR",
"CONTAINER_REGISTRY_CACHE_RULE_READER",
"CONTAINER_REGISTRY_CONFIGURATION_READER_AND_DATA_ACCESS_CONFIGURATION_READER",
"CONTAINER_REGISTRY_CONTRIBUTOR_AND_DATA_ACCESS_CONFIGURATION_ADMINISTRATOR",
"CONTAINER_REGISTRY_CREDENTIAL_SET_ADMINISTRATOR",
"CONTAINER_REGISTRY_CREDENTIAL_SET_READER",
"CONTAINER_REGISTRY_DATA_IMPORTER_AND_DATA_READER",
"CONTAINER_REGISTRY_REPOSITORY_CATALOG_LISTER",
"CONTAINER_REGISTRY_REPOSITORY_CONTRIBUTOR",
"CONTAINER_REGISTRY_REPOSITORY_READER",
"CONTAINER_REGISTRY_REPOSITORY_WRITER",
"CONTAINER_REGISTRY_TASKS_CONTRIBUTOR",
"CONTAINER_REGISTRY_TRANSFER_PIPELINE_CONTRIBUTOR",
"CONTRIBUTOR",
"COSMOSBACKUPOPERATOR",
"COSMOSRESTOREOPERATOR",
"COSMOS_DB_ACCOUNT_READER_ROLE",
"COSMOS_DB_OPERATOR",
"COST_MANAGEMENT_CONTRIBUTOR",
"COST_MANAGEMENT_READER",
"CROSSCONNECTIONMANAGER",
"CROSSCONNECTIONREADER",
"CUSTOM_AUTOMATION_ROLE_ROOT",
"DATA_BOUNDARY_TENANT_ADMINISTRATOR",
"DATA_BOX_CONTRIBUTOR",
"DATA_BOX_READER",
"DATA_FACTORY_CONTRIBUTOR",
"DATA_LABELING_LABELER",
"DATA_LAKE_ANALYTICS_DEVELOPER",
"DATA_OPERATOR_FOR_MANAGED_DISKS",
"DATA_PURGER",
"DEDICATED_HOST_CONTRIBUTOR_ROLE",
"DEFENDER_CSPM_STORAGE_DATA_SCANNER",
"DEFENDER_CSPM_STORAGE_SCANNER_OPERATOR",
"DEFENDER_FOR_STORAGE_DATA_SCANNER",
"DEFENDER_FOR_STORAGE_SCANNER_OPERATOR",
"DEFENDER_KUBERNETES_AGENT_OPERATOR",
"DEID_BATCH_DATA_OWNER",
"DEID_BATCH_DATA_READER",
"DEID_DATA_OWNER",
"DEID_REALTIME_DATA_USER",
"DEPLOYMENT_ENVIRONMENTS_READER",
"DEPLOYMENT_ENVIRONMENTS_USER",
"DESKTOP_VIRTUALIZATION_APPLICATION_GROUP_CONTRIBUTOR",
"DESKTOP_VIRTUALIZATION_APPLICATION_GROUP_READER",
"DESKTOP_VIRTUALIZATION_APP_ATTACH_CONTRIBUTOR",
"DESKTOP_VIRTUALIZATION_CONTRIBUTOR",
"DESKTOP_VIRTUALIZATION_HOST_POOL_CONTRIBUTOR",
"DESKTOP_VIRTUALIZATION_HOST_POOL_READER",
"DESKTOP_VIRTUALIZATION_POWER_ON_CONTRIBUTOR",
"DESKTOP_VIRTUALIZATION_POWER_ON_OFF_CONTRIBUTOR",
"DESKTOP_VIRTUALIZATION_READER",
"DESKTOP_VIRTUALIZATION_SESSION_HOST_OPERATOR",
"DESKTOP_VIRTUALIZATION_USER",
"DESKTOP_VIRTUALIZATION_USER_SESSION_OPERATOR",
"DESKTOP_VIRTUALIZATION_VIRTUAL_MACHINE_CONTRIBUTOR",
"DESKTOP_VIRTUALIZATION_WORKSPACE_CONTRIBUTOR",
"DESKTOP_VIRTUALIZATION_WORKSPACE_READER",
"DEVCENTER_DEV_BOX_USER",
"DEVCENTER_PROJECT_ADMIN",
"DEVICE_PROVISIONING_SERVICE_DATA_CONTRIBUTOR",
"DEVICE_PROVISIONING_SERVICE_DATA_READER",
"DEVICE_UPDATE_ADMINISTRATOR",
"DEVICE_UPDATE_CONTENT_ADMINISTRATOR",
"DEVICE_UPDATE_CONTENT_READER",
"DEVICE_UPDATE_DEPLOYMENTS_ADMINISTRATOR",
"DEVICE_UPDATE_DEPLOYMENTS_READER",
"DEVICE_UPDATE_READER",
"DEVTEST_LABS_USER",
"DICOM_DATA_OWNER",
"DICOM_DATA_READER",
"DISK_BACKUP_READER",
"DISK_ENCRYPTION_SET_OPERATOR_FOR_MANAGED_DISKS",
"DISK_POOL_OPERATOR",
"DISK_RESTORE_OPERATOR",
"DISK_SNAPSHOT_CONTRIBUTOR",
"DNS_RESOLVER_CONTRIBUTOR",
"DNS_ZONE_CONTRIBUTOR",
"DOCUMENTDB_ACCOUNT_CONTRIBUTOR",
"DOMAIN_SERVICES_CONTRIBUTOR",
"DOMAIN_SERVICES_READER",
"DURABLE_TASK_DATA_CONTRIBUTOR",
"DURABLE_TASK_DATA_READER",
"DURABLE_TASK_WORKER",
"EDGE_MANAGEMENT_COPILOT_USER",
"ELASTIC_SAN_NETWORK_ADMIN",
"ELASTIC_SAN_OWNER",
"ELASTIC_SAN_READER",
"ELASTIC_SAN_SNAPSHOT_EXPORTER",
"ELASTIC_SAN_VOLUME_GROUP_OWNER",
"ELASTIC_SAN_VOLUME_IMPORTER",
"ENCLAVE_APPROVER_ROLE",
"ENCLAVE_CONTRIBUTOR_ROLE",
"ENCLAVE_OWNER_ROLE",
"ENCLAVE_READER_ROLE",
"EVENTGRID_CONTRIBUTOR",
"EVENTGRID_DATA_CONTRIBUTOR",
"EVENTGRID_DATA_RECEIVER",
"EVENTGRID_DATA_SENDER",
"EVENTGRID_EVENTSUBSCRIPTION_CONTRIBUTOR",
"EVENTGRID_EVENTSUBSCRIPTION_READER",
"EVENTGRID_TOPICSPACES_PUBLISHER",
"EVENTGRID_TOPICSPACES_SUBSCRIBER",
"EXPERIMENTATION_ADMINISTRATOR",
"EXPERIMENTATION_CONTRIBUTOR",
"EXPERIMENTATION_METRIC_CONTRIBUTOR",
"EXPERIMENTATION_READER",
"FHIR_DATA_CONTRIBUTOR",
"FHIR_DATA_CONVERTER",
"FHIR_DATA_EXPORTER",
"FHIR_DATA_IMPORTER",
"FHIR_DATA_READER",
"FHIR_DATA_WRITER",
"FHIR_SMART_USER",
"FIRMWARE_ANALYSIS_ADMIN",
"FLUX_CONFIGURATIONS_CONTRIBUTOR",
"GEOCATALOG_ADMINISTRATOR",
"GEOCATALOG_READER",
"GITOPS_LZ_LIST_ACTIONS",
"GRAFANA_ADMIN",
"GRAFANA_EDITOR",
"GRAFANA_LIMITED_VIEWER",
"GRAFANA_VIEWER",
"GRAPH_OWNER",
"GROUPQUOTA_READER",
"GROUPQUOTA_REQUEST_OPERATOR",
"GUEST_CONFIGURATION_RESOURCE_CONTRIBUTOR",
"HDINSIGHT_CLUSTER_ADMIN",
"HDINSIGHT_CLUSTER_OPERATOR",
"HDINSIGHT_DOMAIN_SERVICES_CONTRIBUTOR",
"HDINSIGHT_ON_AKS_CLUSTER_ADMIN",
"HDINSIGHT_ON_AKS_CLUSTER_OPERATOR",
"HDINSIGHT_ON_AKS_CLUSTER_POOL_ADMIN",
"HEALTHCARE_AGENT_ADMIN",
"HEALTHCARE_AGENT_EDITOR",
"HEALTHCARE_AGENT_READER",
"HEALTH_SAFEGUARDS_DATA_USER",
"HIERARCHY_SETTINGS_ADMINISTRATOR",
"HYBRIDCOMPUTE_MACHINE_LISTACCESSDETAILS_ACTION_IN_BUILT_ROLE",
"HYBRID_SERVER_ONBOARDING",
"HYBRID_SERVER_RESOURCE_ADMINISTRATOR",
"IMPACT_READER",
"IMPACT_REPORTER",
"INTEGRATION_SERVICE_ENVIRONMENT_CONTRIBUTOR",
"INTEGRATION_SERVICE_ENVIRONMENT_DEVELOPER",
"INTELLIGENT_SYSTEMS_ACCOUNT_CONTRIBUTOR",
"IOT_HUB_DATA_CONTRIBUTOR",
"IOT_HUB_DATA_READER",
"IOT_HUB_REGISTRY_CONTRIBUTOR",
"IOT_HUB_TWIN_CONTRIBUTOR",
"IPAM_POOL_USER",
"ISSUE_CONTRIBUTOR",
"KEY_VAULT_ADMINISTRATOR",
"KEY_VAULT_CERTIFICATES_OFFICER",
"KEY_VAULT_CERTIFICATE_USER",
"KEY_VAULT_CONTRIBUTOR",
"KEY_VAULT_CRYPTO_OFFICER",
"KEY_VAULT_CRYPTO_SERVICE_ENCRYPTION_USER",
"KEY_VAULT_CRYPTO_SERVICE_RELEASE_USER",
"KEY_VAULT_CRYPTO_USER",
"KEY_VAULT_DATA_ACCESS_ADMINISTRATOR",
"KEY_VAULT_PURGE_OPERATOR",
"KEY_VAULT_READER",
"KEY_VAULT_SECRETS_OFFICER",
"KEY_VAULT_SECRETS_USER",
"KNOWLEDGE_CONSUMER",
"KOSTNER_DFS_BASE_ROLE",
"KUBERNETESRUNTIME_LOAD_BALANCER_CONTRIBUTOR_ROLE",
"KUBERNETES_AGENTLESS_OPERATOR",
"KUBERNETES_AGENT_OPERATOR",
"KUBERNETES_AGENT_SUBSCRIPTION_LEVEL_OPERATOR",
"KUBERNETES_CLUSTER_AZURE_ARC_ONBOARDING",
"KUBERNETES_EXTENSION_CONTRIBUTOR",
"KUBERNETES_NAMESPACE_USER",
"KUBERNETES_RUNTIME_STORAGE_CLASS_CONTRIBUTOR_ROLE",
"LAB_ASSISTANT",
"LAB_CONTRIBUTOR",
"LAB_CREATOR",
"LAB_OPERATOR",
"LAB_SERVICES_CONTRIBUTOR",
"LAB_SERVICES_READER",
"LANDING_ZONE_ACCOUNT_OWNER",
"LANDING_ZONE_ACCOUNT_READER",
"LANDING_ZONE_MANAGEMENT_OWNER",
"LANDING_ZONE_MANAGEMENT_READER",
"LOAD_TEST_CONTRIBUTOR",
"LOAD_TEST_OWNER",
"LOAD_TEST_READER",
"LOCALNGFIREWALLADMINISTRATOR_ROLE",
"LOCALRULESTACKSADMINISTRATOR_ROLE",
"LOCKS_CONTRIBUTOR",
"LOGIC_APPS_STANDARD_CONTRIBUTOR_PREVIEW",
"LOGIC_APPS_STANDARD_DEVELOPER_PREVIEW",
"LOGIC_APPS_STANDARD_OPERATOR_PREVIEW",
"LOGIC_APPS_STANDARD_READER_PREVIEW",
"LOGIC_APP_CONTRIBUTOR",
"LOGIC_APP_OPERATOR",
"LOG_ANALYTICS_CONTRIBUTOR",
"LOG_ANALYTICS_READER",
"MANAGED_APPLICATION_CONTRIBUTOR_ROLE",
"MANAGED_APPLICATION_OPERATOR_ROLE",
"MANAGED_APPLICATION_PUBLISHER_OPERATOR",
"MANAGED_HSM_CONTRIBUTOR",
"MANAGED_IDENTITY_CONTRIBUTOR",
"MANAGED_IDENTITY_FEDERATED_IDENTITY_CREDENTIAL_CONTRIBUTOR",
"MANAGED_IDENTITY_OPERATOR",
"MANAGED_SERVICES_REGISTRATION_ASSIGNMENT_DELETE_ROLE",
"MANAGEMENT_GROUP_CONTRIBUTOR",
"MANAGEMENT_GROUP_READER",
"MEDIA_SERVICES_ACCOUNT_ADMINISTRATOR",
"MEDIA_SERVICES_LIVE_EVENTS_ADMINISTRATOR",
"MEDIA_SERVICES_MEDIA_OPERATOR",
"MEDIA_SERVICES_POLICY_ADMINISTRATOR",
"MEDIA_SERVICES_STREAMING_ENDPOINTS_ADMINISTRATOR",
"MICROSOFT_EDGE_WINFIELDS_FEDERATED_SUBSCRIPTION_READ_ACCESS_ROLE",
"MICROSOFT_KUBERNETES_CONNECTED_CLUSTER_ROLE",
"MICROSOFT_POWERBI_TENANT_OPERATIONS_ROLE",
"MICROSOFT_SENTINEL_AUTOMATION_CONTRIBUTOR",
"MICROSOFT_SENTINEL_BUSINESS_APPLICATIONS_AGENT_OPERATOR",
"MICROSOFT_SENTINEL_CONTRIBUTOR",
"MICROSOFT_SENTINEL_PLAYBOOK_OPERATOR",
"MICROSOFT_SENTINEL_READER",
"MICROSOFT_SENTINEL_RESPONDER",
"MONITORING_CONTRIBUTOR",
"MONITORING_DATA_READER",
"MONITORING_METRICS_PUBLISHER",
"MONITORING_READER",
"MYSQL_BACKUP_AND_EXPORT_OPERATOR",
"NETWORK_CONTRIBUTOR",
"NEW_RELIC_APM_ACCOUNT_CONTRIBUTOR",
"NEXUS_NETWORK_FABRIC_SERVICE_READER",
"NEXUS_NETWORK_FABRIC_SERVICE_WRITER",
"OBJECT_ANCHORS_ACCOUNT_OWNER",
"OBJECT_ANCHORS_ACCOUNT_READER",
"OBJECT_UNDERSTANDING_ACCOUNT_OWNER",
"OBJECT_UNDERSTANDING_ACCOUNT_READER",
"ONLINE_EXPERIMENTATION_CONTRIBUTOR",
"ONLINE_EXPERIMENTATION_DATA_OWNER",
"ONLINE_EXPERIMENTATION_DATA_READER",
"ONLINE_EXPERIMENTATION_READER",
"OPENCOST_RATE_CARD_READER",
"OPERATOR_NEXUS_COMPUTE_CONTRIBUTOR_ROLE_PREVIEW",
"OPERATOR_NEXUS_KEY_VAULT_WRITER_SERVICE_ROLE_PREVIEW",
"OPERATOR_NEXUS_OWNER_PREVIEW",
"ORACLE_DATABASE_AUTONOMOUS_DATABASE_ADMINISTRATOR",
"ORACLE_DATABASE_EXADATA_INFRASTRUCTURE_ADMINISTRATOR_BUILT_IN_ROLE",
"ORACLE_DATABASE_EXASCALE_STORAGE_VAULT_ADMINISTRATOR",
"ORACLE_DATABASE_EXASCALE_VMCLUSTER_ADMINISTRATOR",
"ORACLE_DATABASE_OWNER_BUILT_IN_ROLE",
"ORACLE_DATABASE_READER_BUILT_IN_ROLE",
"ORACLE_DATABASE_VMCLUSTER_ADMINISTRATOR_BUILT_IN_ROLE",
"ORACLE_SUBSCRIPTIONS_MANAGER_BUILT_IN_ROLE",
"OWNER",
"PLAYFAB_CONTRIBUTOR",
"PLAYFAB_READER",
"POLICY_INSIGHTS_DATA_WRITER_PREVIEW",
"PORTAL_DASHBOARD_WRITER_SERVICE_ROLE",
"POSTGRESQL_FLEXIBLE_SERVER_LONG_TERM_RETENTION_BACKUP_ROLE",
"POWER_PLATFORM_ACCOUNT_CONTRIBUTOR",
"POWER_PLATFORM_ENTERPRISE_POLICY_CONTRIBUTOR",
"PRIVATE_DNS_ZONE_CONTRIBUTOR",
"PROCUREMENT_CONTRIBUTOR",
"PROJECT_BABYLON_DATA_CURATOR",
"PROJECT_BABYLON_DATA_READER",
"PROJECT_BABYLON_DATA_SOURCE_ADMINISTRATOR",
"PROVIDERHUB_CONTRIBUTOR",
"PROVIDERHUB_READER",
"QUANTUM_WORKSPACE_DATA_CONTRIBUTOR",
"QUOTA_REQUEST_OPERATOR",
"READER",
"READER_AND_DATA_ACCESS",
"REDIS_CACHE_CONTRIBUTOR",
"REMOTE_RENDERING_ADMINISTRATOR",
"REMOTE_RENDERING_CLIENT",
"RESERVATION_PURCHASER",
"RESOURCE_POLICY_CONTRIBUTOR",
"ROLE_BASED_ACCESS_CONTROL_ADMINISTRATOR",
"SAAS_HUB_CONTRIBUTOR",
"SAVINGS_PLAN_PURCHASER",
"SCHEDULED_EVENTS_CONTRIBUTOR",
"SCHEDULED_PATCHING_CONTRIBUTOR",
"SCHEDULER_JOB_COLLECTIONS_CONTRIBUTOR",
"SCHEMA_REGISTRY_CONTRIBUTOR",
"SCHEMA_REGISTRY_READER",
"SEARCH_INDEX_DATA_CONTRIBUTOR",
"SEARCH_INDEX_DATA_READER",
"SEARCH_PARAMETER_MANAGER",
"SEARCH_SERVICE_CONTRIBUTOR",
"SECRETS_STORE_EXTENSION_OWNER",
"SECURE_SCORE_READER",
"SECURITY_ADMIN",
"SECURITY_ASSESSMENT_CONTRIBUTOR",
"SECURITY_DETONATION_CHAMBER_PUBLISHER",
"SECURITY_DETONATION_CHAMBER_READER",
"SECURITY_DETONATION_CHAMBER_SUBMISSION_MANAGER",
"SECURITY_DETONATION_CHAMBER_SUBMITTER",
"SECURITY_MANAGER_LEGACY",
"SECURITY_READER",
"SERVICES_HUB_OPERATOR",
"SERVICE_CONNECTOR_CONTRIBUTOR",
"SERVICE_FABRIC_CLUSTER_CONTRIBUTOR",
"SERVICE_FABRIC_MANAGED_CLUSTER_CONTRIBUTOR",
"SERVICE_GROUP_READER",
"SIGNALR_ACCESSKEY_READER",
"SIGNALR_APP_SERVER",
"SIGNALR_REST_API_OWNER",
"SIGNALR_REST_API_READER",
"SIGNALR_SERVICE_OWNER",
"SIGNALR_WEB_PUBSUB_CONTRIBUTOR",
"SITE_RECOVERY_CONTRIBUTOR",
"SITE_RECOVERY_OPERATOR",
"SITE_RECOVERY_READER",
"SPATIALMAPSACCOUNTS_ACCOUNT_OWNER",
"SPATIAL_ANCHORS_ACCOUNT_CONTRIBUTOR",
"SPATIAL_ANCHORS_ACCOUNT_OWNER",
"SPATIAL_ANCHORS_ACCOUNT_READER",
"SQLDB_MIGRATION_ROLE",
"SQLMI_MIGRATION_ROLE",
"SQLVM_MIGRATION_ROLE",
"SQL_DB_CONTRIBUTOR",
"SQL_MANAGED_INSTANCE_CONTRIBUTOR",
"SQL_SECURITY_MANAGER",
"SQL_SERVER_CONTRIBUTOR",
"SSH_PUBLICKEYS_CONTRIBUTOR_ROLE",
"SSH_PUBLICKEYS_READER_ROLE",
"STANDBY_CONTAINER_GROUP_POOL_CONTRIBUTOR",
"STORAGE_ACCOUNT_BACKUP_CONTRIBUTOR",
"STORAGE_ACCOUNT_CONTRIBUTOR",
"STORAGE_ACCOUNT_ENCRYPTION_SCOPE_CONTRIBUTOR_ROLE",
"STORAGE_ACCOUNT_KEY_OPERATOR_SERVICE_ROLE",
"STORAGE_BLOB_DATA_CONTRIBUTOR",
"STORAGE_BLOB_DATA_OWNER",
"STORAGE_BLOB_DATA_READER",
"STORAGE_BLOB_DELEGATOR",
"STORAGE_FILE_DATA_PRIVILEGED_CONTRIBUTOR",
"STORAGE_FILE_DATA_PRIVILEGED_READER",
"STORAGE_FILE_DATA_SMB_SHARE_CONTRIBUTOR",
"STORAGE_FILE_DATA_SMB_SHARE_ELEVATED_CONTRIBUTOR",
"STORAGE_FILE_DATA_SMB_SHARE_READER",
"STORAGE_QUEUE_DATA_CONTRIBUTOR",
"STORAGE_QUEUE_DATA_MESSAGE_PROCESSOR",
"STORAGE_QUEUE_DATA_MESSAGE_SENDER",
"STORAGE_QUEUE_DATA_READER",
"STORAGE_TABLE_DATA_CONTRIBUTOR",
"STORAGE_TABLE_DATA_READER",
"STREAM_ANALYTICS_CONTRIBUTOR",
"STREAM_ANALYTICS_QUERY_TESTER",
"STREAM_ANALYTICS_READER",
"SUBSCRIPTION_CREATOR",
"SUBSCRIPTION_CREATOR_OLD",
"SUPPORT_REQUEST_CONTRIBUTOR",
"TAG_CONTRIBUTOR",
"TAG_READER",
"TEMPLATE_SPEC_CONTRIBUTOR",
"TEMPLATE_SPEC_READER",
"TEST_BASE_READER",
"TOOLCHAINORCHESTRATOR_ADMIN_ROLE",
"TOOLCHAINORCHESTRATOR_VIEWER_ROLE",
"TRAFFIC_MANAGER_CONTRIBUTOR",
"TRANSPARENCY_LOGS_OWNER",
"TRUSTED_SIGNING_CERTIFICATE_PROFILE_SIGNER",
"TRUSTED_SIGNING_IDENTITY_VERIFIER",
"USAGE_BILLING_CONTRIBUTOR",
"USER_ACCESS_ADMINISTRATOR",
"VIDEO_INDEXER_RESTRICTED_VIEWER",
"VIRTUAL_MACHINE_ADMINISTRATOR_LOGIN",
"VIRTUAL_MACHINE_CONTRIBUTOR",
"VIRTUAL_MACHINE_DATA_ACCESS_ADMINISTRATOR_PREVIEW",
"VIRTUAL_MACHINE_LOCAL_USER_LOGIN",
"VIRTUAL_MACHINE_USER_LOGIN",
"VM_RESTORE_OPERATOR",
"VM_SCANNER_OPERATOR",
"WEBSITE_CONTRIBUTOR",
"WEB_PLAN_CONTRIBUTOR",
"WEB_PUBSUB_SERVICE_OWNER",
"WEB_PUBSUB_SERVICE_READER",
"WINDOWS_ADMIN_CENTER_ADMINISTRATOR_LOGIN",
"WORKBOOK_CONTRIBUTOR",
"WORKBOOK_READER",
"WORKLOADBUILDER_MIGRATION_AGENT_ROLE",
"WORKLOAD_ORCHESTRATION_IT_ADMIN",
"WORKLOAD_ORCHESTRATION_SOLUTION_EXTERNAL_VALIDATOR"
]

View File

@@ -18,8 +18,20 @@ from typing import Any
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Known Azure enum values not always captured in the catalog schema # Known Azure enum values not always captured in the catalog schema
def _load_azure_roles() -> list[str]:
"""Load Azure roles from azure_roles.json (generated from bicep/lookup/rbaclookup)."""
roles_file = pathlib.Path(__file__).parent / "azure_roles.json"
if roles_file.exists():
try:
return json.loads(roles_file.read_text())
except Exception as e:
logger.warning("Failed to load azure_roles.json: %s", e)
return []
_KNOWN_ENUMS: dict[str, list[str]] = { _KNOWN_ENUMS: dict[str, list[str]] = {
"principalType": ["User", "Group", "ServicePrincipal", "Device", "ForeignGroup"], "principalType": ["User", "Group", "ServicePrincipal", "Device", "ForeignGroup"],
"roles": _load_azure_roles(),
"roleDefinitionIds": _load_azure_roles(), # alias for roles
} }
# Catalog is baked into the image root at /bicep_modules_catalog.json # Catalog is baked into the image root at /bicep_modules_catalog.json
@@ -268,6 +280,56 @@ class BicepModuleCatalog:
iac_params = cls._iac_param_map(module_name) iac_params = cls._iac_param_map(module_name)
items = [] items = []
# Build snippet for full params block (shown first)
snippet_params = []
tabstop = 1
for param_name, param_info in ver_params.items():
iac = iac_params.get(param_name, {})
required = iac.get("required", False)
ptype = param_info.get("type", "any")
allowed = param_info.get("allowed", [])
# Include required params + first few optional params in snippet
if required or len(snippet_params) < 5:
if allowed:
# Enum: use placeholder with first allowed value
placeholder = f"'{allowed[0]}'"
elif ptype == "bool":
placeholder = "true"
elif ptype == "int":
placeholder = "0"
elif ptype == "array":
placeholder = "[]"
elif ptype == "object":
placeholder = "{{}}"
else:
placeholder = "''"
snippet_params.append(f" {param_name}: ${{{tabstop}:{placeholder}}}")
tabstop += 1
if snippet_params:
snippet_text = "\n" + "\n".join(snippet_params) + "\n"
required_count = sum(1 for p, i in ver_params.items()
if iac_params.get(p, {}).get("required", False))
items.append({
"label": "⚡ Fill params block",
"kind": 15, # Snippet
"detail": f"{len(snippet_params)} params ({required_count} required)",
"insertText": snippet_text,
"insertTextFormat": 2, # Snippet
"sortText": "0_lru_snippet_000",
"documentation": {
"kind": "markdown",
"value": (
f"**Fill params block**\n\n"
f"Inserts {len(snippet_params)} params for `{module_name}`.\n"
f"Use Tab to navigate between fields."
),
},
})
# Individual param completions
for param_name, param_info in ver_params.items(): for param_name, param_info in ver_params.items():
ptype = param_info.get("type", "any") ptype = param_info.get("type", "any")
allowed = param_info.get("allowed", []) allowed = param_info.get("allowed", [])

View File

@@ -142,6 +142,43 @@ class _ProxySession:
"has_open_quote": bool(value_m.group(2)), "has_open_quote": bool(value_m.group(2)),
} }
# Check if cursor is inside an array value for a param
# e.g. "roles: ['KEY_VAULT_" or "roles: [ '"
array_m = re.search(r"^\s*(\w+):\s*\[[^\]]*?('?)([^',\]]*)$", current)
if array_m and array_m.group(1) not in {"params", "name", "module", "resource"}:
return {
"type": "param_value",
"module": mod_name,
"version": mod_ver,
"param": array_m.group(1),
"has_open_quote": bool(array_m.group(2)),
}
# Check if cursor is inside a multi-line array element
# e.g. " 'APP_CONFIG" on line after "roles: ["
# Walk backwards to find the array opening
for lookback_idx in range(line_idx - 1, max(0, line_idx - 10), -1):
prev_line = lines[lookback_idx]
# Found array opening like "roles: [" or " roles: ["
array_open_m = re.match(r"^\s*(\w+):\s*\[$", prev_line.rstrip())
if array_open_m:
param_name = array_open_m.group(1)
if param_name not in {"params", "name", "module", "resource"}:
# Check if current line is inside the array (has quote or is indented)
if re.match(r"^\s+('?)([^',\]]*)\s*$", current):
has_quote = bool(re.match(r"^\s+'", current))
return {
"type": "param_value",
"module": mod_name,
"version": mod_ver,
"param": param_name,
"has_open_quote": has_quote,
}
break
# Stop if we hit a closing bracket (we're outside the array)
if "]" in prev_line:
break
return { return {
"type": "param", "type": "param",
"module": mod_name, "module": mod_name,

View File

@@ -0,0 +1,70 @@
#!/usr/bin/env python3
"""
Extract all Azure role names from rbacLookup.bicep and generate Python code
for _KNOWN_ENUMS in modules.py.
Usage:
python3 scripts/extract_roles_from_rbaclookup.py /path/to/rbacLookup.bicep
"""
import re
import sys
from pathlib import Path
def extract_role_names(bicep_file: Path) -> list[str]:
"""Extract all role names from the rbacLookup.bicep var roles = {...} block."""
content = bicep_file.read_text()
# Find the "var roles = {" block
roles_match = re.search(r'@export\(\)\s*var\s+roles\s*=\s*\{(.+?)\n\}', content, re.DOTALL)
if not roles_match:
raise ValueError("Could not find 'var roles = {' block in Bicep file")
roles_block = roles_match.group(1)
# Extract all role names (keys before the colon)
# Pattern: " ROLE_NAME: 'guid'"
role_names = re.findall(r'^\s+([A-Z_]+):', roles_block, re.MULTILINE)
return sorted(role_names)
def generate_python_code(role_names: list[str]) -> str:
"""Generate Python code for _KNOWN_ENUMS["roles"]."""
lines = ['_KNOWN_ENUMS = {']
lines.append(' "roles": [')
for role in role_names:
lines.append(f' "{role}",')
lines.append(' ],')
lines.append(' "roleDefinitionIds": [ # alias for roles')
for role in role_names:
lines.append(f' "{role}",')
lines.append(' ],')
lines.append('}')
return '\n'.join(lines)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: extract_roles_from_rbaclookup.py /path/to/rbacLookup.bicep", file=sys.stderr)
sys.exit(1)
bicep_path = Path(sys.argv[1])
if not bicep_path.exists():
print(f"Error: File not found: {bicep_path}", file=sys.stderr)
sys.exit(1)
try:
roles = extract_role_names(bicep_path)
print(f"# Extracted {len(roles)} roles from {bicep_path.name}")
print(f"# Generated: {Path(__file__).name}\n")
print(generate_python_code(roles))
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)

View File

@@ -17,6 +17,7 @@ frames straight to stdout.
import asyncio import asyncio
import ssl import ssl
import sys import sys
import traceback
import websockets import websockets
@@ -71,8 +72,9 @@ async def main(uri: str) -> None:
if msg is None: if msg is None:
break break
await ws.send(msg) await ws.send(msg)
except Exception: except Exception as e:
pass print(f"stdin_to_ws error: {e}", file=sys.stderr)
traceback.print_exc(file=sys.stderr)
async def ws_to_stdout() -> None: async def ws_to_stdout() -> None:
try: try:
@@ -80,8 +82,9 @@ async def main(uri: str) -> None:
data = frame if isinstance(frame, bytes) else frame.encode() data = frame if isinstance(frame, bytes) else frame.encode()
sys.stdout.buffer.write(data) sys.stdout.buffer.write(data)
sys.stdout.buffer.flush() sys.stdout.buffer.flush()
except Exception: except Exception as e:
pass print(f"ws_to_stdout error: {e}", file=sys.stderr)
traceback.print_exc(file=sys.stderr)
await asyncio.gather(stdin_to_ws(), ws_to_stdout()) await asyncio.gather(stdin_to_ws(), ws_to_stdout())
@@ -90,4 +93,9 @@ if __name__ == "__main__":
if len(sys.argv) < 2: if len(sys.argv) < 2:
print("Usage: lsp_bridge.py <wss://...>", file=sys.stderr) print("Usage: lsp_bridge.py <wss://...>", file=sys.stderr)
sys.exit(1) sys.exit(1)
asyncio.run(main(sys.argv[1])) try:
asyncio.run(main(sys.argv[1]))
except Exception as e:
print(f"Fatal error: {e}", file=sys.stderr)
traceback.print_exc(file=sys.stderr)
sys.exit(1)

12
scripts/lsp_bridge_debug.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
# Wrapper for lsp_bridge.py that logs to a file for debugging IntelliJ issues
LOG_FILE="/tmp/lsp_bridge_debug.log"
echo "=== LSP Bridge started at $(date) ===" >> "$LOG_FILE"
echo "Args: $@" >> "$LOG_FILE"
echo "PWD: $(pwd)" >> "$LOG_FILE"
echo "Python: $(which python3)" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"
exec /opt/homebrew/bin/python3 /Users/lrihni/Projects/iLSP/scripts/lsp_bridge.py "$@" 2>> "$LOG_FILE"

View File

@@ -173,8 +173,12 @@ def test_param_completions_injected_on_param_context():
assert "roleDefinitionIds" in labels assert "roleDefinitionIds" in labels
assert "principalId" in labels assert "principalId" in labels
assert "principalType" in labels assert "principalType" in labels
assert items[0]["sortText"].startswith("0_lru_param_") # First item is now the snippet completion
assert items[0]["kind"] == 5 # Field assert items[0]["label"] == "⚡ Fill params block"
assert items[0]["kind"] == 15 # Snippet
# Second item should be a regular param
assert items[1]["sortText"].startswith("0_lru_param_")
assert items[1]["kind"] == 5 # Field
def test_param_completion_items_have_insert_text(): def test_param_completion_items_have_insert_text():
@@ -182,7 +186,12 @@ def test_param_completion_items_have_insert_text():
"roleassignments", versions=["1.1.x"], schema=_ROLEASSIGNMENTS_SCHEMA "roleassignments", versions=["1.1.x"], schema=_ROLEASSIGNMENTS_SCHEMA
)] )]
items = BicepModuleCatalog.param_completion_items("roleassignments", "1.1.x") items = BicepModuleCatalog.param_completion_items("roleassignments", "1.1.x")
for item in items: # First item should be the snippet completion
assert items[0]["label"] == "⚡ Fill params block"
assert items[0]["insertTextFormat"] == 2
assert "principalId" in items[0]["insertText"]
# Individual param items should have ": " suffix
for item in items[1:]:
assert item["insertText"].endswith(": ") assert item["insertText"].endswith(": ")
@@ -302,6 +311,48 @@ def test_detect_param_value_context_open_quote():
assert ctx["has_open_quote"] is True assert ctx["has_open_quote"] is True
def test_detect_param_value_context_in_array():
"""Cursor inside array value → param_value context."""
lines = [
"module myMod 'br/modules:roleassignments:1.1.x' = {",
" params: {",
" roles: ['KEY_VAULT_", # ← cursor inside array element
" }",
"}",
]
session = _make_session_with_doc(URI, lines)
# character = len(" roles: ['KEY_VAULT_") = 23
ctx = session._detect_context(URI, {"line": 2, "character": 23})
assert ctx["type"] == "param_value"
assert ctx["module"] == "roleassignments"
assert ctx["param"] == "roles"
assert ctx["has_open_quote"] is True
def test_detect_param_value_context_in_multiline_array():
"""Cursor in multi-line array element → param_value context."""
lines = [
"module myMod 'br/modules:roleassignments:2.0.x' = {",
" params: {",
" assignments: [",
" {",
" roles: [",
" 'APP_CONFIGURATION_", # ← cursor on separate line
" ]",
" }",
" ]",
" }",
"}",
]
session = _make_session_with_doc(URI, lines)
# character = len(" 'APP_CONFIGURATION_") = 27
ctx = session._detect_context(URI, {"line": 5, "character": 27})
assert ctx["type"] == "param_value"
assert ctx["module"] == "roleassignments"
assert ctx["param"] == "roles"
assert ctx["has_open_quote"] is True
def test_param_value_items_from_catalog_allowed(): def test_param_value_items_from_catalog_allowed():
"""environmentType completions come from catalog 'allowed' field.""" """environmentType completions come from catalog 'allowed' field."""
BicepModuleCatalog._modules = [_make_module( BicepModuleCatalog._modules = [_make_module(
@@ -353,6 +404,24 @@ def test_param_value_items_known_enum_fallback():
assert "User" in labels assert "User" in labels
def test_param_value_items_roles_enum():
"""roles parameter uses _KNOWN_ENUMS for Azure role completions."""
BicepModuleCatalog._modules = [_make_module(
"roleassignments",
versions=["1.1.x"],
schema={"1.1.x": {"parameters": {
"roles": {"type": "array"}, # no 'allowed' in catalog
}}},
)]
items = BicepModuleCatalog.param_value_completion_items(
"roleassignments", "1.1.x", "roles"
)
labels = [i["label"] for i in items]
assert "KEY_VAULT_SECRETS_USER" in labels
assert "STORAGE_BLOB_DATA_READER" in labels
assert "CONTRIBUTOR" in labels
def test_param_value_items_empty_for_free_string(): def test_param_value_items_empty_for_free_string():
"""A plain string param with no allowed values returns no completions.""" """A plain string param with no allowed values returns no completions."""
BicepModuleCatalog._modules = [_make_module( BicepModuleCatalog._modules = [_make_module(