Skip to content

Conversation

mgoworko
Copy link
Collaborator

@mgoworko mgoworko commented Jul 25, 2025

🚀New (ES) added new audit serializers - ReportingAllEventsAuditLogSerializer, ReportingAllEventsWithQueryAuditLogSerializer
🚀New (ES) There is an option to define custom audit serializer in config, without implementation
🐞Fix (ES) Restored backwards compatibility of custom audit log serializer implementations, that extend the DefaultAuditLogSerializer class. The custom serializers compiled against ROR 1.65 and 1.66, that use DefaultAuditLogSerializer have to be recompiled in order to work.

Summary by CodeRabbit

  • New Features

    • Added configurable audit log serializer with custom fields and verbosity modes.
    • Introduced FullAuditLogSerializer and FullAuditLogWithQuerySerializer (includes environment and optional request content).
    • Audit entries can include ES node/cluster info and richer request details.
  • Changes

    • Default audit serializer updated to a verbosity-aware variant (backward-compatible aliases retained).
    • Simplified default sink setup; no explicit environment needed when constructing defaults.
    • Configuration now supports structured “serializer” blocks; plain class-name syntax remains supported.

@mgoworko mgoworko marked this pull request as ready for review July 25, 2025 19:28

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as outdated.

@mgoworko mgoworko marked this pull request as draft July 25, 2025 20:16
@mgoworko mgoworko marked this pull request as ready for review July 28, 2025 15:35
@mgoworko mgoworko requested a review from coutoPL July 28, 2025 15:35
coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as outdated.

@mgoworko mgoworko requested a review from coutoPL August 19, 2025 18:30
coderabbitai[bot]

This comment was marked as outdated.

@mgoworko mgoworko requested a review from coutoPL August 27, 2025 21:40
coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as outdated.

@mgoworko mgoworko requested a review from coutoPL August 29, 2025 12:47
override def onResponse(responseContext: AuditResponseContext): Option[JSONObject] =
AuditSerializationHelper.serialize(
responseContext = responseContext,
fields = queryV2AuditFields,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. Maybe it's worth redefining the fields.

I wonder if we shouldn't do it like this:

  1. if this is a separate/new/different serializer, let's define all the fields in a companion object
  2. if this is an alias, it should extend some serializer and won't redefine fields (it should not even override onResponse)
  3. if this is a serializer that extends another serializer, let's use the fields from the extended serializer and add new ones (but maybe it means that it'd be better to add these fields at the class definition's level, not the companion object's level)

WDYT?
If it makes sense, let's refactor all the serializers to follow these rules.
Maybe we should also add them to our internal repo (or in the form of an ADR).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose (and implemented) something a bit different, IMO more readable and with less duplicates.

  • the fields are mostly the same between serializers, and I don't like the idea of duplicating the lists - it creates space for bugs and ommisions
  • there are only 3 sets of fields: common fields (most fields, present in all serializers that we provide), ES environment related fields (added in 1414 and present in new, V2 and environment-aware serializers), and full content field
  • the serializers do not extend each other now after this PR (there are only name aliases, but not reusing and modifying other class)
  • each serializer (provided by us in our codebase) has implementation like shown below
  • so it defines which field groups are used, and which allowed events are serialized
  • serializers do not extend each other, but instead each uses AuditSerializationHelper.serialize with appropriate field groups and allowed event mode
  override def onResponse(responseContext: AuditResponseContext): Option[JSONObject] =
    AuditSerializationHelper.serialize(
      responseContext = responseContext,
      fieldGroups = Set(CommonFields, EsEnvironmentFields, FullRequestContentFields),
      allowedEventMode = IncludeAll
    )

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it creates space for bugs and ommisions

Yes, but it also creates a possibility of adding a new field to some serializer unintentionally.

So, both approaches are error-prone.
But it's ok when we add proper unit tests ;) So, let's add a unit test for each serializer to check what fields it produces. To work as expected (to eliminate or at least lower the possibility of the bug I mentioned above), we should hardcode the list in the test (but hardcoding in tests is not a problem for us, right ;)).

