Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .kiro/skills/cloudformation-validate-development/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ cargo build # whole workspace (debug)
cargo build -p cfn-validate # CLI -> target/debug/cfn-validate (add --release for optimized)

# Core Rust tests - only when they cover the changed behavior
cargo test -p cel-engine <name> # single crate / filtered test - preferred while iterating
cargo test -p cloudformation-validate-cel-engine <name> # single crate / filtered test - preferred while iterating
cargo test --workspace 2>&1 | tee ../tmp/test-output.txt # broad core changes only; at most once at completion
# CI runs coverage, not plain test: cargo llvm-cov --locked --release --workspace --no-fail-fast

Expand Down Expand Up @@ -74,7 +74,7 @@ Apply these rules when choosing validation:

```bash
# Dump the full SemanticModel - ALWAYS start here. If the model is wrong, fix template-model.
cargo run -p template-model --example inspect -- <template>
cargo run -p cloudformation-validate-template-model --example inspect -- <template>

# Accuracy vs cfn-lint. Requires a local cfn-lint checkout - first check whether cfn-lint is available on the
# machine (`cfn-lint --version`), then ask the user for the checkout path; never assume or hardcode a location.
Expand Down
14 changes: 7 additions & 7 deletions .kiro/steering/structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
src/
├── Cargo.toml # Workspace root
├── rust-toolchain.toml # Pinned toolchain + wasm32 target
├── cfn-validate/ # CLI binary (`cfn-validate`) and library facade
├── bindings-rust/ # Public Rust library facade published as `cloudformation-validate`
├── cfn-validate/ # CLI binary (`cfn-validate`) and CLI-only helpers
├── validation-engine/ # ValidationEngine trait, orchestration pipeline, Step Functions validation
├── template-model/ # LEAF crate — parser (JSON/YAML), SemanticModel, intrinsic resolver,
│ # condition SAT solver, reference graph, SAM transform, nesting, template
Expand All @@ -18,15 +19,14 @@ src/
│ # severity, category, descriptions), filter, category/severity enums
│ # (depends on template-model)
├── schema-validator/ # Compiled JSON Schema validation against provider schemas
├── rego-engine/ # Rego evaluation via Regorus + custom builtins + Guard→Rego translation
│ └── handwritten/rego/ # Hand-written Rego policies (structure, intrinsics, references,
│ # resources, best_practices)
├── rego-engine/ # Rego evaluation via Regorus + custom builtins + Guard→Rego translation;
│ └── handwritten/rego/ # hand-written policies embedded by rego-engine/build.rs
├── cel-engine/ # Native Rust rules + CEL interpreter + Guard→CEL translation
│ └── src/rules/ # Native rules: structure, intrinsics, references, conditions,
│ # resources, resources_extra, best_practices, patterns
├── data-source/ # BUILD-TIME — downloads schemas, syncs cfn-lint data, generates
│ ├── src/ # schema-validator artifacts and CEL rules; build.rs embeds them and
│ │ # the hand-written Rego policies into the binary (zstd)
│ ├── src/ # schema-validator artifacts and CEL rules; build.rs embeds generated
│ │ # and hand-maintained shared data into the binary (zstd)
│ ├── generated/ # Generated artifacts (committed, NEVER edit manually)
│ ├── handwritten/ # Hand-maintained JSON reference tables (deprecated resource types,
│ │ # sensitive ports, GetAtt return-type overrides, schema-dependent
Expand Down Expand Up @@ -102,7 +102,7 @@ src/
go in `rego-engine/handwritten/rego/` or `cel-engine/src/rules/`.
- **Hand-written Rego policies live in `rego-engine/handwritten/rego/`.** These are hand-authored Rego rules organized
by category (structure, intrinsics, references, resources, best_practices). They are embedded into the binary by
`data-source/build.rs`.
`rego-engine/build.rs`.
- **All rules must be registered in the `rules` crate registry (`rules/src/registry.rs`).** A rule that evaluates but
is not registered is a bug — the registry is the single source of truth for IDs, severity, category, and description.
- **Native Rust rules live under `cel-engine/src/rules/`.** Choose the appropriate module (structure, intrinsics,
Expand Down
13 changes: 6 additions & 7 deletions .kiro/steering/tech.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@
## Build-time code generation

The `data-source` crate downloads CloudFormation provider schemas, syncs cfn-lint data, applies patches/extensions, and
generates schema-validator artifacts and (data-driven) CEL rules. Rego policies are hand-written in
`rego-engine/handwritten/rego/`. `data-source/build.rs` compresses every generated and hand-written artifact (zstd) and
exposes them as lazy byte constants via the `data-source::embedded` API. `rego-engine`, `cel-engine`, `schema-validator`,
and `guard-translator` consume those constants at runtime — none of them have their own `build.rs`. Everything compiles
into the binary — no runtime fetching.
generates schema-validator artifacts and (data-driven) CEL rules. `data-source/build.rs` compresses generated and
hand-maintained JSON artifacts (zstd) and exposes them as lazy byte constants via the `data-source::embedded` API.
Rego policies remain hand-written in `rego-engine/handwritten/rego/`; `rego-engine/build.rs` discovers and embeds those
package-local policies. Everything compiles into the binary — no runtime fetching.

`data-source/generated/` is committed generated code — **never hand-edit it, and never run the regeneration
pipeline yourself**. Regeneration is a maintainer-run operation; if a change requires regenerating these artifacts,
Expand All @@ -41,7 +40,7 @@ cargo build # whole workspace (debug)
cargo build -p cfn-validate # CLI -> target/debug/cfn-validate (add --release for optimized)

# Core Rust tests — only when these tests exercise the changed behavior
cargo test -p cel-engine <name> # single crate / filtered test — preferred while iterating
cargo test -p cloudformation-validate-cel-engine <name> # single crate / filtered test — preferred while iterating
cargo test --workspace 2>&1 | tee ../tmp/test-output.txt # broad core changes only; at most once at completion
# CI runs coverage, not plain test: cargo llvm-cov --locked --release --workspace --no-fail-fast

Expand Down Expand Up @@ -98,7 +97,7 @@ Use these, not `println!` or ad-hoc logging.

### inspect — use this first

`cargo run -p template-model --example inspect -- <template>` — dumps the full SemanticModel. Always start here when
`cargo run -p cloudformation-validate-template-model --example inspect -- <template>` — dumps the full SemanticModel. Always start here when
debugging. If the model is wrong, fix `template-model`.

### cfn-validate
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ cargo build # whole workspace (debug)
cargo build -p cfn-validate # CLI -> target/debug/cfn-validate (add --release for optimized)

# Core Rust tests - only when they cover the changed behavior
cargo test -p cel-engine <name> # single crate / filtered test - preferred while iterating
cargo test -p cloudformation-validate-cel-engine <name> # single crate / filtered test - preferred while iterating
cargo test --workspace 2>&1 | tee ../tmp/test-output.txt # broad core changes only; at most once at completion
# CI runs coverage, not plain test: cargo llvm-cov --locked --release --workspace --no-fail-fast

Expand Down Expand Up @@ -68,7 +68,7 @@ Validation depends on the changed surface:

```bash
# Dump the full SemanticModel - ALWAYS start here. If the model is wrong, fix template-model.
cargo run -p template-model --example inspect -- <template>
cargo run -p cloudformation-validate-template-model --example inspect -- <template>

