Complete Entrypoint Detection Re-Engineering Program (Sprints 0410-0415) and Sprint 3500.0002.0003 (Proof Replay + API)

Entrypoint Detection Program (100% complete):
- Sprint 0411: Semantic Entrypoint Engine - all 25 tasks DONE
- Sprint 0412: Temporal & Mesh Entrypoint - all 19 tasks DONE
- Sprint 0413: Speculative Execution Engine - all 19 tasks DONE
- Sprint 0414: Binary Intelligence - all 19 tasks DONE
- Sprint 0415: Predictive Risk Scoring - all tasks DONE

Key deliverables:
- SemanticEntrypoint schema with ApplicationIntent/CapabilityClass
- TemporalEntrypointGraph and MeshEntrypointGraph
- ShellSymbolicExecutor with PathEnumerator and PathConfidenceScorer
- CodeFingerprint index with symbol recovery
- RiskScore with multi-dimensional risk assessment

Sprint 3500.0002.0003 (Proof Replay + API):
- ManifestEndpoints with DSSE content negotiation
- Proof bundle endpoints by root hash
- IdempotencyMiddleware with RFC 9530 Content-Digest
- Rate limiting (100 req/hr per tenant)
- OpenAPI documentation updates

Tests: 357 EntryTrace tests pass, WebService tests blocked by pre-existing infrastructure issue
This commit is contained in:
StellaOps Bot
2025-12-20 17:46:27 +02:00
parent ce8cdcd23d
commit 3698ebf4a8
46 changed files with 4156 additions and 46 deletions

View File

@@ -0,0 +1,84 @@
namespace StellaOps.Signals.Services;
/// <summary>
/// Abstraction for creating rescan jobs in the scheduler.
/// Allows Signals to integrate with the Scheduler module without tight coupling.
/// </summary>
public interface ISchedulerJobClient
{
/// <summary>
/// Creates a targeted rescan job for a specific package.
/// </summary>
/// <param name="request">The rescan job request.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Result indicating success or failure with job ID.</returns>
Task<SchedulerJobResult> CreateRescanJobAsync(
RescanJobRequest request,
CancellationToken cancellationToken = default);
/// <summary>
/// Creates multiple rescan jobs in a batch.
/// </summary>
Task<BatchSchedulerJobResult> CreateRescanJobsAsync(
IReadOnlyList<RescanJobRequest> requests,
CancellationToken cancellationToken = default);
}
/// <summary>
/// Request for creating a rescan job.
/// </summary>
/// <param name="TenantId">Tenant identifier.</param>
/// <param name="UnknownId">ID of the unknown being rescanned.</param>
/// <param name="PackageUrl">Package URL (purl) to rescan.</param>
/// <param name="PackageVersion">Version to rescan (optional).</param>
/// <param name="Priority">Job priority level.</param>
/// <param name="CorrelationId">Correlation ID for tracing.</param>
public sealed record RescanJobRequest(
string TenantId,
string UnknownId,
string PackageUrl,
string? PackageVersion,
RescanJobPriority Priority,
string? CorrelationId = null);
/// <summary>
/// Priority level for rescan jobs.
/// </summary>
public enum RescanJobPriority
{
/// <summary>Immediate processing (HOT band).</summary>
High,
/// <summary>Normal processing (WARM band).</summary>
Normal,
/// <summary>Low priority batch processing (COLD band).</summary>
Low
}
/// <summary>
/// Result from creating a scheduler job.
/// </summary>
/// <param name="Success">Whether the job was created.</param>
/// <param name="JobId">Scheduler job ID if successful.</param>
/// <param name="RunId">Run ID in the scheduler.</param>
/// <param name="ErrorMessage">Error message if failed.</param>
public sealed record SchedulerJobResult(
bool Success,
string? JobId = null,
string? RunId = null,
string? ErrorMessage = null)
{
public static SchedulerJobResult Succeeded(string jobId, string runId)
=> new(true, jobId, runId);
public static SchedulerJobResult Failed(string error)
=> new(false, ErrorMessage: error);
}
/// <summary>
/// Result from batch job creation.
/// </summary>
public sealed record BatchSchedulerJobResult(
int TotalRequested,
int SuccessCount,
int FailureCount,
IReadOnlyList<SchedulerJobResult> Results);

View File

