Skip to content

fix(security): log the error code instead of EncinaError.Message in EF Core, Marten and GraphQL (#1328) - #1397

Merged
dlrivada merged 8 commits into
mainfrom
fix/error-message-logs-1328
Sep 27, 2026
Merged

dlrivada merged 8 commits into
mainfrom
fix/error-message-logs-1328

Conversation

@dlrivada

@dlrivada dlrivada commented Sep 26, 2026 •

Copy link
Copy Markdown
Owner

Summary

EncinaError.Message must never reach a log (AGENTS.md §3, "only the error code or the exception type is recorded"). Five call sites in Encina.EntityFrameworkCore, Encina.Marten and Encina.GraphQL logged it, and the sibling search found a sixth in Marten's inline projection relay.

What changed

  • The call sites now log error.GetEncinaCode():
    • TransactionPipelineBehavior.cs (EF Core);
    • DomainEvents/DomainEventDispatcherInterceptor.cs (EF Core);
    • EventPublishingPipelineBehavior.cs (Marten);
    • Projections/InlineProjectionRelay.cs (Marten, found by the sibling search);
    • GraphQLMediatorBridge.cs, query and mutation paths (GraphQL).
  • The [LoggerMessage] templates in each package's Log.cs and in Marten's ProjectionLog.cs use {ErrorCode} instead of the message placeholder. EventIds are unchanged. The dead SkippingOutboxStorageDueToError template was renamed the same way for consistency.
  • src/Encina/Encina.csproj: InternalsVisibleTo for Encina.Marten and Encina.GraphQL. GetEncinaCode() is internal to core, and EF Core already had this access.
  • Regression tests next to each class's existing tests. Each drives the failure path with an EncinaError whose message carries the sentinel SENTINEL-do-not-log-4f2a, then asserts that no log entry contains the sentinel and that the error code is logged.
  • changelog.d/1328-error-message-logs.security.md and the knowledge record docs/knowledge/issues/1328.md.

Verification

  • Release build of Encina.slnx: 0 warnings, 0 errors.
  • The five touched test classes: 69 passed, 0 failed.
  • dotnet format --verify-no-changes clean on the changed files. changelog-fragments --check and knowledge-records --check OK.
  • Sibling search across the three packages covered error.Message, Activity.SetStatus and SetTag, plus the health checks. No remaining sink was found. The remaining hits put the message into a thrown exception, which is the ROP boundary, or into a new EncinaError returned as Left. Two ActivitySource.Failed helpers that take a message have no caller.
  • The before/after run of the new tests on the old code was not executed. Reverting the files in the worktree was refused by the sandbox. Each test asserts the sentinel's absence while the old code logged error.Message, which contains the sentinel, so every test fails on the old code by construction. The reviewer reached the same conclusion independently.
  • Self-review by adversarial-reviewer: no blocker or major. One minor was fixed: the dead template rename. The other, README examples still showing the anti-pattern, is filed as [DEBT] EF Core and GraphQL package READMEs still show error.Message in log/error examples #1396.

Cross-cutting checklist (ADR-018)

Security fix at existing log call sites. Structured logging is integrated: the templates now carry the error code only, and EventIds are unchanged. The other eleven functions are not applicable, because no new entity, store, behavior or integration is added.

Fixes #1328

Summary by CodeRabbit

  • Mejoras
    • Los registros de errores de EF Core, Marten y GraphQL muestran ahora el código del error en lugar de su mensaje. Esto ofrece información más uniforme al revisar fallos de transacciones, publicación de eventos, proyecciones y consultas.
    • Los mensajes de error que reciben las aplicaciones y el comportamiento de las operaciones afectadas se mantienen sin cambios.

…d GraphQL

Replace the free-text error.Message with error.GetEncinaCode() in the four
Log.cs call sites named in #1328 (TransactionPipelineBehavior,
DomainEventDispatcherInterceptor, EventPublishingPipelineBehavior,
GraphQLMediatorBridge), plus one sibling found by the same search
(InlineProjectionRelay's InlineProjectionFailedAfterSave log). Rename each
LoggerMessage template placeholder from the message name to an error-code
name, keeping EventIds unchanged. Grant Encina.Marten and Encina.GraphQL
InternalsVisibleTo access to Encina so they can call the internal
GetEncinaCode() extension, matching Encina.EntityFrameworkCore's existing
access.

Add a regression test per fixed call site that drives the failure path with
a sentinel-bearing EncinaError and asserts the sentinel never reaches the
log while the error code does.
@coderabbitai

coderabbitai Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Repository: dlrivada/Encina/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 6967370f-3d1a-44f1-b41b-abba73cb56af

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: dlrivada/Encina/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: f9152703-cfef-4900-a486-95ec63fdc46b

📥 Commits

Reviewing files that changed from the base of the PR and between 7d636ed and 524cbc8.

📒 Files selected for processing (17)
  • changelog.d/1328-error-message-logs.security.md
  • docs/knowledge/issues/1328.md
  • src/Encina.EntityFrameworkCore/DomainEvents/DomainEventDispatcherInterceptor.cs
  • src/Encina.EntityFrameworkCore/Log.cs
  • src/Encina.EntityFrameworkCore/TransactionPipelineBehavior.cs
  • src/Encina.GraphQL/GraphQLMediatorBridge.cs
  • src/Encina.GraphQL/Log.cs
  • src/Encina.Marten/EventPublishingPipelineBehavior.cs
  • src/Encina.Marten/Log.cs
  • src/Encina.Marten/Projections/InlineProjectionRelay.cs
  • src/Encina.Marten/Projections/ProjectionLog.cs
  • src/Encina/Encina.csproj
  • tests/Encina.UnitTests/EntityFrameworkCore/DomainEvents/DomainEventDispatcherInterceptorTests.cs
  • tests/Encina.UnitTests/EntityFrameworkCore/TransactionPipelineBehaviorIntegrationTests.cs
  • tests/Encina.UnitTests/GraphQL/GraphQLEncinaBridgeTests.cs
  • tests/Encina.UnitTests/Marten/EventPublishingPipelineBehaviorTests.cs
  • tests/Encina.UnitTests/Marten/Projections/InlineProjectionRelayTests.cs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Los registros modificados en EF Core, GraphQL y Marten usan códigos de error de Encina en lugar de mensajes libres. Se añaden pruebas que verifican el código registrado y la ausencia del texto centinela.

Changes

Registro de errores en integraciones

Layer / File(s) Summary
Registros y pruebas de EF Core
src/Encina.EntityFrameworkCore/*, tests/Encina.UnitTests/EntityFrameworkCore/*
Los registros de rollback y de fallos de publicación usan el código de error. Las pruebas comprueban que el mensaje centinela no aparece en los registros. El texto del mensaje sigue usándose en la excepción cuando StopOnFirstError está activo.
Registros y pruebas de GraphQL
src/Encina.GraphQL/*, src/Encina/Encina.csproj, tests/Encina.UnitTests/GraphQL/*
Los fallos de consultas y mutaciones registran el código de error. Las pruebas cubren ambos casos y comprueban que el mensaje centinela no se registra.
Registros y pruebas de Marten
src/Encina.Marten/*, tests/Encina.UnitTests/Marten/*, changelog.d/1328-error-message-logs.security.md, docs/knowledge/issues/1328.md
La publicación de eventos y los fallos de proyección registran el código de error. Las pruebas verifican que el mensaje centinela no aparece en los registros. Las respuestas de error y el resultado de proyección tolerado conservan su comportamiento descrito. Se añaden notas de cambio y de conocimiento de la incidencia.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 524cb

The identified EF Core, GraphQL, and Marten logs use error codes rather than free-text error messages. No issue in the supplied evidence currently prevents merging.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.42% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 38 functions across 14 files. (3 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed El título identifica de forma clara y concisa el cambio principal: registrar el código de error en lugar de EncinaError.Message en EF Core, Marten y GraphQL.
Description check ✅ Passed La descripción explica el problema, los cambios, las pruebas, la verificación, el alcance y la incidencia relacionada. No incluye la sección formal "Type of Change" ni marca las casillas del checklist…
Linked Issues check ✅ Passed La PR cumple los requisitos de código de #1328. EF Core, Marten y GraphQL pasan error.GetEncinaCode() a los registros afectados. Las plantillas usan {ErrorCode}. La PR conserva los EventId. Tamb…
Out of Scope Changes check ✅ Passed Los cambios permanecen dentro del alcance de #1328. Los cambios en Log.cs, los puntos de llamada, las pruebas, InternalsVisibleTo y la documentación de la incidencia implementan o documentan la el…
Full details: Docstring Coverage

Explanation

Docstring coverage is 18.42% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 38 functions across 14 files. (3 skipped: 3 unsupported.)

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@dlrivada
dlrivada enabled auto-merge (squash) September 26, 2026 11:51
@dlrivada

Copy link
Copy Markdown
Owner Author

CodeRabbit reported "Review limit reached" when the review was requested (2026-09-26 ~13:50 CEST). Per the pr-cycle procedure the merge does not wait for it: this PR already had an adversarial-reviewer pass before opening (no blocker or major; one minor fixed, one filed as #1396). The maintainer will request the CodeRabbit review again once the limit resets; any thread it opens blocks the auto-merge until answered.

@codecov

codecov Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

…CRAP under 10

CI's crap-gate job flagged Handle (complexity 12, CRAP 12.42) after #1328's
one-line error.GetEncinaCode() change pulled it into the gate. Extract the
new-transaction path into ExecuteInNewTransactionAsync, the commit/rollback
Match into CommitOrRollbackAsync, and the shared rollback-if-active check
into RollbackIfActiveAsync. No behavior change; existing tests pass
unmodified.
…ng CRAP under 10

CI's crap-gate job flagged Handle (complexity 18, CRAP 18.82) after #1328's
one-line error.GetEncinaCode() change pulled it into the gate. Extract the
pending-notification LINQ query into GetPendingNotifications and the
per-event publish-and-log-on-failure logic into PublishEventAsync. No
behavior change; existing tests pass unmodified.
…r 10

CI's crap-gate job flagged DispatchDomainEventsAsync (complexity 18,
coverage 65%, CRAP 31.63) after #1328's one-line error.GetEncinaCode()
change pulled it into the gate. Extract the INotification resolution check
into TryResolveNotification, the per-event publish/try-catch into
DispatchSingleEventAsync, the failed-publish logging and StopOnFirstError
handling into HandlePublishFailure, and the post-dispatch entity clearing
into ClearEntities. No behavior change; existing tests pass unmodified.
The crap-gate job measures the compiler-generated async state machine
(<Handle>d__5.MoveNext), which folds every await point of one async method
into a single complexity score (#1355: MoveNext attribution). With the
publish-loop's await still inside Handle, its MoveNext stayed at complexity
10 (CRAP 10.29). Move the loop into PublishPendingEventsAsync so each async
method's state machine covers fewer branches. No behavior change.
@dlrivada

Copy link
Copy Markdown
Owner Author

The first CI run failed the blocking crap-gate: the #1328 one-line fixes pulled three long pre-existing methods into the gate (CRAP 31.6, 18.8, 12.4). Four behaviour-preserving splits follow (61a2545, 61869a9, c10c435, eb7b327): TransactionPipelineBehavior.Handle, EventPublishingPipelineBehavior.Handle and DomainEventDispatcherInterceptor.DispatchDomainEventsAsync now delegate to small helpers. Local run of the gate script on real coverage: "No changed method exceeds the CRAP threshold" (25 changed methods). Build 0 warnings, 88/88 tests of the six touched classes pass, the sentinel regression tests are untouched, and a second adversarial review found no issue.

@dlrivada
dlrivada merged commit a806ab6 into main Sep 27, 2026
48 checks passed
@dlrivada
dlrivada deleted the fix/error-message-logs-1328 branch September 27, 2026 09:12
dlrivada added a commit that referenced this pull request Sep 27, 2026
dlrivada added a commit that referenced this pull request Sep 27, 2026
…as the review-bot fallback (#1447) (#1458)

* docs(plans): implementation plan for pr-reviewer agent (#1447)

* feat(agents): add pr-reviewer agent definition (#1447)

* feat(hooks): wire pr-reviewer into spawn/publish/path-ownership hooks (#1447)

* test(hooks): add pr-reviewer regression cases to Test-Hooks.ps1 (#1447)

* docs(pr-cycle): trigger pr-reviewer instead of adversarial-reviewer when CodeRabbit is unavailable (#1447)

* docs(engineering): sync pr-reviewer agent into routing table and history (#1447)

Adds pr-reviewer to the Claude subagent tier table in ai-task-routing.md
(kept verbatim in sync with .claude/agents/README.md) and records it as
item 15 of the 2026-09-23 agent system review in AI-DEVELOPMENT-MODEL.md.

* docs(knowledge): record pr-reviewer implementation and #1397/#1399 dry-run comparison (#1447)

* fix(agents): wire enforce-path-ownership on pr-reviewer's Bash|PowerShell matcher too

* docs(knowledge): record the self-review finding and fix (#1447)

* docs(knowledge): link PR #1458 in the #1447 record

---------

Co-authored-by: dlrivada <3762783+dlrivada@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] EF Core, Marten and GraphQL log EncinaError.Message through their Log.cs templates

1 participant