{
  "steward": "api-config-steward",
  "project": "Azure-AI-RAG-CSharp-Semantic-Kernel-Functions",
  "runDate": "2026-03-21",
  "runId": "2026-03-21T00-00-00",
  "findings": [
    {
      "id": "ACFG-VALID-001",
      "title": "No startup validation — missing config causes runtime failures",
      "severity": "critical",
      "category": "VALID",
      "file": "src/ChatAPI/Program.cs",
      "description": "All ten required configuration keys are accessed with null-forgiving operators (!) and no startup validation. A missing key allows the application to start and pass health probes, then fail mid-request with NullReferenceException, ArgumentNullException, or UriFormatException. Runtime failures are harder to diagnose and recover from than startup failures.",
      "recommendation": "Introduce typed options classes and call ValidateDataAnnotations().ValidateOnStart() so the application refuses to start when required configuration is absent.",
      "status": "open"
    },
    {
      "id": "ACFG-OPTIONS-001",
      "title": "Raw IConfiguration injection in service classes instead of typed options",
      "severity": "notable",
      "category": "OPTIONS",
      "file": "src/ChatAPI/Data/ProductData.cs",
      "description": "ProductData, ChatHistoryData, and GenerateProductInfo all accept IConfiguration as a constructor parameter and read config keys directly (e.g., config[\"CosmosDb_Database\"]!). This couples service classes to the configuration system, hides the configuration contract from the service signature, and bypasses validation.",
      "recommendation": "Create a CosmosDbOptions class, register it with services.Configure<CosmosDbOptions>(config.GetSection(\"CosmosDb\")), and inject IOptions<CosmosDbOptions> into the affected service constructors.",
      "status": "open"
    },
    {
      "id": "ACFG-OPTIONS-002",
      "title": "No typed options classes or IOptions<T> used anywhere in the project",
      "severity": "notable",
      "category": "OPTIONS",
      "file": "src/ChatAPI/Program.cs",
      "description": "The project does not define any typed options classes and does not use IOptions<T>, IOptionsMonitor<T>, or IOptionsSnapshot<T>. All configuration is consumed as raw string values with no type safety, validation, or discoverability.",
      "recommendation": "Define CosmosDbOptions, AzureOpenAIOptions, and AzureSearchOptions. Register each with services.Configure<T>() and inject via IOptions<T> in consuming classes.",
      "status": "open"
    },
    {
      "id": "ACFG-OPTIONS-003",
      "title": "Direct builder.Configuration[\"Key\"]! at service registration in Program.cs",
      "severity": "notable",
      "category": "OPTIONS",
      "file": "src/ChatAPI/Program.cs",
      "description": "Program.cs uses builder.Configuration[\"Key\"]! as captured values in AddSingleton factory lambdas for CosmosClient, AzureOpenAIClient, SearchClient, SearchIndexClient, and the OpenTelemetry monitor. These do not participate in the IOptions pipeline or validation.",
      "recommendation": "Replace direct configuration access in factory lambdas with IOptions<T> injection. Validate values before building the application using explicit null/empty checks or the ValidateOnStart() mechanism.",
      "status": "open"
    },
    {
      "id": "ACFG-SECRET-001",
      "title": "No Azure Key Vault integration in the configuration pipeline",
      "severity": "notable",
      "category": "SECRET",
      "file": "src/ChatAPI/Program.cs",
      "description": "Program.cs does not call AddAzureKeyVault(). The CosmosDb_ConnectionString is a sensitive value expected via environment variables with no audit trail or rotation support. DefaultAzureCredential is used for identity-based access where available, but the connection string is not covered.",
      "recommendation": "Add builder.Configuration.AddAzureKeyVault(new Uri(vaultUri), new DefaultAzureCredential()) to the configuration pipeline, or explicitly document that Azure Container Apps secrets injection is the accepted production secrets strategy.",
      "status": "open"
    },
    {
      "id": "ACFG-SECRET-002",
      "title": "No dotnet user-secrets configured for local development",
      "severity": "notable",
      "category": "SECRET",
      "file": "src/ChatAPI/ChatAPI.csproj",
      "description": "The .csproj file has no <UserSecretsId> element. Developers must manually configure all ten required environment variables to run the project locally. There is no .env.example or documented onboarding path for local configuration.",
      "recommendation": "Add <UserSecretsId> to the .csproj, document the required secrets using dotnet user-secrets set, and add an onboarding section to the README listing all required configuration keys.",
      "status": "open"
    },
    {
      "id": "ACFG-VALID-002",
      "title": "No ValidateDataAnnotations() or ValidateOnStart() for any options",
      "severity": "notable",
      "category": "VALID",
      "file": "src/ChatAPI/Program.cs",
      "description": "Even when typed options are adopted, validation must be explicitly enabled. services.Configure<T>() alone does not perform validation. Currently no options registration exists at all.",
      "recommendation": "When registering options, chain .ValidateDataAnnotations().ValidateOnStart() to eagerly validate all required options at application startup.",
      "status": "open"
    },
    {
      "id": "ACFG-ENV-001",
      "title": "Swagger unconditionally enabled — environment guard is commented out",
      "severity": "notable",
      "category": "ENV",
      "file": "src/ChatAPI/Program.cs",
      "line": 86,
      "description": "The IsDevelopment() guard around UseSwagger() and UseSwaggerUI() has been commented out. Swagger is enabled in all environments including production, exposing the full API schema and interactive UI publicly.",
      "recommendation": "Restore the environment guard or introduce a configuration flag (e.g., Swagger:Enabled defaulting to false) that can be explicitly enabled in appsettings.Development.json.",
      "status": "open"
    },
    {
      "id": "ACFG-CORS-001",
      "title": "AllowAll CORS policy hardcoded with no environment-specific override",
      "severity": "notable",
      "category": "CORS",
      "file": "src/ChatAPI/Program.cs",
      "line": 71,
      "description": "The CORS policy AllowAll (AllowAnyOrigin, AllowAnyHeader, AllowAnyMethod) is hardcoded and applied unconditionally in all environments. In production this allows any origin to call the API without restriction.",
      "recommendation": "Move allowed origins to configuration (e.g., Cors:AllowedOrigins array). In production, restrict to known frontend origins. Reserve AllowAnyOrigin for local development only, via appsettings.Development.json.",
      "status": "open"
    },
    {
      "id": "ACFG-STRUCT-001",
      "title": "No appsettings.Development.json or appsettings.Production.json",
      "severity": "minor",
      "category": "STRUCT",
      "file": "src/ChatAPI/",
      "description": "Only appsettings.json exists. There are no environment-specific override files for Development or Production. Environment-specific settings (log levels, Swagger, CORS, feature flags) are not separated.",
      "recommendation": "Add appsettings.Development.json with development-specific settings (verbose logging, Swagger enabled) and appsettings.Production.json with production hardening (stricter logging, Swagger disabled, restricted CORS).",
      "status": "open"
    },
    {
      "id": "ACFG-STRUCT-002",
      "title": "Required configuration keys undocumented — absent from appsettings.json",
      "severity": "minor",
      "category": "STRUCT",
      "file": "src/ChatAPI/appsettings.json",
      "description": "The ten required configuration keys are entirely absent from appsettings.json. A developer cloning the repository must read Program.cs and all service constructors to discover what configuration is required. There is no .env.example, README section, or configuration schema.",
      "recommendation": "Add placeholder entries to appsettings.json for all required keys with instructional values (e.g., \"<set via environment>\"). When typed options are adopted, the options class properties and [Required] annotations serve this purpose automatically.",
      "status": "open"
    },
    {
      "id": "ACFG-ENV-002",
      "title": "launchSettings.json has only one profile — no HTTPS or Staging profile",
      "severity": "minor",
      "category": "ENV",
      "file": "src/ChatAPI/Properties/launchSettings.json",
      "description": "Only a single http profile exists in launchSettings.json. There is no HTTPS profile for local TLS testing and no Staging profile for pre-production validation.",
      "recommendation": "Add a standard https profile with HTTPS application URL. This is a low-priority improvement aligned with ASP.NET Core scaffolding defaults.",
      "status": "open"
    },
    {
      "id": "ACFG-POSIT-001",
      "title": "No secrets committed to source control — appsettings.json is clean",
      "severity": "info",
      "category": "SECRET",
      "file": "src/ChatAPI/appsettings.json",
      "description": "appsettings.json contains only logging and host settings. No connection strings, API keys, or credentials are committed to source control. DefaultAzureCredential is used correctly for identity-based access to Azure OpenAI and Azure AI Search.",
      "recommendation": "No action required. Continue to enforce that appsettings.json and appsettings.*.json files never contain secret values.",
      "status": "open"
    }
  ],
  "summary": {
    "critical": 1,
    "notable": 7,
    "minor": 3,
    "info": 1,
    "total": 12
  }
}