@@ -0,0 +1,65 @@
using Microsoft.Extensions.Logging;
namespace StellaOps.Signals.Services;
/// <summary>
/// Null implementation of <see cref="ISchedulerJobClient"/> that logs requests
/// but does not actually create jobs. Used when Scheduler integration is not configured.
/// </summary>
public sealed class NullSchedulerJobClient : ISchedulerJobClient
{
private readonly TimeProvider _timeProvider;
private readonly ILogger<NullSchedulerJobClient> _logger;
public NullSchedulerJobClient(
TimeProvider timeProvider,
ILogger<NullSchedulerJobClient> logger)
{
_timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public Task<SchedulerJobResult> CreateRescanJobAsync(
RescanJobRequest request,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(request);
_logger.LogDebug(
"Null scheduler client: Would create rescan job for unknown {UnknownId} (purl={Purl})",
request.UnknownId,
request.PackageUrl);
// Generate a fake job ID for testing/development
var jobId = $"null-job-{Guid.NewGuid():N}";
var runId = $"null-run-{_timeProvider.GetUtcNow():yyyyMMddHHmmss}";
return Task.FromResult(SchedulerJobResult.Succeeded(jobId, runId));
}
public Task<BatchSchedulerJobResult> CreateRescanJobsAsync(
IReadOnlyList<RescanJobRequest> requests,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(requests);
_logger.LogDebug(
"Null scheduler client: Would create {Count} rescan jobs",
requests.Count);
var results = requests
.Select(r =>
{
var jobId = $"null-job-{Guid.NewGuid():N}";
var runId = $"null-run-{_timeProvider.GetUtcNow():yyyyMMddHHmmss}";
return SchedulerJobResult.Succeeded(jobId, runId);
})
.ToList();
return Task.FromResult(new BatchSchedulerJobResult(
requests.Count,
requests.Count,
0,
results));
}
}

View File

@@ -0,0 +1,189 @@
using Microsoft.Extensions.Logging;
using StellaOps.Signals.Models;
namespace StellaOps.Signals.Services;
/// <summary>
/// Implementation of <see cref="IRescanOrchestrator"/> that integrates with
/// the Scheduler module via <see cref="ISchedulerJobClient"/>.
/// </summary>
public sealed class SchedulerRescanOrchestrator : IRescanOrchestrator
{
private readonly ISchedulerJobClient _schedulerClient;
private readonly TimeProvider _timeProvider;
private readonly ILogger<SchedulerRescanOrchestrator> _logger;
public SchedulerRescanOrchestrator(
ISchedulerJobClient schedulerClient,
TimeProvider timeProvider,
ILogger<SchedulerRescanOrchestrator> logger)
{
_schedulerClient = schedulerClient ?? throw new ArgumentNullException(nameof(schedulerClient));
_timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task<RescanResult> TriggerRescanAsync(
UnknownSymbolDocument unknown,
RescanPriority priority,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(unknown);
var request = CreateJobRequest(unknown, priority);
_logger.LogInformation(
"Creating rescan job for unknown {UnknownId} (purl={Purl}, priority={Priority})",
unknown.Id,
unknown.Purl,
priority);
try
{
var result = await _schedulerClient.CreateRescanJobAsync(request, cancellationToken)
.ConfigureAwait(false);
if (result.Success)
{
_logger.LogDebug(
"Rescan job {JobId} created for unknown {UnknownId}",
result.JobId,
unknown.Id);
return new RescanResult(
unknown.Id,
Success: true,
NextScheduledRescan: ComputeNextRescan(priority));
}
_logger.LogWarning(
"Failed to create rescan job for unknown {UnknownId}: {Error}",
unknown.Id,
result.ErrorMessage);
return new RescanResult(
unknown.Id,
Success: false,
ErrorMessage: result.ErrorMessage);
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
_logger.LogError(ex, "Exception creating rescan job for unknown {UnknownId}", unknown.Id);
return new RescanResult(
unknown.Id,
Success: false,
ErrorMessage: ex.Message);
}
}
public async Task<BatchRescanResult> TriggerBatchRescanAsync(
IReadOnlyList<UnknownSymbolDocument> unknowns,
RescanPriority priority,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(unknowns);
if (unknowns.Count == 0)
{
return new BatchRescanResult(0, 0, 0, []);
}
var requests = unknowns
.Select(u => CreateJobRequest(u, priority))
.ToList();
_logger.LogInformation(
"Creating {Count} rescan jobs with priority {Priority}",
requests.Count,
priority);
try
{
var batchResult = await _schedulerClient.CreateRescanJobsAsync(requests, cancellationToken)
.ConfigureAwait(false);
var rescanResults = batchResult.Results
.Zip(unknowns, (jobResult, unknown) => new RescanResult(
unknown.Id,
jobResult.Success,
jobResult.ErrorMessage,
jobResult.Success ? ComputeNextRescan(priority) : null))
.ToList();
_logger.LogInformation(
"Batch rescan complete: {Success}/{Total} succeeded",
batchResult.SuccessCount,
batchResult.TotalRequested);
return new BatchRescanResult(
batchResult.TotalRequested,
batchResult.SuccessCount,
batchResult.FailureCount,
rescanResults);
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
_logger.LogError(ex, "Exception in batch rescan for {Count} unknowns", unknowns.Count);
var failedResults = unknowns
.Select(u => new RescanResult(u.Id, Success: false, ErrorMessage: ex.Message))
.ToList();
return new BatchRescanResult(
unknowns.Count,
0,
unknowns.Count,
failedResults);
}
}
private RescanJobRequest CreateJobRequest(UnknownSymbolDocument unknown, RescanPriority priority)
{
var jobPriority = priority switch
{
RescanPriority.Immediate => RescanJobPriority.High,
RescanPriority.Scheduled => RescanJobPriority.Normal,
_ => RescanJobPriority.Low
};
// Extract tenant from the unknown context
// For now, use a default tenant if not available
var tenantId = ExtractTenantId(unknown);
return new RescanJobRequest(
TenantId: tenantId,
UnknownId: unknown.Id,
PackageUrl: unknown.Purl ?? unknown.SubjectKey,
PackageVersion: unknown.PurlVersion,
Priority: jobPriority,
CorrelationId: unknown.CallgraphId);
}
private static string ExtractTenantId(UnknownSymbolDocument unknown)
{
// The CallgraphId often follows pattern: {tenant}:{graph-id}
// If not available, use a default
if (string.IsNullOrEmpty(unknown.CallgraphId))
{
return "default";
}
var colonIndex = unknown.CallgraphId.IndexOf(':', StringComparison.Ordinal);
return colonIndex > 0
? unknown.CallgraphId[..colonIndex]
: "default";
}
private DateTimeOffset ComputeNextRescan(RescanPriority priority)
{
var now = _timeProvider.GetUtcNow();
return priority switch
{
RescanPriority.Immediate => now.AddMinutes(15), // Re-evaluate after 15 min
RescanPriority.Scheduled => now.AddHours(24), // Next day for WARM
_ => now.AddDays(7) // Weekly for COLD
};
}
}