Skip to content

[K9CODESEC-2398] Add RunCustomRegoQuery and ValidateCustomRegoQuery#202

Merged
whitemerch merged 2 commits into
mainfrom
chakib.hamie/verify_and_validate_rego_endpoints
Jun 24, 2026
Merged

[K9CODESEC-2398] Add RunCustomRegoQuery and ValidateCustomRegoQuery#202
whitemerch merged 2 commits into
mainfrom
chakib.hamie/verify_and_validate_rego_endpoints

Conversation

@whitemerch

@whitemerch whitemerch commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Motivation

Custom rule authors writing Rego policies need to know immediately whether their code is valid, not after a failed deployment. This PR adds two new exported functions, ValidateCustomRegoQuery and RunCustomRegoQuery, that give callers IDE-quality diagnostics and evaluation results for custom Rego rules without running a full scan.

Related Ticket: K9CODESEC-2398

Changes

Validation pipeline

ValidateCustomRegoQuery runs three phases in a single call and returns all errors simultaneously, so authors see the full picture at once rather than fixing one error at a time:

  1. Parse: OPA parse errors are rewritten into actionable messages. Bare .document references (missing input prefix), missing package declarations, missing commas inside objects, and unbalanced parentheses each get a precise line/column location and a human-readable explanation instead of OPA's internal error text.
  2. Static AST checks: verifies that the package is datadog, that a DatadogPolicy rule is present, that all required result fields (documentId, resourceType, resourceName, searchKey) are assigned, that sprintf call matches its format string, and that any aliased library has a corresponding import statement.
  3. OPA compilation: compiles the rule against the platform libraries and surfaces type errors and unresolved references. Errors that are purely a consequence of an earlier structural problem (wrong package, missing rule, missing import) are filtered out so they do not drown out the root cause.

If the module is missing its package declaration, validation recovers by temporarily prepending package datadog, runs the static checks on the recovered AST, and shifts error line numbers back so locations still point at the user's original code.

Evaluation

RunCustomRegoQuery writes the Rego content and the IaC file to temporary files with the correct platform-specific extension (.tf, .yaml, .json, …), runs the scan engine in-memory, and returns findings with precise resource locations alongside any runtime errors.

CLI

Two new subcommands are registered under custom:

datadog-iac-scanner custom validate --platform <platform> --rego <base64> — outputs JSON {"errors": [...]}.

datadog-iac-scanner custom evaluate --platform <platform> --rego <base64> --file <base64> — runs validation first; if errors are found they are returned without scanning. Otherwise outputs JSON {"findings": [...], "errors": [...]}.

Both commands accept base64-encoded inputs so binary-safe content can be passed from any calling process without shell escaping concerns.

Note

I have a branch with an UI and a server, let me know if you need it to better test.

Author Checklist

  • I have reviewed my own PR.
  • I have added or updated relevant unit tests where necessary. If no tests are added, I've explained why.
  • All new and existing tests pass.
  • I have tested my changes on staging (if applicable).
  • I have updated any relevant documentation (if applicable).

QA Instruction

  1. go test ./pkg/scan/ -run TestValidateCustomRegoQuery -v — all scenarios (missing package, wrong package, missing rule, missing result fields, missing imports, missing commas, unbalanced parens, missing input, undefined variables) should pass.
  2. Build: go build ./cmd/scanner/...
  3. Validate a known-good rule end-to-end:
REGO=$(base64 -i <path-to-valid-rule.rego>)
./bin/datadog-iac-scanner custom validate --platform terraform --rego "$REGO"
# expect: {"errors": []}
  1. Introduce a deliberate error (remove resourceType from the result object) and re-run validate — expect a missing_result_field error with the correct line number.
  2. Evaluate against a sample Terraform file:
FILE=$(base64 -i <path-to-sample.tf>)
./bin/datadog-iac-scanner custom evaluate --platform terraform --rego "$REGO" --file "$FILE"
# expect: {"findings": [...], "errors": []}

Blast Radius

