Rustmaninoff
Attribute scanner for Terraform, CloudFormation, and Kubernetes. Policies are Checkov-compatible YAML and reuse published CKV ids. The engine is not a port of the Checkov Python runtime.
Built-in policies are rewritten YAML, attributed to Checkov (Bridgecrew / Palo Alto Networks, Apache-2.0).
Build
Requires Rust 1.95 or newer.
Scan
Exit codes: 0 when nothing fails the threshold, 1 when a finding is at or above --fail-on (default HIGH) or a file fails to parse, 2 on usage errors. --soft-fail always exits 0.
Interpolations (${...}, Fn::*, !Ref, !GetAtt) are unknown. Unknown results do not fail the process. Pass --show-unknown to print them.
Inline skip: # checkov:skip=CKV_AWS_3:reason. Kubernetes annotation value: checkov.io/skip: CKV_K8S_16=reason.
Optional .rustmaninoff.yaml:
frameworks:
skip_checks:
fail_on: HIGH
excluded_paths:
external_checks_dirs:
show_unknown: false
compact: false
Directories named .git, .terraform, .terragrunt-cache, node_modules, vendor, and target are skipped. Symbolic links are not followed. Files larger than 10 MB, and files past the nesting or YAML-alias limits, are reported as diagnostics and are not parsed.
v0.1 scope
- Terraform
.tfand.tf.jsonresource blocks. No module download and no full HCL evaluation. Data sources are not scanned. - CloudFormation YAML and JSON
Resources. Attribute paths are relative toProperties. - Kubernetes multi-document YAML, including
List. - 162 built-in checks (86 Terraform, 46 CloudFormation, 30 Kubernetes). Each check has a pass fixture and a fail fixture.
- Text, JSON, SARIF 2.1.0, and JUnit reports.
S3 encryption, versioning, and logging on current Terraform target aws_s3_bucket_server_side_encryption_configuration, aws_s3_bucket_versioning, and aws_s3_bucket_logging. CKV_AWS_286 matches a static action subset, including * and *:*. CKV_K8S_14 accepts a digest or a tag other than latest; an image whose last colon is a registry port and which has no tag is treated as pinned.
Not in v0.1: graph checks (CKV2_*), Terraform plan JSON, remote modules, Helm, Kustomize, Dockerfiles, secrets, full variable evaluation, and cfn-lint resource-spec validation.
Policy dialect
A check definition is the pass condition. Operators: equals, not_equals, exists, not_exists, contains, not_contains, within, regex_match, starting_with, ending_with, numeric comparisons, is_true, is_false, is_empty, length_greater_than, length_less_than, and their negated forms. Combinators: and, or, not.
Extensions: no_element, forbid_resource, equals_any, intersects, image_tag_pinned, and missing: pass|fail|unknown. scope is ignored. Severity defaults to MEDIUM when omitted.
Benchmark
Against Checkov and Trivy
Wall-clock time of each CLI on one synthetic corpus, Apple M2, macOS 14.8. Median of three runs after a warmup. Stdout was discarded. The corpus is 40 Terraform files (1,080 resources), 20 CloudFormation files (300 resources), and 20 Kubernetes files (160 resources).
| Scanner | Full corpus | Terraform | CloudFormation | Kubernetes |
|---|---|---|---|---|
| Rustmaninoff 0.1.0 | 20 ms | 11 ms | 9 ms | 11 ms |
| Checkov 3.3.21 | 4.51 s | 3.72 s | 2.71 s | 2.92 s |
| Trivy 0.74.0 | 5.71 s | 2.67 s | 1.29 s | 2.59 s |
On the full corpus that is about 225 times the Rustmaninoff time for Checkov, and about 285 times for Trivy. The catalogs are not the same: Rustmaninoff runs 162 attribute checks, Checkov runs its built-in checks for the selected frameworks, and Trivy runs its misconfiguration policies.
xychart-beta
title "CLI wall time on the full corpus"
x-axis [Rustmaninoff, Checkov, Trivy]
y-axis "seconds" 0 --> 6
bar [0.02, 4.51, 5.71]
xychart-beta
title "Times slower than Rustmaninoff"
x-axis ["TF Checkov", "TF Trivy", "CFN Checkov", "CFN Trivy", "K8s Checkov", "K8s Trivy"]
y-axis "times slower" 0 --> 360
bar [345, 247, 288, 137, 263, 234]
Commands, release binary versus the other CLIs:
Engine stages
Release build, same synthetic corpus, measured twice on this machine. Findings stayed at 9,476. These times are in-process. They do not include CLI startup or report formatting, which is why they are lower than the CLI rows above.
| Stage | Before | After |
|---|---|---|
| Terraform, 40 files, 1,080 resources | 222 ms | 13.3 ms |
| Terraform, those files in parallel | 44.2 ms | 2.7 ms |
| One Terraform file, 400 resources | 77.9 ms | 3.2 ms |
| CloudFormation, 20 files, 300 resources | 31.3 ms | 2.8 ms |
| Kubernetes, 20 files, 160 resources | 18.4 ms | 4.3 ms |
| Full builtin pack on 1,540 resources | 17.4 ms | 7.9 ms |
CKV_AWS_3 on 2,000 volumes |
2.64 ms | 2.06 ms |
| Attribute lookup, 200,000 single keys | 29.7 ms | 5.9 ms |
xychart-beta
title "Parse time, before and after"
x-axis ["TF", "TF parallel", "TF 400", "CFN", "K8s"]
y-axis "milliseconds" 0 --> 230
bar [222, 44, 78, 31, 18]
bar [13, 3, 3, 3, 4]
The taller series is the earlier build. The shorter series is the current parser. Builtin YAML is parsed once per process (about 6 ms) and reused. Repeat the stage measurement with cargo run --release -p rustmaninoff --example stages.
Release
Pushing the tag v0.1.0 runs .github/workflows/release.yml. It publishes Linux and macOS binaries for amd64 and arm64, each with a SHA-256 checksum.
- uses: actions/checkout@v4
- run: cargo install --path crates/cli --locked
- run: rustmaninoff scan . --fail-on HIGH --output sarif --sarif-file rustmaninoff.sarif
License
Apache-2.0. See LICENSE.