Skip to content

fix(jans-cedarling): add cedarling log to lock log mapping#13554

Open
dagregi wants to merge 4 commits intomainfrom
jans-cedarling-13518
Open

fix(jans-cedarling): add cedarling log to lock log mapping#13554
dagregi wants to merge 4 commits intomainfrom
jans-cedarling-13518

Conversation

@dagregi
Copy link
Contributor

@dagregi dagregi commented Mar 23, 2026

Prepare


Description

Target issue

closes #13518

Implementation Details

New log format mapping - transforms Cedarling logs → Lock Server format

  • New mapping.rs: CedarlingLogEntry (input) + LockServerLogEntry (output) with From conversion
  • gRPC: Replaced JsonLogEntry, added RFC3339 timestamp parsing via parse_timestamp()
  • REST: Same mapping applied
  • Tests: Updated to new Cedarling format with proper field mappings

Test and Document the changes

  • Static code analysis has been run locally and issues have been fixed
  • Relevant unit and integration tests have been added/updated
  • Relevant documentation has been updated if any (i.e. user guides, installation and configuration guides, technical design docs etc)

Please check the below before submitting your PR. The PR will not be merged if there are no commits that start with docs: to indicate documentation changes or if the below checklist is not selected.

  • I confirm that there is no impact on the docs due to the code changes in this PR.

Summary by CodeRabbit

  • Tests

    • Updated log-entry tests and fixtures to use a standardized audit-oriented JSON shape with timestamps, decision/action fields, and higher-precision timestamp expectations.
  • Chores

    • Unified log handling across transports to map incoming audit logs into the server's expected schema.
    • Improved timestamp parsing to RFC3339 with nanosecond precision, adjusted batching/serialization behavior, and preserved malformed-entry skipping semantics.

* update tests to match new log format

Signed-off-by: dagregi <dagmawi.m@proton.me>
@dagregi dagregi self-assigned this Mar 23, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 23, 2026

📝 Walkthrough

Walkthrough

Convert incoming Cedarling decision-log JSON into the Lock Server audit schema by adding a mapping module and updating REST and gRPC transports and tests to deserialize CedarlingLogEntry, map to LockServerLogEntry (including RFC3339 timestamps and flattened context), and send audit-style payloads.

Changes

