save progress
This commit is contained in:
@@ -2,4 +2,4 @@
|
||||
|
||||
### Unreleased
|
||||
|
||||
- CONCELIER0004: Flag direct `new HttpClient()` usage inside `StellaOps.Concelier.Connector*` namespaces; require sandboxed `IHttpClientFactory` to enforce allow/deny lists.
|
||||
- CONCELIER0004: Flag direct `new HttpClient()` usage inside `StellaOps.Concelier.Connector*` namespaces; require sandboxed `IHttpClientFactory` to enforce allow/deny lists. Exempts test assemblies and uses symbol-based namespace matching.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
@@ -36,18 +37,59 @@ public sealed class ConnectorHttpClientSandboxAnalyzer : DiagnosticAnalyzer
|
||||
return;
|
||||
}
|
||||
|
||||
var type = context.SemanticModel.GetTypeInfo(objectCreation, context.CancellationToken).Type;
|
||||
if (type?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) != "global::System.Net.Http.HttpClient")
|
||||
var httpClientSymbol = context.Compilation.GetTypeByMetadataName("System.Net.Http.HttpClient");
|
||||
if (httpClientSymbol is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var containingSymbol = context.ContainingSymbol?.ContainingNamespace?.ToDisplayString();
|
||||
if (containingSymbol is null || !containingSymbol.StartsWith("StellaOps.Concelier.Connector"))
|
||||
var createdType = context.SemanticModel
|
||||
.GetTypeInfo(objectCreation, context.CancellationToken)
|
||||
.Type;
|
||||
if (createdType is null || !SymbolEqualityComparer.Default.Equals(createdType, httpClientSymbol))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var assemblyName = context.ContainingSymbol?.ContainingAssembly?.Name;
|
||||
if (IsTestAssembly(assemblyName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var containingNamespace = context.ContainingSymbol?.ContainingNamespace;
|
||||
if (!IsConnectorNamespace(containingNamespace))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
context.ReportDiagnostic(Diagnostic.Create(Rule, objectCreation.GetLocation()));
|
||||
}
|
||||
|
||||
private static bool IsTestAssembly(string? assemblyName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(assemblyName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return assemblyName.EndsWith(".Tests", StringComparison.OrdinalIgnoreCase)
|
||||
|| assemblyName.EndsWith(".Test", StringComparison.OrdinalIgnoreCase)
|
||||
|| assemblyName.EndsWith(".Testing", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static bool IsConnectorNamespace(INamespaceSymbol? namespaceSymbol)
|
||||
{
|
||||
while (namespaceSymbol is not null && !namespaceSymbol.IsGlobalNamespace)
|
||||
{
|
||||
if (namespaceSymbol.ToDisplayString().Equals("StellaOps.Concelier.Connector", StringComparison.Ordinal))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
namespaceSymbol = namespaceSymbol.ContainingNamespace;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<IncludeBuildOutput>false</IncludeBuildOutput>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -7,4 +7,4 @@ Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0144-M | DONE | Maintainability audit for StellaOps.Concelier.Analyzers. |
|
||||
| AUDIT-0144-T | DONE | Test coverage audit for StellaOps.Concelier.Analyzers. |
|
||||
| AUDIT-0144-A | TODO | Pending approval for changes. |
|
||||
| AUDIT-0144-A | DONE | Applied analyzer hardening + tests. |
|
||||
|
||||
Reference in New Issue
Block a user