Skip to content

Expose crate so that Guard DSL can be used as a library#684

Open
satyakigh wants to merge 2 commits intomainfrom
guard-lib
Open

Expose crate so that Guard DSL can be used as a library#684
satyakigh wants to merge 2 commits intomainfrom
guard-lib

Conversation

@satyakigh
Copy link
Copy Markdown

@satyakigh satyakigh commented Mar 26, 2026

Summary

This PR extracts the core Guard DSL engine (parser, AST, evaluator, path-value system, and built-in functions) from the guard CLI crate into a new standalone guard-lang library crate. This enables third-party Rust projects to embed the Guard policy-as-code evaluation engine without depending on the CLI binary or its command infrastructure.

Motivation

Previously, the Guard DSL internals lived under guard/src/rules/ with pub(crate) visibility, making it impossible for external consumers to programmatically parse rules, evaluate policies, or inspect evaluation results. By extracting these into guard-lang, users can:

  • Parse Guard DSL rules files into an AST (parser::rules_file)
  • Evaluate rules against arbitrary JSON/YAML data (eval::eval_rules_file)
  • Inspect structured evaluation results (eval_context::simplified_json_from_root)
  • Use the path-aware value system for data traversal

What Changed

1. New crate: guard-lang

  • New guard-lang/Cargo.toml (v1.0.0, edition 2018, Apache-2.0) with the same core dependencies as guard (nom, serde, fancy-regex, chrono, etc.)
  • Added to workspace in root Cargo.toml

2. File moves (guard/src/rules/guard-lang/src/)

Module Description
eval.rs, eval_context.rs, evaluate.rs Evaluation engine
parser.rs Guard DSL parser (nom-based)
exprs.rs AST types (rules, clauses, blocks, queries)
path_value.rs + path_value/traversal.rs Path-aware JSON/YAML value system
values.rs Core value types, comparison operators, YAML loader
errors.rs, display.rs Error types and display formatting
functions/ Built-in functions (collections, converters, strings, date_time)
libyaml/ unsafe-libyaml wrapper

3. Visibility changes

All pub(crate) and pub(in crate::rules) changed to pub across all moved files. This includes structs, enums, traits, functions, and struct fields.

4. Import path rewriting

All crate::rules::X paths rewritten to crate::X:

crate::rules::path_value::compare_eq  →  crate::path_value::compare_eq
crate::rules::eval_context::...       →  crate::eval_context::...
crate::rules::Result                  →  crate::Result

5. Re-export bridge

guard/src/rules/mod.rs reduced to:

// Re-export everything from guard-lang
pub use guard_lang::*;

This maintains backward compatibility for all existing code in the guard crate.

6. print_verbose_tree moved

The pretty-print tree function moved from guard/src/commands/validate.rs to guard-lang/src/eval_context.rs, with the signature generalized from &mut Writer to &mut dyn std::io::Write. The validate.rs bridge delegates to it.

7. Disjunction context string fix

eval_conjunction_clauses now uses the short type name (e.g., GuardClause) instead of the full path (cfn_guard::rules::exprs::GuardClause) in disjunction context strings. The same fix applied in evaluate.rs using std::any::type_name comparison. Test output .out files updated accordingly.

Before:

Disjunction(Status = PASS)[Context=cfn_guard::rules::exprs::GuardClause#disjunction]

After:

Disjunction(Status = PASS)[Context=GuardClause#disjunction]

8. read_file_content added

A new read_file_content(File) -> Result<String> utility added to guard-lang/src/lib.rs so tests in evaluate_tests.rs don't depend on guard::commands::files.

9. Test path sanitization

guard/tests/utils.rs updated to also replace CARGO_MANIFEST_DIR in test output sanitization, handling paths outside $HOME.

10. Asset files

cfn-lambda.yaml and cfn-template.json copied to guard-lang/assets/ for tests that reference them.

@satyakigh satyakigh marked this pull request as ready for review April 8, 2026 18:21
@Zee2413 Zee2413 requested a review from joshfried-aws April 10, 2026 15:19
@satyakigh satyakigh changed the title Expose methods for using guard as a library Expose crate so that Guard DSL can be used as a library Apr 10, 2026
@satyakigh satyakigh force-pushed the guard-lib branch 3 times, most recently from 041fa03 to f6444c2 Compare April 10, 2026 22:39
Comment thread guard-lang/src/eval/operators.rs
Comment thread guard-lang/src/eval.rs
Copy link
Copy Markdown

@kddejong kddejong left a comment

Choose a reason for hiding this comment

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

Blanket pub visibility is a blocker

The extraction is mechanically sound — CI is green, backward compat is preserved via the re-export bridge. But every pub(crate) was changed to pub without selectivity, exposing 345 items as public API when the stated use cases only need ~30.

Key concerns

  • libyaml/* is fully exposed, including pub unsafe fn convert_event. None of this is consumer API.
  • parser.rs: 28 of 30 items are internal nom combinators (comment2, white_space, preceded_by, etc.). Only rules_file needs to be public.
  • eval.rs: 10 of 12 items are internal dispatch functions. Only eval_rules_file is an entry point.
  • eval/operators.rs: 21 internal comparison structs/traits (LhsRhsPair, QueryIn, Comparator, etc.) no consumer needs.
  • All struct fields are pub, freezing internal layout as API. Renaming BlockCheck.at_least_one_matches or changing Messages.error_message becomes a breaking change.

At v1.0.0 this is permanent

Every signature, field, and trait is a semver commitment. Shipping 345 pub items at 1.0.0 means any future cleanup is a breaking change.

Suggestion

Keep modules pub(crate) by default and re-export a curated surface from lib.rs:

pub use parser::rules_file;
pub use eval::eval_rules_file;
pub use eval_context::{simplified_json_from_root, FileReport, RuleReport, ClauseReport};
pub use path_value::{PathAwareValue, Path, Location};
pub use values::{read_from, MarkedValue};
// ~30 items total

Or ship at 0.1.0 to signal the API is unstable and iterate toward a curated 1.0.

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.

4 participants