Add PHP Analyzer Plugin and Composer Lock Data Handling
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Implemented the PhpAnalyzerPlugin to analyze PHP projects. - Created ComposerLockData class to represent data from composer.lock files. - Developed ComposerLockReader to load and parse composer.lock files asynchronously. - Introduced ComposerPackage class to encapsulate package details. - Added PhpPackage class to represent PHP packages with metadata and evidence. - Implemented PhpPackageCollector to gather packages from ComposerLockData. - Created PhpLanguageAnalyzer to perform analysis and emit results. - Added capability signals for known PHP frameworks and CMS. - Developed unit tests for the PHP language analyzer and its components. - Included sample composer.lock and expected output for testing. - Updated project files for the new PHP analyzer library and tests.
This commit is contained in:
@@ -12,6 +12,7 @@ using StellaOps.Configuration;
|
||||
using StellaOps.DependencyInjection;
|
||||
using StellaOps.Findings.Ledger.Domain;
|
||||
using StellaOps.Findings.Ledger.Infrastructure;
|
||||
using StellaOps.Findings.Ledger.Infrastructure.AirGap;
|
||||
using StellaOps.Findings.Ledger.Infrastructure.Merkle;
|
||||
using StellaOps.Findings.Ledger.Infrastructure.Postgres;
|
||||
using StellaOps.Findings.Ledger.Infrastructure.Projection;
|
||||
@@ -140,6 +141,10 @@ builder.Services.AddSingleton<PolicyEngineEvaluationService>();
|
||||
builder.Services.AddSingleton<IPolicyEvaluationService>(sp => sp.GetRequiredService<PolicyEngineEvaluationService>());
|
||||
builder.Services.AddSingleton<ILedgerEventWriteService, LedgerEventWriteService>();
|
||||
builder.Services.AddSingleton<IFindingWorkflowService, FindingWorkflowService>();
|
||||
builder.Services.AddSingleton<IOrchestratorExportRepository, PostgresOrchestratorExportRepository>();
|
||||
builder.Services.AddSingleton<OrchestratorExportService>();
|
||||
builder.Services.AddSingleton<IAirgapImportRepository, PostgresAirgapImportRepository>();
|
||||
builder.Services.AddSingleton<AirgapImportService>();
|
||||
builder.Services.AddSingleton<IAttachmentEncryptionService, AttachmentEncryptionService>();
|
||||
builder.Services.AddSingleton<IAttachmentUrlSigner, AttachmentUrlSigner>();
|
||||
builder.Services.AddSingleton<IConsoleCsrfValidator, ConsoleCsrfValidator>();
|
||||
@@ -300,6 +305,95 @@ app.MapGet("/ledger/export/sboms", () => TypedResults.Json(new ExportPage<SbomEx
|
||||
.RequireAuthorization(LedgerExportPolicy)
|
||||
.Produces(StatusCodes.Status200OK);
|
||||
|
||||
app.MapPost("/internal/ledger/orchestrator-export", async Task<Results<Accepted<OrchestratorExportResponse>, ProblemHttpResult>> (
|
||||
HttpContext httpContext,
|
||||
OrchestratorExportRequest request,
|
||||
OrchestratorExportService service,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!httpContext.Request.Headers.TryGetValue("X-Stella-Tenant", out var tenantValues) || string.IsNullOrWhiteSpace(tenantValues))
|
||||
{
|
||||
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "missing_tenant");
|
||||
}
|
||||
|
||||
var tenantId = tenantValues.ToString();
|
||||
var input = new OrchestratorExportInput(
|
||||
tenantId,
|
||||
request.RunId,
|
||||
request.JobType,
|
||||
request.ArtifactHash,
|
||||
request.PolicyHash,
|
||||
request.StartedAt,
|
||||
request.CompletedAt,
|
||||
request.Status,
|
||||
request.ManifestPath,
|
||||
request.LogsPath);
|
||||
|
||||
var record = await service.RecordAsync(input, cancellationToken).ConfigureAwait(false);
|
||||
var response = new OrchestratorExportResponse(record.RunId, record.MerkleRoot);
|
||||
return TypedResults.Accepted($"/internal/ledger/orchestrator-export/{record.RunId}", response);
|
||||
})
|
||||
.WithName("OrchestratorExportRecord")
|
||||
.RequireAuthorization(LedgerWritePolicy)
|
||||
.Produces(StatusCodes.Status202Accepted)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest);
|
||||
|
||||
app.MapGet("/internal/ledger/orchestrator-export/{artifactHash}", async Task<Results<JsonHttpResult<IReadOnlyList<OrchestratorExportRecord>>, ProblemHttpResult>> (
|
||||
HttpContext httpContext,
|
||||
string artifactHash,
|
||||
OrchestratorExportService service,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!httpContext.Request.Headers.TryGetValue("X-Stella-Tenant", out var tenantValues) || string.IsNullOrWhiteSpace(tenantValues))
|
||||
{
|
||||
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "missing_tenant");
|
||||
}
|
||||
|
||||
var records = await service.GetByArtifactAsync(tenantValues.ToString(), artifactHash, cancellationToken).ConfigureAwait(false);
|
||||
return TypedResults.Json(records);
|
||||
})
|
||||
.WithName("OrchestratorExportQuery")
|
||||
.RequireAuthorization(LedgerExportPolicy)
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest);
|
||||
|
||||
app.MapPost("/internal/ledger/airgap-import", async Task<Results<Accepted<AirgapImportResponse>, ProblemHttpResult>> (
|
||||
HttpContext httpContext,
|
||||
AirgapImportRequest request,
|
||||
AirgapImportService service,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!httpContext.Request.Headers.TryGetValue("X-Stella-Tenant", out var tenantValues) || string.IsNullOrWhiteSpace(tenantValues))
|
||||
{
|
||||
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "missing_tenant");
|
||||
}
|
||||
|
||||
var input = new AirgapImportInput(
|
||||
tenantValues.ToString(),
|
||||
request.BundleId,
|
||||
request.MirrorGeneration,
|
||||
request.MerkleRoot,
|
||||
request.TimeAnchor,
|
||||
request.Publisher,
|
||||
request.HashAlgorithm,
|
||||
request.Contents ?? Array.Empty<string>(),
|
||||
request.ImportOperator);
|
||||
|
||||
var result = await service.RecordAsync(input, cancellationToken).ConfigureAwait(false);
|
||||
if (!result.Success)
|
||||
{
|
||||
return TypedResults.Problem(statusCode: StatusCodes.Status409Conflict, title: "airgap_import_failed", detail: result.Error ?? "Failed to record air-gap import.");
|
||||
}
|
||||
|
||||
var response = new AirgapImportResponse(result.ChainId, result.SequenceNumber, result.LedgerEventId, "accepted", null);
|
||||
return TypedResults.Accepted($"/internal/ledger/airgap-import/{request.BundleId}", response);
|
||||
})
|
||||
.WithName("AirgapImportRecord")
|
||||
.RequireAuthorization(LedgerWritePolicy)
|
||||
.Produces(StatusCodes.Status202Accepted)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest)
|
||||
.ProducesProblem(StatusCodes.Status409Conflict);
|
||||
|
||||
app.Run();
|
||||
|
||||
static Created<LedgerEventResponse> CreateCreatedResponse(LedgerEventRecord record)
|
||||
|
||||
Reference in New Issue
Block a user