Cohort / File(s) Summary
Mapping module
jans-cedarling/cedarling/src/lock/transport/mapping.rs, jans-cedarling/cedarling/src/lock/transport/mod.rs
Add CedarlingLogEntry and LockServerLogEntry types, MappingValidationError, and TryFrom<CedarlingLogEntry> for LockServerLogEntry conversion that validates required fields, maps timestamps, derives service/node_name, concatenates principal, extracts client_id, and moves remaining extras into context_information.
gRPC transport
jans-cedarling/cedarling/src/lock/transport/grpc.rs
Replace inline JSON parsing with deserialization into CedarlingLogEntryLockServerLogEntry → protobuf LogEntry; parse RFC3339 timestamps (including nanos) into protobuf Timestamp; stringify non-string context values; compute skipped from conversion failures; update unit tests to new JSON/proto shape.
REST transport
jans-cedarling/cedarling/src/lock/transport/rest.rs
Deserialize each serialized entry as CedarlingLogEntry, convert to LockServerLogEntry, POST Vec<LockServerLogEntry>, compute skipped = entries.len() - logs.len(), preserve malformed-entry skipping and error behavior; update tests and remove two obsolete tests.
Integration tests / mocks
jans-cedarling/cedarling/src/lock/mod.rs
Update test MockLogEntry and Loggable implementation to emit log_kind and decision/audit fields; change mocked /jans-auth/v1/audit/log/bulk expectation to audit-style fields (creation_date, event_time, service, node_name, severity_level, action, decision_result, requested_resource, principal_id).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • olehbozhok
  • haileyesus2433
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately captures the main objective: adding a mapping transformation from Cedarling logs to Lock Server log format.
Description check ✅ Passed The description covers target issue (#13518), implementation details (new mapping.rs, gRPC/REST updates, RFC3339 timestamp parsing), and test updates with all checklist items addressed.
Linked Issues check ✅ Passed All requirements from #13518 are met: mapping transforms Cedarling logs to Lock Server format, includes all required audit-log fields (creation_date, event_time, service, node_name, event_type, severity_level, action, decision_result, requested_resource), and applies consistently across gRPC and REST transports.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the log format mapping specified in #13518: new mapping module, gRPC/REST transport updates, test updates, and timestamp parsing—no extraneous modifications present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jans-cedarling-13518

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 and usage tips.

@mo-auto mo-auto added comp-jans-cedarling Touching folder /jans-cedarling kind-bug Issue or PR is a bug in existing functionality labels Mar 23, 2026
@mo-auto
Copy link
Member

mo-auto commented Mar 23, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@dagregi dagregi marked this pull request as ready for review March 23, 2026 14:07
Copy link
Contributor

@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: 3

Caution

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

⚠️ Outside diff range comments (2)
jans-cedarling/cedarling/src/lock/mod.rs (1)

559-564: 🧹 Nitpick | 🔵 Trivial

Use expect_err instead of assert!(result.is_err()) pattern.

Per coding guidelines, error checking in tests should use result.expect_err("descriptive message") instead of assert!(result.is_err()).

♻️ Proposed fix
-        let result = LockService::new(pdp_id, &config, None).await;
-        assert!(result.is_err());
-        assert!(matches!(
-            result.unwrap_err(),
+        let error = LockService::new(pdp_id, &config, None)
+            .await
+            .expect_err("startup with invalid SSA should fail");
+        assert!(matches!(
+            error,
             InitLockServiceError::InvalidSsaJwt(_)
-        ));
+        ), "expected InvalidSsaJwt error, got {error:?}");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@jans-cedarling/cedarling/src/lock/mod.rs` around lines 559 - 564, Replace the
two-step test that uses assert!(result.is_err()) and then matches on
result.unwrap_err() with a single expect_err call: call LockService::new(pdp_id,
&config, None).await and use result.expect_err("descriptive message about
expecting invalid SSA JWT") to capture the error, then assert that the captured
error matches InitLockServiceError::InvalidSsaJwt(_) (keep the matches check) so
you both provide a descriptive failure message and avoid unwrap_err on an
assertion-only check.
jans-cedarling/cedarling/src/lock/transport/rest.rs (1)

216-221: 🧹 Nitpick | 🔵 Trivial

Add descriptive message to the matches! assertion.

Per coding guidelines, all assertions must include a descriptive message explaining what is being tested.

♻️ Proposed fix
         let result = transport.send_logs(&entries).await;
-        assert!(matches!(
-            result.unwrap_err(),
-            TransportError::Serialization(_)
-        ));
+        let error = result.expect_err("all malformed entries should cause serialization error");
+        assert!(
+            matches!(error, TransportError::Serialization(_)),
+            "expected serialization error, got {error:?}"
+        );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@jans-cedarling/cedarling/src/lock/transport/rest.rs` around lines 216 - 221,
The assertion using assert!(matches!(result.unwrap_err(),
TransportError::Serialization(_))) lacks a descriptive message; update the test
around the transport.send_logs(&entries).await call to include a clear assertion
message explaining that a Serialization error is expected (mention
TransportError::Serialization) and include the actual error (e.g., using "{:?}")
so test failures show the observed error; keep the matches! check but append a
message to the assert! macro referencing result.unwrap_err() for diagnostics.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@jans-cedarling/cedarling/src/lock/transport/grpc.rs`:
- Around line 151-159: The parse_timestamp function uses a non-existent
cast_signed() on dt.timestamp_subsec_nanos(); update the Timestamp nanos
conversion in parse_timestamp to cast the u32 to i32 using a standard Rust cast
(i.e., replace the cast_signed() call on dt.timestamp_subsec_nanos() with an as
i32 cast) so Timestamp { seconds: dt.timestamp(), nanos: ... } compiles
correctly.

In `@jans-cedarling/cedarling/src/lock/transport/mapping.rs`:
- Around line 1-4: Add the standard Apache 2.0 license header (including the
Gluu, Inc. copyright notice) to the top of this Rust source file (mapping.rs in
the lock::transport module) so it precedes any use/import statements; ensure the
header text matches the project's canonical Apache-2.0 block used across other
Rust files in the repo.
- Around line 67-76: The code constructs client_id from
value.extra.get("lock_client_id") but then includes the same key in
context_information; to fix this remove or consume "lock_client_id" from
value.extra before building context_information. Specifically, when mapping into
the struct (referencing client_id and context_information), ensure you either
call value.extra.remove("lock_client_id") (or filter out that key) so
context_information is built from the remaining entries only, and keep client_id
assigned from the extracted value.

---

Outside diff comments:
In `@jans-cedarling/cedarling/src/lock/mod.rs`:
- Around line 559-564: Replace the two-step test that uses
assert!(result.is_err()) and then matches on result.unwrap_err() with a single
expect_err call: call LockService::new(pdp_id, &config, None).await and use
result.expect_err("descriptive message about expecting invalid SSA JWT") to
capture the error, then assert that the captured error matches
InitLockServiceError::InvalidSsaJwt(_) (keep the matches check) so you both
provide a descriptive failure message and avoid unwrap_err on an assertion-only
check.

In `@jans-cedarling/cedarling/src/lock/transport/rest.rs`:
- Around line 216-221: The assertion using assert!(matches!(result.unwrap_err(),
TransportError::Serialization(_))) lacks a descriptive message; update the test
around the transport.send_logs(&entries).await call to include a clear assertion
message explaining that a Serialization error is expected (mention
TransportError::Serialization) and include the actual error (e.g., using "{:?}")
so test failures show the observed error; keep the matches! check but append a
message to the assert! macro referencing result.unwrap_err() for diagnostics.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e22de0ae-5717-4c35-90f0-cd1ffa2e5d9a

📥 Commits

Reviewing files that changed from the base of the PR and between e14944d and 7fa2829.

📒 Files selected for processing (5)
  • jans-cedarling/cedarling/src/lock/mod.rs
  • jans-cedarling/cedarling/src/lock/transport/grpc.rs
  • jans-cedarling/cedarling/src/lock/transport/mapping.rs
  • jans-cedarling/cedarling/src/lock/transport/mod.rs
  • jans-cedarling/cedarling/src/lock/transport/rest.rs

* remove duplicated lock_client_id

Signed-off-by: dagregi <dagmawi.m@proton.me>
Copy link
Contributor

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@jans-cedarling/cedarling/src/lock/transport/mapping.rs`:
- Around line 14-25: The fields log_kind, decision, action, and resource should
not silently default to empty strings; remove the #[serde(default)] from the
struct fields log_kind, decision, action, and resource so deserialization fails
on missing input, and add explicit validation in the conversion routine that
maps these struct fields to the output fields event_type, action,
decision_result, and requested_resource (returning a Result and not panicking).
Implement a small thiserror-backed enum (e.g., MappingValidationError) and in
the conversion function (the TryFrom/into conversion that produces the
audit/event object) check for empty or missing values and return
Err(MappingValidationError::MissingField("log_kind")) etc., so incomplete logs
fail fast with a descriptive error.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6d2b1163-3218-4a18-945d-25b337099c4c

📥 Commits

Reviewing files that changed from the base of the PR and between 7fa2829 and 55b302d.

📒 Files selected for processing (1)
  • jans-cedarling/cedarling/src/lock/transport/mapping.rs

Signed-off-by: dagregi <dagmawi.m@proton.me>
Copy link
Contributor

@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.

♻️ Duplicate comments (1)
jans-cedarling/cedarling/src/lock/transport/mapping.rs (1)

11-15: 🧹 Nitpick | 🔵 Trivial

Consider adding context to MissingField error variant.

The error variant lacks information about which field is missing, making debugging harder. When a log entry fails validation, operators won't know which of the four checked fields (log_kind, decision, action, resource) was empty.

♻️ Proposed enhancement
 #[derive(Debug, thiserror::Error)]
 pub(super) enum MappingValidationError {
-    #[error("missing required field")]
-    MissingField,
+    #[error("missing required field: {0}")]
+    MissingField(&'static str),
 }

Then update the validation:

-        if value.log_kind.is_empty()
-            || value.decision.is_empty()
-            || value.action.is_empty()
-            || value.resource.is_empty()
-        {
-            return Err(MappingValidationError::MissingField);
-        }
+        if value.log_kind.is_empty() {
+            return Err(MappingValidationError::MissingField("log_kind"));
+        }
+        if value.decision.is_empty() {
+            return Err(MappingValidationError::MissingField("decision"));
+        }
+        if value.action.is_empty() {
+            return Err(MappingValidationError::MissingField("action"));
+        }
+        if value.resource.is_empty() {
+            return Err(MappingValidationError::MissingField("resource"));
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@jans-cedarling/cedarling/src/lock/transport/mapping.rs` around lines 11 - 15,
Change MappingValidationError::MissingField to carry the missing field name and
update its error message (e.g., MissingField(String) with a thiserror format
like "missing required field: {0}"), then update the validation logic that
checks log_kind, decision, action, and resource to return
MappingValidationError::MissingField("log_kind".into()) (or the appropriate
field name) instead of the unit variant so logs and errors include which field
was empty.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@jans-cedarling/cedarling/src/lock/transport/mapping.rs`:
- Around line 11-15: Change MappingValidationError::MissingField to carry the
missing field name and update its error message (e.g., MissingField(String) with
a thiserror format like "missing required field: {0}"), then update the
validation logic that checks log_kind, decision, action, and resource to return
MappingValidationError::MissingField("log_kind".into()) (or the appropriate
field name) instead of the unit variant so logs and errors include which field
was empty.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c9853559-2527-4980-96bf-6f7bf01035bd

📥 Commits

Reviewing files that changed from the base of the PR and between 55b302d and ab59258.

📒 Files selected for processing (4)
  • jans-cedarling/cedarling/src/lock/mod.rs
  • jans-cedarling/cedarling/src/lock/transport/grpc.rs
  • jans-cedarling/cedarling/src/lock/transport/mapping.rs
  • jans-cedarling/cedarling/src/lock/transport/rest.rs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp-jans-cedarling Touching folder /jans-cedarling kind-bug Issue or PR is a bug in existing functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(jans-cedarling): lock integration sends logs in wrong format

3 participants