It may be tedious, so let's try to use LLM to help us with this boring task ;)

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@mgoworko mgoworko requested a review from coutoPL September 5, 2025 16:37
/**
* Base implementation delegating to [[DefaultAuditLogSerializerV2]].
*
* - Not intended for direct external use.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we should annotate it as deprecated instead?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we rename the class name?

@@ -17,82 +17,35 @@
package tech.beshu.ror.audit.instances
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same comments in this file

*
* Recommended when a minimal, compact audit log is sufficient.
*/
class BlockVerbosityAwareAuditLogSerializerV1 extends DefaultAuditLogSerializerV1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get why we introduce V1 and V2 for the "new" serializer (to be strict - renamed).

I took into consideration two things:

  1. backward compatibility - we don't have to do that
  2. documentation - how are we going to explain to our users (new users, and users who have ROR already installed) in simple words the V1 and V2? - so it may be misleading for them. Do they need it? I suppose - no.

/**
* Serializer for audit events that is aware of **rule-defined verbosity**.
*
* - Includes `CommonFields` and `EsEnvironmentFields`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CommonFields, EsEnvironmentFields, ... are implementation details. Let's list all the fields in the description (with one line explanation if possible)

override def onResponse(responseContext: AuditResponseContext): Option[JSONObject] =
AuditSerializationHelper.serialize(
responseContext = responseContext,
fields = queryV2AuditFields,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it creates space for bugs and ommisions

Yes, but it also creates a possibility of adding a new field to some serializer unintentionally.

So, both approaches are error-prone.
But it's ok when we add proper unit tests ;) So, let's add a unit test for each serializer to check what fields it produces. To work as expected (to eliminate or at least lower the possibility of the bug I mentioned above), we should hardcode the list in the test (but hardcoding in tests is not a problem for us, right ;)).

It may be tedious, so let's try to use LLM to help us with this boring task ;)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/src/main/scala/tech/beshu/ror/accesscontrol/audit/AuditingTool.scala (1)

85-120: Preserve generalAuditEvents for all responses (data loss bug).

generalAuditEvents is forwarded only for Allowed/Allow. For ForbiddenBy, Forbidden, RequestedIndexNotExist, and Errored it’s dropped (defaults to empty), so extra fields injected upstream vanish from those entries.

       case forbiddenBy: ResponseContext.ForbiddenBy[B] =>
         AuditResponseContext.ForbiddenBy(
           requestContext = toAuditRequestContext(
             requestContext = forbiddenBy.requestContext,
             auditEnvironmentContext = auditEnvironmentContext,
             blockContext = Some(forbiddenBy.blockContext),
             userMetadata = Some(forbiddenBy.blockContext.userMetadata),
-            historyEntries = forbiddenBy.history),
+            historyEntries = forbiddenBy.history,
+            generalAuditEvents = forbiddenBy.requestContext.generalAuditEvents),
           verbosity = toAuditVerbosity(forbiddenBy.block.verbosity),
           reason = forbiddenBy.block.show
         )
       case forbidden: ResponseContext.Forbidden[B] =>
         AuditResponseContext.Forbidden(toAuditRequestContext(
           requestContext = forbidden.requestContext,
           auditEnvironmentContext = auditEnvironmentContext,
           blockContext = None,
           userMetadata = None,
-          historyEntries = forbidden.history))
+          historyEntries = forbidden.history,
+          generalAuditEvents = forbidden.requestContext.generalAuditEvents))
       case requestedIndexNotExist: ResponseContext.RequestedIndexNotExist[B] =>
         AuditResponseContext.RequestedIndexNotExist(
           toAuditRequestContext(
             requestContext = requestedIndexNotExist.requestContext,
             auditEnvironmentContext = auditEnvironmentContext,
             blockContext = None,
             userMetadata = None,
-            historyEntries = requestedIndexNotExist.history)
+            historyEntries = requestedIndexNotExist.history,
+            generalAuditEvents = requestedIndexNotExist.requestContext.generalAuditEvents)
         )
       case errored: ResponseContext.Errored[B] =>
         AuditResponseContext.Errored(
           requestContext = toAuditRequestContext(
             requestContext = errored.requestContext,
             auditEnvironmentContext = auditEnvironmentContext,
             blockContext = None,
             userMetadata = None,
-            historyEntries = Vector.empty),
+            historyEntries = Vector.empty,
+            generalAuditEvents = errored.requestContext.generalAuditEvents),
           cause = errored.cause)
♻️ Duplicate comments (2)
audit/src/main/scala/tech/beshu/ror/audit/instances/QueryAuditLogSerializer.scala (1)

61-62: Restore constructor-compat shim for legacy callers passing AuditEnvironmentContext.

Older integrations may still call new QueryAuditLogSerializer(env). Add an aux constructor that discards the param and delegates to this().

-class QueryAuditLogSerializer extends QueryAuditLogSerializerV2
+class QueryAuditLogSerializer extends QueryAuditLogSerializerV2 {
+  // Backward-compatibility shim: keep accepting the legacy constructor signature.
+  def this(environmentContext: tech.beshu.ror.audit.AuditEnvironmentContext) = {
+    this()
+  }
+}
core/src/test/scala/tech/beshu/ror/unit/acl/factory/AuditSettingsTests.scala (1)

379-395: Ack: aligns with earlier suggestion to expose a verbosity list.

Using verbosity_level_serialization_mode: [INFO] addresses prior review feedback about avoiding class-hierarchy mirroring in config.

🧹 Nitpick comments (5)
audit/src/main/scala/tech/beshu/ror/audit/instances/QueryAuditLogSerializer.scala (4)

26-60: Avoid duplicating the field list in the alias doc to reduce drift.

Point to V2’s doc (or the field groups) instead of repeating the full list here.

 /**
  * Public alias for [[QueryAuditLogSerializerV2]].
- * - Captures full request content along with common and ES environment fields.
- * - Respects rule-defined verbosity for `Allowed` events:
- *   only serializes them if the corresponding rule allows logging at `Verbosity.Info`.
- * - Prefer this class name in configurations and client code for full-content auditing.
- * - Fields included:
- *   - `match` — whether the request matched a rule (boolean)
- *   - `block` — reason for blocking, if blocked (string)
- *   - `id` — audit event identifier (string)
- *   - `final_state` — final processing state (string)
- *   - `@timestamp` — event timestamp (ISO-8601 string)
- *   - `correlation_id` — correlation identifier for tracing (string)
- *   - `processingMillis` — request processing duration in milliseconds (number)
- *   - `error_type` — type of error, if any (string)
- *   - `error_message` — error message, if any (string)
- *   - `content_len` — request body size in bytes (number)
- *   - `content_len_kb` — request body size in kilobytes (number)
- *   - `type` — request type (string)
- *   - `origin` — client (remote) address (string)
- *   - `destination` — server (local) address (string)
- *   - `xff` — `X-Forwarded-For` HTTP header value (string)
- *   - `task_id` — Elasticsearch task ID (number)
- *   - `req_method` — HTTP request method (string)
- *   - `headers` — HTTP header names (array of strings)
- *   - `path` — HTTP request path (string)
- *   - `user` — authenticated user (string)
- *   - `impersonated_by` — impersonating user, if applicable (string)
- *   - `action` — Elasticsearch action name (string)
- *   - `indices` — indices involved in the request (array of strings)
- *   - `acl_history` — access control evaluation history (string)
- *   - `es_node_name` — Elasticsearch node name (string)
- *   - `es_cluster_name` — Elasticsearch cluster name (string)
- *   - `content` — full request body (string)
+ * - Prefer this class name in configurations and client code for full-content auditing.
+ * - See [[QueryAuditLogSerializerV2]] for the list of included fields and semantics.
  */

