{
  "steward": "bicep-module-steward",
  "project": "Azure-AI-RAG-CSharp-Semantic-Kernel-Functions",
  "runDate": "2026-03-22",
  "runId": "2026-03-22T00-00-00",
  "findings": [
    {
      "id": "BICM-PARAM-001",
      "title": "CosmosDb_ConnectionString set to empty string — API app will fail to connect to Cosmos DB at runtime",
      "severity": "critical",
      "category": "PARAM",
      "file": "infra/app/api-app.bicep",
      "line": 65,
      "description": "The CosmosDb_ConnectionString app setting is explicitly set to an empty string. The Cosmos DB endpoint is never forwarded to the API App Service. At runtime, any code that reads the connection string will receive an empty value and fail to connect. Managed identity authentication requires at minimum the account endpoint to be configured.",
      "recommendation": "Wire database.outputs.endpoint into the API app settings as AZURE_COSMOS_DB_ENDPOINT and use managed identity authentication. Remove the empty CosmosDb_ConnectionString app setting.",
      "status": "open"
    },
    {
      "id": "BICM-PARAM-002",
      "title": "No parameter files exist for any environment — no reproducible multi-environment deployments possible",
      "severity": "critical",
      "category": "PARAM",
      "description": "No .bicepparam or parameters.json files exist in the repository. There is no way to deploy this infrastructure to different environments (dev, staging, prod) without manually overriding parameters on every deployment command. This makes repeatable environment provisioning impossible and increases the risk of configuration drift.",
      "recommendation": "Create infra/main.dev.bicepparam and infra/main.prod.bicepparam files that define environmentName, projectName, and location per environment.",
      "status": "open"
    },
    {
      "id": "BICM-APIVER-001",
      "title": "Microsoft.Authorization/roleAssignments@2020-04-01-preview preview API used in four files",
      "severity": "notable",
      "category": "APIVER",
      "file": "infra/core/storage/blob-storage-account.bicep",
      "description": "The preview API version 2020-04-01-preview for Microsoft.Authorization/roleAssignments is used in openai-account.bicep, blob-storage-account.bicep, and search-services.bicep (four role assignment resources total). The stable replacement 2022-04-01 has been available since 2022. Preview APIs can be deprecated without notice.",
      "recommendation": "Replace Microsoft.Authorization/roleAssignments@2020-04-01-preview with @2022-04-01 in all four files.",
      "status": "open"
    },
    {
      "id": "BICM-APIVER-002",
      "title": "Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30 is over 5 years old",
      "severity": "notable",
      "category": "APIVER",
      "file": "infra/core/security/managed-identity.bicep",
      "line": 5,
      "description": "The managed identity module uses the 2018-11-30 API version which is more than five years old. The current stable version is 2023-01-31. Using very old API versions risks missing newer resource properties and may encounter deprecation.",
      "recommendation": "Update Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30 to @2023-01-31 in managed-identity.bicep.",
      "status": "open"
    },
    {
      "id": "BICM-APIVER-003",
      "title": "Microsoft.Search/searchServices@2021-04-01-preview is a 2021 preview API",
      "severity": "notable",
      "category": "APIVER",
      "file": "infra/core/search/search-services.bicep",
      "line": 48,
      "description": "The Azure AI Search service uses the 2021-04-01-preview API from 2021. This is a preview API that is over three years old. A stable version (2023-11-01) is available.",
      "recommendation": "Update Microsoft.Search/searchServices@2021-04-01-preview to @2023-11-01 in search-services.bicep.",
      "status": "open"
    },
    {
      "id": "BICM-APIVER-004",
      "title": "Microsoft.OperationalInsights/workspaces@2021-12-01-preview is a preview API",
      "severity": "notable",
      "category": "APIVER",
      "file": "infra/core/monitor/loganalytics.bicep",
      "line": 6,
      "description": "The Log Analytics workspace uses the 2021-12-01-preview API version. The stable version 2023-09-01 is available and should be used for production infrastructure.",
      "recommendation": "Update Microsoft.OperationalInsights/workspaces@2021-12-01-preview to @2023-09-01 in loganalytics.bicep.",
      "status": "open"
    },
    {
      "id": "BICM-APIVER-005",
      "title": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2021-07-01-preview is a preview API",
      "severity": "notable",
      "category": "APIVER",
      "file": "infra/core/database/cosmos-db/account.bicep",
      "line": 66,
      "description": "The Cosmos DB SQL role definition resource uses the 2021-07-01-preview API version. The stable version 2023-04-15 is available.",
      "recommendation": "Update Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2021-07-01-preview to @2023-04-15 in account.bicep.",
      "status": "open"
    },
    {
      "id": "BICM-PARAM-003",
      "title": "Hardcoded location 'centralus' for Cosmos DB bypasses the deployment location parameter",
      "severity": "notable",
      "category": "PARAM",
      "file": "infra/main.bicep",
      "line": 83,
      "description": "The database module call passes location: 'centralus' as a hardcoded string instead of using the location parameter. All other modules use the location parameter. This means the Cosmos DB account will always deploy to centralus regardless of the operator's chosen deployment region, silently diverging from all other resources.",
      "recommendation": "Remove the hardcoded location: 'centralus' and pass the location parameter instead so all resources deploy to the same region.",
      "status": "open"
    },
    {
      "id": "BICM-PARAM-004",
      "title": "Storage account name missing uniqueString() token — globally unique name not guaranteed across subscriptions",
      "severity": "notable",
      "category": "PARAM",
      "file": "infra/main.bicep",
      "line": 45,
      "description": "The storage account name is constructed as 'sa${projectName}${environmentName}' without including resourceToken. Storage account names are globally unique across all Azure tenants. All other resource names in main.bicep include resourceToken (which incorporates the subscription ID) to guarantee uniqueness. Omitting it here means two deployments with the same projectName and environmentName on different subscriptions will collide.",
      "recommendation": "Update the storage account name to include resourceToken using take() to stay within the 24-character limit, e.g. 'sa${take(projectName,8)}${take(environmentName,4)}${take(resourceToken,10)}'.",
      "status": "open"
    },
    {
      "id": "BICM-PARAM-005",
      "title": "Multiple app settings hardcoded inline — model names, API versions, index names, and DB names cannot vary by environment",
      "severity": "notable",
      "category": "PARAM",
      "file": "infra/app/api-app.bicep",
      "description": "Model deployment names ('text-embedding', 'gpt-chat'), OpenAI API version ('2023-05-15'), AI Search index name ('azure-support'), and Cosmos DB database/container names ('chatdatabase', 'products', 'chathistory') are hardcoded in both api-app.bicep and loader-function.bicep. These values cannot differ between environments without modifying the Bicep source files.",
      "recommendation": "Extract these values into parameters with sensible defaults so they can be overridden per environment via parameter files.",
      "status": "open"
    },
    {
      "id": "BICM-OUTPUT-001",
      "title": "instrumentationKey exported as plain string output — sensitive credential should use Key Vault reference",
      "severity": "notable",
      "category": "OUTPUT",
      "file": "infra/core/monitor/applicationinsights.bicep",
      "line": 30,
      "description": "The Application Insights instrumentation key is exported as a plain output string and then injected directly into app settings in api-app.bicep and loader-function.bicep as APPINSIGHTS_INSTRUMENTATIONKEY. Instrumentation keys should be stored in Key Vault and referenced via Key Vault secret references to avoid exposing them in deployment outputs and Azure portal.",
      "recommendation": "Store the instrumentation key in Key Vault and reference it in app settings via @Microsoft.KeyVault(SecretUri=...) syntax, or rely solely on the connection string (APPLICATIONINSIGHTS_CONNECTION_STRING) which already includes the key.",
      "status": "open"
    },
    {
      "id": "BICM-MODULE-001",
      "title": "key-vault.bicep is an empty placeholder file — Key Vault integration was planned but never implemented",
      "severity": "notable",
      "category": "MODULE",
      "file": "infra/core/security/key-vault.bicep",
      "description": "The file infra/core/security/key-vault.bicep exists but contains no content. The KeyVaultUri app setting in loader-function.bicep is set to an empty string, indicating Key Vault integration was planned but never completed. The empty file creates a false impression that Key Vault is provisioned.",
      "recommendation": "Either implement key-vault.bicep to provision a Key Vault and wire up the KeyVaultUri app setting, or delete the empty file and remove the placeholder app setting.",
      "status": "open"
    },
    {
      "id": "BICM-PARAM-006",
      "title": "Parameter names use non-camelCase conventions in multiple modules",
      "severity": "minor",
      "category": "PARAM",
      "file": "infra/app/loader-function.bicep",
      "description": "Parameters named StorageBlobURL, StorageAccountName, OpenAIEndPoint, and AZURE_AI_SEARCH_ENDPOINT violate the camelCase naming convention for Bicep parameters. AZURE_AI_SEARCH_ENDPOINT uses SCREAMING_SNAKE_CASE and OpenAIEndPoint uses PascalCase. The output StorageAccountName in blob-storage-account.bicep also uses PascalCase while all other outputs use camelCase.",
      "recommendation": "Rename parameters to camelCase: openAiEndpoint, azureAiSearchEndpoint, storageBlobUrl, storageAccountName. Update all callers in main.bicep, api-app.bicep, and loader-function.bicep.",
      "status": "open"
    },
    {
      "id": "BICM-PARAM-007",
      "title": "Missing @description() decorators on parameters across multiple modules",
      "severity": "minor",
      "category": "PARAM",
      "description": "All parameters in infra/app/api-app.bicep, infra/app/loader-function.bicep, infra/app/web-app.bicep, infra/core/host/app-service.bicep, infra/core/ai/openai/openai-account.bicep, infra/core/storage/blob-storage-account.bicep, and infra/core/security/managed-identity.bicep lack @description() decorators. The ttlValue parameter in container.bicep and monitoring.bicep parameters are also missing descriptions.",
      "recommendation": "Add @description() decorators to all parameters that are missing them across the infra/app/ and affected infra/core/ modules.",
      "status": "open"
    },
    {
      "id": "BICM-NAMING-001",
      "title": "Variables blob_uri and queue_uri use snake_case instead of camelCase",
      "severity": "minor",
      "category": "NAMING",
      "file": "infra/app/loader-function.bicep",
      "line": 13,
      "description": "The variables blob_uri and queue_uri in loader-function.bicep use snake_case naming. Bicep convention is camelCase for all variables.",
      "recommendation": "Rename blob_uri to blobUri and queue_uri to queueUri.",
      "status": "open"
    },
    {
      "id": "BICM-NAMING-002",
      "title": "Custom Cosmos DB role display name 'My Read Write Role' is informal and misleading",
      "severity": "minor",
      "category": "NAMING",
      "file": "infra/core/database/cosmos-db/account.bicep",
      "line": 70,
      "description": "The custom Cosmos DB SQL role definition has the display name 'My Read Write Role' but its dataActions list contains only read operations (readMetadata, read, executeQuery, readChangeFeed). The name is both informal and inaccurate, which could lead to developers granting overly permissive access based on the misleading name.",
      "recommendation": "Rename the role to accurately reflect its actual permissions, such as '${accountName}-ReadData', and remove 'Write' from the display name.",
      "status": "open"
    },
    {
      "id": "BICM-OUTPUT-002",
      "title": "appServiceURL and storageBlobURL constructed via string interpolation instead of resource properties",
      "severity": "minor",
      "category": "OUTPUT",
      "file": "infra/app/api-app.bicep",
      "line": 159,
      "description": "The appServiceURL output in api-app.bicep and web-app.bicep is constructed as 'https://${appServiceName}.azurewebsites.net' via string interpolation instead of reading from appService.properties.defaultHostName. Similarly, storageBlobURL in blob-storage-account.bicep interpolates the storage account name instead of reading from storageAcct.properties.primaryEndpoints.blob. String interpolation breaks if custom domains are configured or if the account is in a sovereign cloud.",
      "recommendation": "Replace string-interpolated URL outputs with resource property reads: appServiceNode.properties.defaultHostName for app services, storageAcct.properties.primaryEndpoints.blob for blob storage URLs.",
      "status": "open"
    },
    {
      "id": "BICM-INFO-001",
      "title": "Module decomposition into core/ primitives and app/ orchestration is a sound pattern",
      "severity": "info",
      "category": "MODULE",
      "description": "The two-tier module structure — infra/core/ for reusable single-resource primitives and infra/app/ for application-tier orchestration — is a well-recognised Bicep pattern. The use of abbreviations.json for consistent resource name prefixes is also good practice.",
      "status": "open"
    },
    {
      "id": "BICM-INFO-002",
      "title": "Managed identity plus RBAC-only access pattern correctly avoids connection string secrets",
      "severity": "info",
      "category": "PARAM",
      "description": "The infrastructure consistently uses a single user-assigned managed identity with RBAC role assignments for storage, Azure AI Search, and Azure OpenAI. This avoids storing connection string secrets in app settings and is the recommended approach for Azure workload identity.",
      "status": "open"
    }
  ],
  "summary": {
    "critical": 2,
    "notable": 9,
    "minor": 6,
    "info": 2,
    "total": 19
  }
}
