{
  "steward": "infra-deployment-steward",
  "project": "Azure-AI-RAG-CSharp-Semantic-Kernel-Functions",
  "runDate": "2026-03-22",
  "runId": "2026-03-22T00-00-00",
  "findings": [
    {
      "id": "IDEP-CICD-001",
      "title": "No CI/CD pipeline — deployment is fully manual",
      "severity": "critical",
      "category": "CICD",
      "description": "There is no GitHub Actions workflow, Azure DevOps pipeline, or any other CI/CD pipeline in the repository. All deployment is performed manually by running PowerShell scripts from a developer workstation. This means deployments are non-repeatable, ungoverned, and cannot enforce build/test/deploy stage separation.",
      "recommendation": "Implement a GitHub Actions or Azure DevOps pipeline with distinct build, test, and deploy stages. Use workload identity federation to authenticate to Azure without interactive login.",
      "status": "open"
    },
    {
      "id": "IDEP-CICD-002",
      "title": "No Bicep what-if validation before deployment",
      "severity": "critical",
      "category": "CICD",
      "file": "infra/deploy.ps1",
      "line": 25,
      "description": "The deploy.ps1 script runs `az deployment sub create` directly without a preceding `--what-if` dry-run. Destructive or unexpected infrastructure changes can be applied without any preview or human review.",
      "recommendation": "Add an `az deployment sub create --what-if` step before the actual deployment. In a pipeline, require a manual approval gate after reviewing the what-if output.",
      "status": "open"
    },
    {
      "id": "IDEP-SECRETS-001",
      "title": "CosmosDB connection string managed manually outside automation",
      "severity": "critical",
      "category": "SECRETS",
      "file": "infra/app/api-app.bicep",
      "line": 65,
      "description": "The CosmosDb_ConnectionString app setting is deployed as an empty string in Bicep, and the README explicitly instructs developers to manually copy the connection string from the Azure Portal and paste it into App Settings after deployment. This bypasses any automated, auditable, or repeatable secrets management process and introduces a human error risk on every deployment.",
      "recommendation": "Use `az cosmosdb keys list` in the deployment script to retrieve the connection string programmatically and set it as an App Setting, or implement Key Vault with a Key Vault reference (@Microsoft.KeyVault(SecretUri=...)) so the App Service resolves the secret at runtime without it ever appearing in plaintext in deployment scripts.",
      "status": "open"
    },
    {
      "id": "IDEP-ENV-001",
      "title": "Single hardcoded environment — no staging or promotion gates",
      "severity": "notable",
      "category": "ENV",
      "file": "infra/deploy.ps1",
      "line": 10,
      "description": "The environmentName variable is hardcoded to 'demo' with no parameterization for dev/staging/production environments. All deployments target a single environment with no gating, approval, or promotion strategy.",
      "recommendation": "Parameterise environmentName as a pipeline variable. Define at least a staging environment separate from production, and require manual approval before promoting a deployment to production.",
      "status": "open"
    },
    {
      "id": "IDEP-ROLLBACK-001",
      "title": "No rollback mechanism — no deployment slots or artifact preservation",
      "severity": "notable",
      "category": "ROLLBACK",
      "file": "infra/scripts/deploy_api.ps1",
      "description": "All three application deployments (API, Function App, Web) use zip-deploy directly to the running production slot with no backup, no deployment slot swap strategy, and no artifact preservation. There is no way to return to a previous known-good state without rebuilding from source.",
      "recommendation": "Configure App Service deployment slots (e.g., a staging slot). Deploy to the staging slot, validate, then swap to production. Preserve versioned zip artifacts in Azure Storage so prior versions can be re-deployed without a full rebuild.",
      "status": "open"
    },
    {
      "id": "IDEP-VALIDATE-001",
      "title": "No post-deployment health check after application deployment",
      "severity": "notable",
      "category": "VALIDATE",
      "file": "infra/scripts/deploy_api.ps1",
      "description": "After each az webapp deploy or az functionapp deployment, the scripts do not verify that the application started successfully. The only readiness mechanism is a static 120-second sleep before the first app deployment. Deployment failures (startup errors, bad configuration) will not be detected by the scripts.",
      "recommendation": "After each deployment, poll the application's health endpoint or use `az webapp show --query state` in a loop to confirm the app is running before proceeding to the next deployment step. Fail the script if the app does not reach a Running state within a timeout.",
      "status": "open"
    },
    {
      "id": "IDEP-SECRETS-002",
      "title": "Key Vault provisioned but key-vault.bicep is empty and KeyVaultUri is unset",
      "severity": "notable",
      "category": "SECRETS",
      "file": "infra/core/security/key-vault.bicep",
      "description": "The key-vault.bicep file is empty (1 line, no content), meaning Key Vault is not actually deployed despite being referenced in the module structure. The loader-function.bicep has a KeyVaultUri app setting set to an empty string, indicating an incomplete Key Vault integration. Secrets that should be stored in Key Vault are currently either absent or managed manually.",
      "recommendation": "Implement key-vault.bicep to provision an Azure Key Vault with access policies or RBAC for the Managed Identity. Store CosmosDb_ConnectionString and any other secrets as Key Vault secrets and reference them using App Service Key Vault references.",
      "status": "open"
    },
    {
      "id": "IDEP-CICD-003",
      "title": "Interactive az login in deploy script prevents pipeline automation",
      "severity": "minor",
      "category": "CICD",
      "file": "infra/deploy.ps1",
      "line": 20,
      "description": "The deploy.ps1 script calls `az login` interactively (with browser-based authentication), which requires a human at a workstation. This makes the script unusable in any automated or headless environment.",
      "recommendation": "Replace `az login` with a service principal login (`az login --service-principal`) or, preferably, with workload identity federation configured at the pipeline level so no credentials need to be managed at all.",
      "status": "open"
    },
    {
      "id": "IDEP-CICD-004",
      "title": "Fixed Start-Sleep used as infrastructure readiness wait",
      "severity": "minor",
      "category": "CICD",
      "file": "infra/deploy.ps1",
      "line": 35,
      "description": "A 120-second sleep is used to wait for Azure infrastructure to be ready after Bicep deployment. This is fragile: the wait may be too short in slow regions or under high load, and wastes time when resources are ready sooner.",
      "recommendation": "Replace Start-Sleep with a polling loop that queries `az deployment sub show --query properties.provisioningState` and waits until it returns 'Succeeded' before proceeding.",
      "status": "open"
    },
    {
      "id": "IDEP-CICD-005",
      "title": "--track-status false suppresses deployment error detection",
      "severity": "minor",
      "category": "CICD",
      "file": "infra/scripts/deploy_api.ps1",
      "line": 26,
      "description": "The az webapp deploy call for the ChatAPI uses --track-status false, which tells the Azure CLI not to wait for or report the final deployment status. If the deployment fails, the script will not detect the failure and will continue to subsequent steps.",
      "recommendation": "Remove the --track-status false flag so the CLI waits for and reports deployment completion status. Handle the non-zero exit code in the script to halt on failure.",
      "status": "open"
    },
    {
      "id": "IDEP-SECRETS-003",
      "title": "Managed Identity used for all service authentication",
      "severity": "info",
      "category": "SECRETS",
      "description": "The project correctly uses a User-Assigned Managed Identity for authenticating to Azure OpenAI, Azure AI Search, Azure Storage, and Azure Functions runtime storage. No API keys or connection strings (other than CosmosDB) are stored in configuration. This is a strong baseline for passwordless authentication.",
      "status": "open"
    },
    {
      "id": "IDEP-AZD-001",
      "title": "No azure.yaml — project does not use Azure Developer CLI",
      "severity": "info",
      "category": "AZD",
      "description": "The project does not use the Azure Developer CLI (azd). There is no azure.yaml file. Deployment is handled entirely by custom PowerShell scripts. This is not a defect but means the project misses out on azd's standardised environment management, pipeline templates, and hook system.",
      "recommendation": "Consider adopting azd by adding an azure.yaml service manifest. This would enable `azd up`, `azd deploy`, and standardised CI/CD pipeline generation via `azd pipeline config`.",
      "status": "open"
    }
  ],
  "summary": {
    "critical": 3,
    "notable": 4,
    "minor": 3,
    "info": 2,
    "total": 12
  }
}