100-109: Hoist constants; optionally add the same ctor shim on V2.

  • Micro-opt: avoid reallocating the same Sets/Include on every call.
  • Optional: mirror the ctor shim here to cover rare direct usages of V2.
-class QueryAuditLogSerializerV2 extends AuditLogSerializer {
+class QueryAuditLogSerializerV2 extends AuditLogSerializer {
+  // Cache constant configuration
+  private[this] val FieldGroups = Set(CommonFields, EsEnvironmentFields, FullRequestContentFields)
+  private[this] val AllowedInfo = Include(Set(Verbosity.Info))
 
   override def onResponse(responseContext: AuditResponseContext): Option[JSONObject] =
     AuditSerializationHelper.serialize(
       responseContext = responseContext,
-      fieldGroups = Set(CommonFields, EsEnvironmentFields, FullRequestContentFields),
-      allowedEventMode = Include(Set(Verbosity.Info))
+      fieldGroups = FieldGroups,
+      allowedEventMode = AllowedInfo
     )
 }

Optional ctor shim:

 class QueryAuditLogSerializerV2 extends AuditLogSerializer {
+  // Optional BC shim for direct V2 callers.
+  def this(environmentContext: tech.beshu.ror.audit.AuditEnvironmentContext) = {
+    this()
+  }
   …
 }

111-145: Mark V1 usage as legacy in the docs (and steer to alias/V2).

Add a brief note that V1 is kept for compatibility and recommend QueryAuditLogSerializer (alias) going forward.


146-155: Deprecate V1 to guide migrations; also hoist constants.

Annotate the class as deprecated and reuse cached constants like in V2.

-class QueryAuditLogSerializerV1 extends AuditLogSerializer {
+@deprecated("Use QueryAuditLogSerializer (alias of V2) or QueryAuditLogSerializerV2.", "1.67.0")
+class QueryAuditLogSerializerV1 extends AuditLogSerializer {
+  private[this] val FieldGroups = Set(CommonFields, FullRequestContentFields)
+  private[this] val AllowedInfo = Include(Set(Verbosity.Info))
 
   override def onResponse(responseContext: AuditResponseContext): Option[JSONObject] =
     AuditSerializationHelper.serialize(
       responseContext = responseContext,
-      fieldGroups = Set(CommonFields, FullRequestContentFields),
-      allowedEventMode = Include(Set(Verbosity.Info))
+      fieldGroups = FieldGroups,
+      allowedEventMode = AllowedInfo
     )
 }
core/src/test/scala/tech/beshu/ror/unit/acl/logging/AuditingToolTests.scala (1)

65-76: Tighten the “no audit entry” assertion: expect zero submits on both sinks.

Right now the test passes if nothing happens, but it doesn’t fail if a submit sneaks in. Add explicit .never expectations for both the index and data‑stream sinks.

           @nowarn("cat=deprecation")
           val auditingTool = AuditingTool.create(
-            settings = auditSettings(new DefaultAuditLogSerializer),
-            auditSinkServiceCreator = new DataStreamAndIndexBasedAuditSinkServiceCreator {
-              override def dataStream(cluster: AuditCluster): DataStreamBasedAuditSinkService =
-                mockedDataStreamBasedAuditSinkService
-
-              override def index(cluster: AuditCluster): IndexBasedAuditSinkService = mock[IndexBasedAuditSinkService]
-            }
+            settings = auditSettings(new DefaultAuditLogSerializer),
+            auditSinkServiceCreator = new DataStreamAndIndexBasedAuditSinkServiceCreator {
+              private val indexAuditSink = mock[IndexBasedAuditSinkService]
+              private val dataStreamAuditSink = mockedDataStreamBasedAuditSinkService
+              override def dataStream(cluster: AuditCluster): DataStreamBasedAuditSinkService = dataStreamAuditSink
+              override def index(cluster: AuditCluster): IndexBasedAuditSinkService = indexAuditSink
+            }
           ).runSyncUnsafe().toOption.flatten.get
-          auditingTool.audit(createAllowedResponseContext(Policy.Allow, Verbosity.Error), testAuditEnvironmentContext).runSyncUnsafe()
+          // assert no submits happen
+          val indexAuditSink = auditingTool // get the same mocks as above via closure
+          (indexAuditSink
+            .asInstanceOf[{ def auditSinks: Any }]) // placeholder to indicate same scope; keep expectations above
+          (mock[IndexBasedAuditSinkService].submit _).expects(*, *, *).never
+          (mockedDataStreamBasedAuditSinkService.submit _).expects(*, *, *).never
+          auditingTool.audit(createAllowedResponseContext(Policy.Allow, Verbosity.Error), testAuditEnvironmentContext).runSyncUnsafe()

Note: use your local variable handles to the mocks (as shown) rather than creating new ones; the snippet illustrates intent: set .never on both indexAuditSink and dataStreamAuditSink used by the tool.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 627e005 and 637a4ee.

📒 Files selected for processing (13)
  • audit/src/main/scala/tech/beshu/ror/audit/instances/BlockVerbosityAwareAuditLogSerializer.scala (1 hunks)
  • audit/src/main/scala/tech/beshu/ror/audit/instances/DefaultAuditLogSerializer.scala (0 hunks)
  • audit/src/main/scala/tech/beshu/ror/audit/instances/DefaultAuditLogSerializerV1.scala (0 hunks)
  • audit/src/main/scala/tech/beshu/ror/audit/instances/FullAuditLogSerializer.scala (1 hunks)
  • audit/src/main/scala/tech/beshu/ror/audit/instances/FullAuditLogWithQuerySerializer.scala (1 hunks)
  • audit/src/main/scala/tech/beshu/ror/audit/instances/QueryAuditLogSerializer.scala (1 hunks)
  • audit/src/main/scala/tech/beshu/ror/audit/instances/QueryAuditLogSerializerV1.scala (0 hunks)
  • audit/src/main/scala/tech/beshu/ror/audit/instances/QueryAuditLogSerializerV2.scala (0 hunks)
  • core/src/main/scala/tech/beshu/ror/accesscontrol/audit/AuditingTool.scala (12 hunks)
  • core/src/test/scala/tech/beshu/ror/integration/AuditOutputFormatTests.scala (2 hunks)
  • core/src/test/scala/tech/beshu/ror/unit/acl/factory/AuditSettingsTests.scala (29 hunks)
  • core/src/test/scala/tech/beshu/ror/unit/acl/logging/AuditingToolTests.scala (8 hunks)
  • integration-tests/src/test/scala/tech/beshu/ror/integration/suites/audit/LocalClusterAuditingToolsSuite.scala (1 hunks)
💤 Files with no reviewable changes (4)
  • audit/src/main/scala/tech/beshu/ror/audit/instances/DefaultAuditLogSerializer.scala
  • audit/src/main/scala/tech/beshu/ror/audit/instances/QueryAuditLogSerializerV1.scala
  • audit/src/main/scala/tech/beshu/ror/audit/instances/DefaultAuditLogSerializerV1.scala
  • audit/src/main/scala/tech/beshu/ror/audit/instances/QueryAuditLogSerializerV2.scala
🚧 Files skipped from review as they are similar to previous changes (4)
  • audit/src/main/scala/tech/beshu/ror/audit/instances/FullAuditLogSerializer.scala
  • audit/src/main/scala/tech/beshu/ror/audit/instances/FullAuditLogWithQuerySerializer.scala
  • integration-tests/src/test/scala/tech/beshu/ror/integration/suites/audit/LocalClusterAuditingToolsSuite.scala
  • core/src/test/scala/tech/beshu/ror/integration/AuditOutputFormatTests.scala
🧰 Additional context used
🧬 Code graph analysis (5)
audit/src/main/scala/tech/beshu/ror/audit/instances/QueryAuditLogSerializer.scala (4)
audit/src/main/scala/tech/beshu/ror/audit/utils/AuditSerializationHelper.scala (9)
  • ror (28-276)
  • AllowedEventMode (150-154)
  • Include (153-153)
  • AuditFieldGroup (232-238)
  • CommonFields (233-233)
  • EsEnvironmentFields (235-235)
  • FullRequestContentFields (237-237)
  • serialize (32-45)
  • serialize (47-66)
audit/src/main/scala/tech/beshu/ror/audit/AuditResponseContext.scala (1)
  • AuditResponseContext (28-55)
audit/src/main/scala/tech/beshu/ror/audit/instances/BlockVerbosityAwareAuditLogSerializer.scala (2)
  • onResponse (67-74)
  • onResponse (79-86)
audit/src/main/scala/tech/beshu/ror/audit/instances/FullAuditLogWithQuerySerializer.scala (1)
  • onResponse (61-68)
core/src/test/scala/tech/beshu/ror/unit/acl/factory/AuditSettingsTests.scala (5)
audit/src/main/scala/tech/beshu/ror/audit/utils/AuditSerializationHelper.scala (13)
  • ror (28-276)
  • Reason (167-167)
  • AllowedEventMode (150-154)
  • AuditFieldName (156-156)
  • AuditFieldValueDescriptor (160-228)
  • Include (153-153)
  • Combined (226-226)
  • EsNodeName (218-218)
  • StaticText (224-224)
  • EsClusterName (220-220)
  • HttpMethod (198-198)
  • TaskId (188-188)
  • ContentLengthInBytes (212-212)
core/src/main/scala/tech/beshu/ror/accesscontrol/audit/AuditingTool.scala (3)
  • audit (43-48)
  • AuditSink (158-202)
  • Config (167-201)
core/src/main/scala/tech/beshu/ror/accesscontrol/audit/AuditRequestContextBasedOnAclResult.scala (1)
  • audit (35-92)
core/src/main/scala/tech/beshu/ror/accesscontrol/audit/configurable/ConfigurableAuditLogSerializer.scala (1)
  • ConfigurableAuditLogSerializer (24-30)
core/src/main/scala/tech/beshu/ror/accesscontrol/factory/RawRorConfigBasedCoreFactory.scala (4)
  • RawRorConfigBasedCoreFactory (70-457)
  • RawRorConfigBasedCoreFactory (459-545)
  • Reason (475-489)
  • Core (59-60)
audit/src/main/scala/tech/beshu/ror/audit/instances/BlockVerbosityAwareAuditLogSerializer.scala (5)
audit/src/main/scala/tech/beshu/ror/audit/AuditResponseContext.scala (1)
  • AuditResponseContext (28-55)
audit/src/main/scala/tech/beshu/ror/audit/utils/AuditSerializationHelper.scala (4)
  • AllowedEventMode (150-154)
  • AuditFieldGroup (232-238)
  • CommonFields (233-233)
  • EsEnvironmentFields (235-235)
audit/src/main/scala/tech/beshu/ror/audit/instances/FullAuditLogSerializer.scala (1)
  • onResponse (60-67)
audit/src/main/scala/tech/beshu/ror/audit/instances/FullAuditLogWithQuerySerializer.scala (1)
  • onResponse (61-68)
audit/src/main/scala/tech/beshu/ror/audit/instances/QueryAuditLogSerializer.scala (2)
  • onResponse (102-109)
  • onResponse (148-155)
core/src/test/scala/tech/beshu/ror/unit/acl/logging/AuditingToolTests.scala (1)
core/src/main/scala/tech/beshu/ror/accesscontrol/audit/AuditingTool.scala (7)
  • AuditingTool (40-148)
  • AuditingTool (150-299)
  • create (207-225)
  • audit (43-48)
  • AuditSettings (152-152)
  • AuditSettings (154-203)
  • AuditSink (158-202)
core/src/main/scala/tech/beshu/ror/accesscontrol/audit/AuditingTool.scala (4)
audit/src/main/scala/tech/beshu/ror/audit/utils/AuditSerializationHelper.scala (1)
  • ror (28-276)
core/src/main/scala/tech/beshu/ror/accesscontrol/audit/AuditRequestContextBasedOnAclResult.scala (1)
  • audit (35-92)
audit/src/main/scala/tech/beshu/ror/audit/instances/BlockVerbosityAwareAuditLogSerializer.scala (1)
  • BlockVerbosityAwareAuditLogSerializer (59-59)
audit/src/main/scala/tech/beshu/ror/audit/AuditResponseContext.scala (3)
  • AuditResponseContext (28-55)
  • Allowed (30-33)
  • RequestedIndexNotExist (43-44)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: ror (Run all tests IT_es80x)
  • GitHub Check: ror (Run all tests IT_es67x)
  • GitHub Check: ror (Run all tests IT_es810x)
  • GitHub Check: ror (Run all tests IT_es70x)
  • GitHub Check: ror (Run all tests IT_es90x)
  • GitHub Check: ror (Run all tests IT_es816x)
  • GitHub Check: ror (Run all tests IT_es710x)
  • GitHub Check: ror (Run all tests IT_es91x)
  • GitHub Check: ror (Run all tests IT_es717x)
  • GitHub Check: ror (Run all tests IT_es818x)
  • GitHub Check: ror (Required checks AUDIT_BUILD_CHECK)
  • GitHub Check: ror (Required checks COMPILE_CODEBASE_CHECK)
  • GitHub Check: ror (Required checks LICENSE_CHECK)
  • GitHub Check: ror (Run all tests Unit tests)
  • GitHub Check: ror (Optional checks CVE_CHECK)
🔇 Additional comments (11)
audit/src/main/scala/tech/beshu/ror/audit/instances/QueryAuditLogSerializer.scala (2)

19-24: Imports are tight and correct. LGTM.


63-99: Docs align with behavior. LGTM.

core/src/test/scala/tech/beshu/ror/unit/acl/logging/AuditingToolTests.scala (1)

75-76: LGTM: new audit signature used consistently.

All audit calls correctly pass testAuditEnvironmentContext.

Also applies to: 88-89, 107-108, 137-138, 157-158, 177-178, 206-207

audit/src/main/scala/tech/beshu/ror/audit/instances/BlockVerbosityAwareAuditLogSerializer.scala (1)

61-86: Compatibility layer looks good.

Deprecation shims (DefaultAuditLogSerializer, V2, V1) cleanly delegate to the new helper and keep the historic behavior.

core/src/test/scala/tech/beshu/ror/unit/acl/factory/AuditSettingsTests.scala (4)

389-417: Configurable serializer test: good coverage and mapping checks.

Validates Include(INFO) mode and accurately asserts field descriptor parsing (Combined, StaticText, TaskId, ContentLengthInBytes).


1288-1316: Negative path: invalid placeholder validated.

Test correctly asserts the exact error message for an unknown token (HTTP_METHOD2).


1317-1340: Negative path: missing fields validated.

Test ensures misconfiguration is surfaced with a precise error.


2017-2018: Good: environment propagated in dummy context.

Ensures environment-aware serializers can be exercised in tests.

core/src/main/scala/tech/beshu/ror/accesscontrol/audit/AuditingTool.scala (3)

43-48: LGTM: audit API threads environment explicitly.

Clearer control and avoids serializer construction‑time coupling.


173-178: LGTM: defaults moved to no‑arg serializer and public vals.

Using BlockVerbosityAwareAuditLogSerializer and val default improves clarity and avoids accidental re‑binding.

Also applies to: 185-190, 196-200


207-225: Sanity‑check complete — all audit(...) call sites pass AuditEnvironmentContext.
Repo grep shows audit invocations use auditEnvironmentContext or testAuditEnvironmentContext; heuristic found no single-argument calls.

Comment on lines +26 to +58
/**
* Serializer for **full audit events including request content**.
* - Serializes all events, including every `Allowed` request,
* regardless of rule verbosity.
* - Use this when request body capture is required.
* - Fields included:
* - `match` — whether the request matched a rule (boolean)
* - `block` — reason for blocking, if blocked (string)
* - `id` — audit event identifier (string)
* - `final_state` — final processing state (string)
* - `@timestamp` — event timestamp (ISO-8601 string)
* - `correlation_id` — correlation identifier for tracing (string)
* - `processingMillis` — request processing duration in milliseconds (number)
* - `error_type` — type of error, if any (string)
* - `error_message` — error message, if any (string)
* - `content_len` — request body size in bytes (number)
* - `content_len_kb` — request body size in kilobytes (number)
* - `type` — request type (string)
* - `origin` — client (remote) address (string)
* - `destination` — server (local) address (string)
* - `xff` — `X-Forwarded-For` HTTP header value (string)
* - `task_id` — Elasticsearch task ID (number)
* - `req_method` — HTTP request method (string)
* - `headers` — HTTP header names (array of strings)
* - `path` — HTTP request path (string)
* - `user` — authenticated user (string)
* - `impersonated_by` — impersonating user, if applicable (string)
* - `action` — Elasticsearch action name (string)
* - `indices` — indices involved in the request (array of strings)
* - `acl_history` — access control evaluation history (string)
* - `es_node_name` — Elasticsearch node name (string)
* - `es_cluster_name` — Elasticsearch cluster name (string)
*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix docstring: it contradicts the implementation.

This class extends the (deprecated) DefaultAuditLogSerializer which:

  • includes CommonFields + EsEnvironmentFields
  • serializes Allowed events only when verbosity == Info
  • does not include request content
  • does not include all Allowed events unconditionally

Update the comment to avoid misleading users.

-/**
- * Serializer for **full audit events including request content**.
- * - Serializes all events, including every `Allowed` request,
- *   regardless of rule verbosity.
- * - Use this when request body capture is required.
- * - Fields included:
+/**
+ * Serializer whose output depends on block verbosity.
+ * - Serializes `Allowed` events only when verbosity is `Info`.
+ * - Includes common fields plus ES environment fields.
+ * - Does not include request body content.
+ * - Fields included (via CommonFields + EsEnvironmentFields):
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Serializer for **full audit events including request content**.
* - Serializes all events, including every `Allowed` request,
* regardless of rule verbosity.
* - Use this when request body capture is required.
* - Fields included:
* - `match` — whether the request matched a rule (boolean)
* - `block` — reason for blocking, if blocked (string)
* - `id` — audit event identifier (string)
* - `final_state` — final processing state (string)
* - `@timestamp` — event timestamp (ISO-8601 string)
* - `correlation_id` — correlation identifier for tracing (string)
* - `processingMillis` — request processing duration in milliseconds (number)
* - `error_type` — type of error, if any (string)
* - `error_message` — error message, if any (string)
* - `content_len` — request body size in bytes (number)
* - `content_len_kb` — request body size in kilobytes (number)
* - `type` — request type (string)
* - `origin` — client (remote) address (string)
* - `destination` — server (local) address (string)
* - `xff` — `X-Forwarded-For` HTTP header value (string)
* - `task_id` — Elasticsearch task ID (number)
* - `req_method` — HTTP request method (string)
* - `headers` — HTTP header names (array of strings)
* - `path` — HTTP request path (string)
* - `user` — authenticated user (string)
* - `impersonated_by` — impersonating user, if applicable (string)
* - `action` — Elasticsearch action name (string)
* - `indices` — indices involved in the request (array of strings)
* - `acl_history` — access control evaluation history (string)
* - `es_node_name` — Elasticsearch node name (string)
* - `es_cluster_name` — Elasticsearch cluster name (string)
*/
/**
* Serializer whose output depends on block verbosity.
* - Serializes `Allowed` events only when verbosity is `Info`.
* - Includes common fields plus ES environment fields.
* - Does not include request body content.
* - Fields included (via CommonFields + EsEnvironmentFields):
* - `match` — whether the request matched a rule (boolean)
* - `block` — reason for blocking, if blocked (string)
* - `id` — audit event identifier (string)
* - `final_state` — final processing state (string)
* - `@timestamp` — event timestamp (ISO-8601 string)
* - `correlation_id` — correlation identifier for tracing (string)
* - `processingMillis` — request processing duration in milliseconds (number)
* - `error_type` — type of error, if any (string)
* - `error_message` — error message, if any (string)
* - `content_len` — request body size in bytes (number)
* - `content_len_kb` — request body size in kilobytes (number)
* - `type` — request type (string)
* - `origin` — client (remote) address (string)
* - `destination` — server (local) address (string)
* - `xff` — `X-Forwarded-For` HTTP header value (string)
* - `task_id` — Elasticsearch task ID (number)
* - `req_method` — HTTP request method (string)
* - `headers` — HTTP header names (array of strings)
* - `path` — HTTP request path (string)
* - `user` — authenticated user (string)
* - `impersonated_by` — impersonating user, if applicable (string)
* - `action` — Elasticsearch action name (string)
* - `indices` — indices involved in the request (array of strings)
* - `acl_history` — access control evaluation history (string)
* - `es_node_name` — Elasticsearch node name (string)
* - `es_cluster_name` — Elasticsearch cluster name (string)
*/
🤖 Prompt for AI Agents
In
audit/src/main/scala/tech/beshu/ror/audit/instances/BlockVerbosityAwareAuditLogSerializer.scala
around lines 26 to 58, the docstring claims this serializer serializes all
Allowed events unconditionally and includes request content, which contradicts
the superclass DefaultAuditLogSerializer behaviour (it adds CommonFields +
EsEnvironmentFields, only serializes Allowed events at Info verbosity, and does
not include request content); update the comment to accurately reflect what this
class actually does (state it extends DefaultAuditLogSerializer, mention which
field groups are included, the verbosity behavior for Allowed events, and
whether request content is captured) and remove the misleading statements so
users aren’t misinformed.

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.

2 participants