Skip to content

Expose matched rule description after policy evaluation#67

Open
annacai21 wants to merge 14 commits into
mainfrom
anna.cai/match-description-2
Open

Expose matched rule description after policy evaluation#67
annacai21 wants to merge 14 commits into
mainfrom
anna.cai/match-description-2

Conversation

@annacai21

@annacai21 annacai21 commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

After a policy evaluates to TRUE, callers had no way to know which specific rule triggered the match. This PR surfaces that information through plcs_eval_ctx_get_matched_description().

Hardcoded policies (from the injector JSON) carry pre-written descriptions on every leaf node (e.g. "[skip] Apache Cassandra — JVM main class matches '...'""). Remote config policies ship with no descriptions, so the engine synthesizes one from the evaluator's field label, comparator, and value (e.g. "entry point class matches 'org.example.App'"). In both cases evaluate_policy prepends [skip] or [allow] when the description doesn't already start with [.

Changes

eval_ctx.h/c

  • Adds matched_description to plcs_eval_ctx, reset to NULL in plcs_eval_ctx_reset()
  • Exposes plcs_eval_ctx_get_matched_description() for callers (e.g. auto_inject action callbacks)
  • Removes unused action_entry.error field and plcs_eval_ctx_set_action_error()

evaluator.c

  • Adds capture_matched_description(): called at each BOOL_OR short-circuit, recursed through BOOL_NOT nodes to reach their child, and called on the last TRUE child after a BOOL_AND loop completes
  • Falls back to synthesizing a description from the StrEvaluator's field label + comparator + value when no description string is present in the binary
  • evaluate_policy prepends [skip] /[allow] based on the first action's ActionId, unless the description already starts with [

Tests

  • test_matched_description.json: four policies covering nested OR capture, flat OR capture, AND last-true-child capture, and synthesized description (bare-bones node with no description)
  • test_matched_description_policies.h: compiled FlatBuffers binary of the above
  • 7 test cases in test_evaluator.c under evaluator_matched_description

Notes

  • matched_description is reset at the start of each evaluate_policy call — must be read inside an action callback when using plcs_evaluate_buffer across multiple policies
  • Stays NULL if no policy matches

https://datadoghq.atlassian.net/browse/INPLAT-1155

@datadog-official

datadog-official Bot commented Jun 3, 2026

Copy link
Copy Markdown

Pipelines

Fix all issues with BitsAI

⚠️ Warnings

🚦 1 Pipeline job failed

Development | checks   View in Datadog   GitHub Actions

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 602c299 | Docs | Datadog PR Page | Give us feedback!

Comment thread c/src/evaluator.c
if (existing && existing[0] != '\0') {
return;
}
const char *description = NULL;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Have you discussed the possibility of generating the description in the backend instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, the concern was that generating on the backend would make it harder to include runtime context (which arg matched, what value triggered the rule, etc.), since that information is only available at injection time. It would also require the backend to maintain an enum -> description mapping, meaning policy changes would need to be coordinated across repos. I'd lean toward keeping it in dd-policy-engine for those reasons, but if you have other thoughts let me know!

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