This PR only adds new exported functions and CLI subcommands. No existing scan logic, query loading, or result reporting paths are modified. The only change to existing files is wiring the new custom command into the CLI entry point and a minor fix to pass the IaC file path through the scan client.

Additional Notes

I submit this contribution under the Apache-2.0 license.

@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Jun 19, 2026

Copy link
Copy Markdown

🎯 Code Coverage (details)
Patch Coverage: 0.00%
Overall Coverage: 49.12% (-0.02%)

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

@whitemerch
whitemerch force-pushed the chakib.hamie/verify_and_validate_rego_endpoints branch 8 times, most recently from 1f4c142 to 4f6c863 Compare June 23, 2026 17:03
@whitemerch whitemerch changed the title Add RunCustomRegoQuery and ValidateCustomRegoQuery to pkg/scan [K9CODESEC-2398] Add RunCustomRegoQuery and ValidateCustomRegoQuery Jun 23, 2026
@whitemerch
whitemerch force-pushed the chakib.hamie/verify_and_validate_rego_endpoints branch from 4f6c863 to 879905c Compare June 23, 2026 17:09
@whitemerch
whitemerch marked this pull request as ready for review June 23, 2026 17:10
@whitemerch
whitemerch requested a review from a team as a code owner June 23, 2026 17:10
chatgpt-codex-connector[bot]

This comment was marked as resolved.

@ChouraquiBen ChouraquiBen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A few comments 🙏

Comment thread pkg/scan/custom_scan.go Outdated
Comment thread pkg/scan/custom_scan.go Outdated
Platform: []string{platform},
ChangedDefaultQueryPath: true,
MaxFileSizeFlag: 5,
QueryExecTimeout: 10, // shorter than the CLI default; custom rules should be fast

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Question: Is it like the timeout discussed yesterday? The one that made the scanner non-deterministic?

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.

indeed hahaha, i did this PR a few days ago but took time to test it with the UI (new release => binary => dd-source => deploy), which obviously I forgot about it since the discussion around the timeout happened yesterday afternoon. That's a good comment, thank you Jeff

Comment thread pkg/scan/custom_scan.go Outdated
Comment thread pkg/scan/custom_scan.go
Comment thread pkg/scan/custom_scan.go
return "scan-target.tf"
case "cloudformation", platformARM:
return scanTargetJSON
case "kubernetes", "ansible":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

must-fix: using 'kubernetes"as platform, the k8s.rego library won't be loaded as it won't be found. Using the k8s platform, the target becomes JSON as described below. More on this line 840.

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 i noticed this before you added comments, that's part of why I force-pushed ahha. Sorry for that, now I am deriving it from libraryPlatform

Comment thread pkg/scan/custom_scan.go
}

func libraryFilesystemSource(ctx context.Context, platform string) *source.FilesystemSource {
return source.NewFilesystemSource(ctx, []string{"."}, []string{platform}, []string{""}, source.LibrariesDefaultBasePath, false)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The platform could be normalized here using a map or something so that platform can be kubernetes and links to k8s

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 using libraryPlatform now

Comment thread pkg/scan/custom_scan.go Outdated
Comment on lines +249 to +251
if !ok || varName == resultVar {
// "result is unsafe" is always a cascade of other unsafe vars; skip it.
continue

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it not still skipping? It is expected behaviour?

@whitemerch
whitemerch force-pushed the chakib.hamie/verify_and_validate_rego_endpoints branch from 879905c to 4dd260f Compare June 24, 2026 08:46
@whitemerch
whitemerch force-pushed the chakib.hamie/verify_and_validate_rego_endpoints branch from 00139b9 to 3895b1a Compare June 24, 2026 09:00

@ChouraquiBen ChouraquiBen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM 🙏

@whitemerch
whitemerch merged commit d374ab2 into main Jun 24, 2026
19 checks passed
@whitemerch
whitemerch deleted the chakib.hamie/verify_and_validate_rego_endpoints branch June 24, 2026 12:45
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