# Accuracy vs cfn-lint. Requires a local cfn-lint checkout - first check whether cfn-lint is available on the
# machine (`cfn-lint --version`), then ask the user for the checkout path; never assume or hardcode a location.
Expand Down
21 changes: 18 additions & 3 deletions INSTALLATION.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Installation

`cloudformation-validate` is distributed as a prebuilt command-line tool and as packages for Node.js, Python, Go, and
the JVM. All distributions contain the validation rules and CloudFormation resource schemas they need, so validation
runs offline after installation without AWS credentials or runtime downloads.
`cloudformation-validate` is distributed as a prebuilt command-line tool and as packages for Rust, Node.js, Python,
Go, and the JVM. All distributions contain the validation rules and CloudFormation resource schemas they need, so
validation runs offline after installation without AWS credentials or runtime downloads.

## Command-line interface

Expand Down Expand Up @@ -34,6 +34,21 @@ codes.
Package-manager installation is recommended: it selects the compatible native artifact and resolves any runtime
dependencies. Use an explicit version in applications that require reproducible builds.

### Rust

The Rust library is published to [crates.io as `cloudformation-validate`](https://crates.io/crates/cloudformation-validate)
and requires Rust 1.96 or later.

```bash
# Latest release
cargo add cloudformation-validate

# Specific release (replace <version>)
cargo add 'cloudformation-validate@=<version>'
```

See the [Rust API and examples](src/bindings-rust/README.md).

### Node.js

The Node.js/WASM package is published to
Expand Down
35 changes: 22 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,13 @@ When a template is submitted, `cloudformation-validate` runs a fixed pipeline:

## Installation

Use a prebuilt CLI or install a published language binding; Rust and this source repository are not required.
Use the prebuilt CLI, embed the Rust library, or install a published language binding; this source repository is not
required.

| Interface | Published artifact | Install |
|-----------|--------------------|---------|
| CLI | [GitHub Releases](https://github.com/aws-cloudformation/cloudformation-validate/releases) | [Download the newest binary for Linux, macOS, or Windows](INSTALLATION.md#command-line-interface) |
| CLI binary | [GitHub Releases](https://github.com/aws-cloudformation/cloudformation-validate/releases) | [Download the newest binary for Linux, macOS, or Windows](INSTALLATION.md#command-line-interface) |
| Rust library | [crates.io: `cloudformation-validate`](https://crates.io/crates/cloudformation-validate) | `cargo add cloudformation-validate` |
| Node.js | [npm: `@aws/cloudformation-validate`](https://www.npmjs.com/package/@aws/cloudformation-validate) | `npm install @aws/cloudformation-validate` |
| Python | [PyPI](https://pypi.org/project/cloudformation-validate/) / [TestPyPI beta](https://test.pypi.org/project/cloudformation-validate/) | `python3 -m pip install cloudformation-validate` |
| Go | [Go module](https://pkg.go.dev/github.com/aws-cloudformation/cloudformation-validate/src/bindings-go/go) | `go get github.com/aws-cloudformation/cloudformation-validate/src/bindings-go/go@latest` |
Expand Down Expand Up @@ -101,28 +103,35 @@ cargo run -p cfn-validate -- template.yaml --guard-rule-source ./my-rules/

## Embedding as a library

### Rust
### Rust [(bindings-rust)](src/bindings-rust/README.md)

Add the library facade:

```toml
[dependencies]
cloudformation-validate = "1.10.0"
```

Construct an engine and a schema validator once, then validate many templates:

```rust
use rego_engine::RegoEngine;
use schema_validator::SchemaValidator;
use validation_engine::{validate_bytes_with_path, EngineConfig, ValidateConfig};
use cloudformation_validate::{
EngineConfig, RegoEngine, SchemaValidator, ValidateConfig, validate_bytes_with_path,
};

let schema_validator = SchemaValidator::default();
let engine = RegoEngine::new(EngineConfig::default())?;

let bytes = std::fs::read("template.yaml") ?;
let bytes = std::fs::read("template.yaml")?;
let report = validate_bytes_with_path(
& engine,
& schema_validator,
& bytes,
ValidateConfig::default (),
&engine,
&schema_validator,
&bytes,
ValidateConfig::default(),
"template.yaml".to_string(),
) ?;
)?;

for d in & report.diagnostics {
for d in &report.diagnostics {
println!("[{}] {} - {}", d.severity, d.rule_id, d.message);
}
```
Expand Down
19 changes: 10 additions & 9 deletions scripts/generate_licenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,18 @@
"bindings-jvm",
"bindings-python",
"bindings-wasm",
"cel-engine",
"cfn-validate",
"data-source",
"diagnostics",
"guard-translator",
"rego-engine",
"cloudformation-validate",
"cloudformation-validate-cel-engine",
"cloudformation-validate-data-source",
"cloudformation-validate-diagnostics",
"cloudformation-validate-guard-translator",
"cloudformation-validate-rego-engine",
"cloudformation-validate-rules",
"cloudformation-validate-schema-validator",
"cloudformation-validate-template-model",
"cloudformation-validate-validation-engine",
"resources",
"rules",
"schema-validator",
"template-model",
"validation-engine",
}

APACHE_LICENSE_REFERENCE = (
Expand Down
Loading
Loading