fix(cv): harden document parsing

Upgrade and hash-lock upload-facing parser dependencies, reject resource-heavy or mismatched inputs, remove unsafe backend binary fallbacks, and prevent internal parser failures from leaking to users.
This commit is contained in:
cesnimda
2026-08-30 11:00:52 +02:00
parent a74daa7aa4
commit a8bf505ce5
14 changed files with 1869 additions and 110 deletions
@@ -231,11 +231,15 @@ public sealed partial class ProfileCvController : ControllerBase
if (string.IsNullOrWhiteSpace(text))
{
text = (await ExtractTextAsync(file, extension)).Trim();
text = (await ExtractPlainTextAsync(file, extension, cancellationToken)).Trim();
}
if (string.IsNullOrWhiteSpace(text))
{
throw new InvalidOperationException("The uploaded CV file could not be read or was empty.");
throw new InvalidOperationException(
string.Equals(extension, ".txt", StringComparison.OrdinalIgnoreCase) ||
string.Equals(extension, ".md", StringComparison.OrdinalIgnoreCase)
? "The uploaded CV file could not be read or was empty."
: "The document extraction service could not read this CV safely.");
}
text = RepairKnownMojibake(text);
@@ -506,8 +510,12 @@ public sealed partial class ProfileCvController : ControllerBase
{
var generationFailure = ex as AiGenerationException;
var retryable = generationFailure?.Retryable == true;
var failureMessage = generationFailure?.Message
?? (ex is InvalidOperationException
? ex.Message
: "CV processing failed unexpectedly. Please try again.");
run.Status = retryable ? "queued" : "failed";
run.ErrorMessage = ex.Message;
run.ErrorMessage = failureMessage;
run.CompletedAtUtc = retryable ? null : DateTimeOffset.UtcNow;
await _db.SaveChangesAsync(cancellationToken);
if (!retryable)
@@ -519,7 +527,7 @@ public sealed partial class ProfileCvController : ControllerBase
return new CvProcessingOutcome(
false,
generationFailure?.Category ?? "cv_processing_failed",
ex.Message,
failureMessage,
retryable,
generationFailure?.Provider,
generationFailure?.Model,