Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Canonical entities must enforce EF max-length caps and FK `Guid` validity at the
<!-- gitnexus:start -->
# GitNexus — Code Intelligence

This project is indexed by GitNexus as **PatchHound** (11164 symbols, 92808 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
This project is indexed by GitNexus as **PatchHound** (11435 symbols, 97109 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.

> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Canonical entities must enforce EF max-length caps and FK `Guid` validity at the
<!-- gitnexus:start -->
# GitNexus — Code Intelligence

This project is indexed by GitNexus as **PatchHound** (11164 symbols, 92808 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
This project is indexed by GitNexus as **PatchHound** (11435 symbols, 97109 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.

> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/ai-settings.schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const saveTenantAiProfileSchema = z.object({
apiVersion: z.string(),
keepAlive: z.string(),
allowExternalResearch: z.boolean(),
webResearchMode: z.enum(['Disabled', 'ProviderNative', 'PatchHoundManaged']),
webResearchMode: z.enum(['Disabled', 'ProviderNative', 'PatchHoundManaged', 'LocalVulnerabilityIntel']),
includeCitations: z.boolean(),
maxResearchSources: z.number().int().positive(),
allowedDomains: z.string(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,7 @@ function AiProfileEditorPage({
<div className="space-y-1">
<span className="text-sm font-medium text-foreground">Allow external web research</span>
<p className="text-sm text-muted-foreground">
Use recent external context when supported by the provider or by PatchHound-managed research.
Use recent external context when supported by the provider or by PatchHound-managed research. Vulnerability assessments always use local PatchHound intel first.
</p>
</div>
</label>
Expand All @@ -917,9 +917,19 @@ function AiProfileEditorPage({
{draft.providerType === 'OpenAi' ? (
<SelectItem value="ProviderNative">Provider native</SelectItem>
) : null}
<SelectItem value="LocalVulnerabilityIntel">Local vulnerability intel</SelectItem>
<SelectItem value="PatchHoundManaged">PatchHound managed</SelectItem>
</SelectContent>
</Select>
{draft.webResearchMode === 'PatchHoundManaged' ? (
<p className="mt-2 text-xs leading-5 text-muted-foreground">
PatchHound-managed external research sends search queries and fetched public pages through the configured research service.
</p>
Comment thread
FrodeHus marked this conversation as resolved.
) : draft.webResearchMode === 'LocalVulnerabilityIntel' ? (
<p className="mt-2 text-xs leading-5 text-muted-foreground">
Local vulnerability intel uses PatchHound and NVD cache data only. It does not perform external HTTP research.
</p>
) : null}
</Field>

<Field label="Max research sources" tooltip="Upper bound for external sources added to the research context.">
Expand Down
3 changes: 3 additions & 0 deletions src/PatchHound.Api/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@
},
"ConnectionStrings": {
"PatchHound": ""
},
"AiResearch": {
"JinaSearchProvider": "Google"
}
}
3 changes: 3 additions & 0 deletions src/PatchHound.Api/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
"Frontend": {
"Origin": "http://localhost:5173"
},
"AiResearch": {
"JinaSearchProvider": "Google"
},
"FeatureManagement": {
"Workflows": true,
"AuthenticatedScans": true
Expand Down
7 changes: 7 additions & 0 deletions src/PatchHound.Core/Enums/AiResearchProviderKind.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace PatchHound.Core.Enums;

public enum AiResearchProviderKind
{
ExternalWebSearch = 0,
LocalVulnerabilityIntel = 1,
}
1 change: 1 addition & 0 deletions src/PatchHound.Core/Enums/TenantAiWebResearchMode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ public enum TenantAiWebResearchMode
Disabled = 0,
ProviderNative = 1,
PatchHoundManaged = 2,
LocalVulnerabilityIntel = 3,
}
6 changes: 5 additions & 1 deletion src/PatchHound.Core/Models/AiWebResearchRequest.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
using PatchHound.Core.Enums;

namespace PatchHound.Core.Models;

public record AiWebResearchRequest(
string Query,
IReadOnlyList<string> AllowedDomains,
int MaxSources,
bool IncludeCitations
bool IncludeCitations,
IReadOnlyList<Guid>? VulnerabilityIds = null,
IReadOnlyList<AiResearchProviderKind>? Providers = null
);
5 changes: 4 additions & 1 deletion src/PatchHound.Infrastructure/DependencyInjection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,11 @@ void ConfigureDbContext(IServiceProvider sp, DbContextOptionsBuilder options) =>
services.AddScoped<ExecutiveDashboardBriefingService>();
services.AddScoped<IRiskChangeBriefAiSummaryService, RiskChangeBriefAiSummaryService>();
services.AddScoped<ITenantAiConfigurationResolver, TenantAiConfigurationResolver>();
services.Configure<AiResearchOptions>(configuration.GetSection(AiResearchOptions.SectionName));
services.AddScoped<LocalVulnerabilityIntelResearchProvider>();
services.AddScoped<ITenantAiResearchService, TenantAiResearchService>();
services
.AddHttpClient<ITenantAiResearchService, TenantAiResearchService>()
.AddHttpClient<ExternalWebSearchResearchProvider>()
.AddExternalHttpPolicies(maxConnectionsPerServer: 2);
services.AddScoped<ISetupService, SetupService>();
services.AddScoped<EnvironmentalSeverityCalculator>();
Expand Down
8 changes: 8 additions & 0 deletions src/PatchHound.Infrastructure/Options/AiResearchOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace PatchHound.Infrastructure.Options;

public class AiResearchOptions
{
public const string SectionName = "AiResearch";

public string JinaSearchProvider { get; set; } = "Google";
}
Loading
Loading