This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
cnspec is an open-source, cloud-native security and policy project that assesses infrastructure security and compliance. It finds vulnerabilities and misconfigurations across cloud environments, Kubernetes, containers, servers, SaaS products, and more.
# Build cnspec binary
make cnspec/build
# Install to $GOBIN
make cnspec/install
# Build for specific platforms
make cnspec/build/linux
make cnspec/build/linux/arm
make cnspec/build/windowsWhen modifying protobuf files, auto-generated files, or policy structures:
# Install required tools (first time only)
make prep
# Clone/verify cnquery dependency (required for proto compilation)
make prep/repos
# Update cnquery dependency when needed
make prep/repos/update
# Regenerate all generated code (proto, policy, reporter)
make cnspec/generateImportant: Always run make cnspec/generate after modifying:
.protofiles- Policy bundle structures
- Reporter configurations
# Run all tests
make test
# Run Go tests only
make test/go
# Run tests with coverage
make test/go/plain
# Run CI-friendly tests with JUnit output
make test/go/plain-ci
# Run linter
make test/lint
# Lint policy and querypack files
make test/lint/content
# Run benchmarks
make benchmark/go# Run a specific test
go test -v ./policy -run TestSpecificTest
# Run tests in a package
go test -v ./policy/...
# Run with race detection
go test -race ./...# Lint all policies in content directory
cnspec policy lint ./content
# Lint a specific policy file
cnspec policy lint ./content/mondoo-linux-security.mql.yamlcnspec is built on top of cnquery - it's not just a dependency relationship:
- cnquery provides: MQL query engine, provider system, resource framework, data gathering
- cnspec adds: Policy evaluation, scoring, compliance frameworks, security assessments, risk factors
- Shared runtime: Both use the same provider system (
providers.Runtime) for connecting to target systems - Import path: cnspec imports
go.mondoo.com/cnquery/v12extensively
When working on cnspec, you may need to understand or modify cnquery components.
The policy execution pipeline has four main stages:
- Policy files (
.mql.yaml) loaded viaBundleLoaderin policy/bundle.go - Bundles contain: Policies, QueryPacks, Frameworks, Queries, Properties, Migrations
- MQL code compiled to executable
llx.CodeBundle(protobuf format) viamqlc.CompilerConfig - Code bundles are cached and reusable across multiple asset scans
- Core logic in policy/resolver.go and policy/resolved_policy_builder.go
- Asset filters evaluated to determine which policies apply to each asset
- Builds dependency graph of: Policies → Frameworks → Controls → Checks/Queries
- Graph walking from non-prunable leaf nodes ensures only applicable checks run
- Generates two critical structures:
- ExecutionJob: All queries to execute with checksums and code bundles
- CollectorJob: Score aggregation rules with scoring systems and hierarchy
- Orchestrated by
GraphExecutorin policy/executor/graph.go - Queries executed via cnquery's
llx.MQLExecutorV2 - Results collected through
BufferedCollectorpattern - Handles: data points, scores, risk factors, upstream transmission
- Scores calculated via
ScoreCalculatorin policy/score_calculator.go - Reporting jobs aggregate child scores based on impact ratings
- Final
Reportstructures contain scores, statistics, CVSS data
Main orchestrator: LocalScanner in policy/scan/local_scanner.go
Scan Flow:
Job (Inventory + Bundle + Options)
↓
distributeJob() - Batches assets, connects providers
↓
Multiple provider.Runtime instances (one per asset)
↓
RunAssetJob() - Per-asset execution
↓
localAssetScanner.run() - Policy execution for single asset
↓
Results → Reporters (console, SARIF, JUnit, etc.)
Key Components:
- Inventory: List of assets to scan (from CLI flags or inventory files)
- Asset: Describes target system (platform, connections, credentials)
- Provider Runtime: Manages provider plugins via gRPC, handles connections
- DataLake: Storage layer with two implementations:
- InMemory (default): Fast, ephemeral
- SQLite (feature flag): Persistent storage
- Reporters: Various output formats (human-readable, JSON, SARIF, etc.)
The provider system (inherited from cnquery) enables scanning diverse targets:
Connection Flow:
Inventory Asset → Runtime.Connect() → Provider Plugin (gRPC) → Target System
Providers are separate processes:
- Communicate via gRPC using
providers-sdk - Can be written in any language
- Support auto-update with versioned protocols
- Examples: os, aws, k8s, azure, gcp, github, etc.
Provider Discovery:
- Can delay discovery (
DelayDiscoveryflag) - Detect platform details and update asset info on connect
- Platform IDs synchronized with Mondoo Platform for asset tracking
Protobuf is central to cnspec's architecture:
Data Structures (policy/cnspec_policy.proto):
- All major types defined in proto:
Policy,Bundle,Framework,ResolvedPolicy,ExecutionJob,Report,Score - Enables versioning, backwards compatibility, fast serialization
- vtproto used for optimized marshaling (
cnspec_policy_vtproto.pb.go)
RPC Services:
PolicyHub: CRUD operations for policies and frameworksPolicyResolver: Policy resolution, job updates, result storage- ranger-rpc (Mondoo's gRPC wrapper) for communication
Provider Plugins:
- Each provider implements gRPC service defined in
providers-sdk - Allows distributed provider ecosystem
- Versioned protocol ensures compatibility
-
Graph-Based Policy Resolution: Dependencies form a directed graph, traversed from leaves (checks) to roots (policies), with pruning for efficiency
-
Two-Phase Execution: Compilation (MQL → Code Bundles, cached) + Execution (Code Bundles → Results, per asset)
-
Upstream/Local Hybrid: Works standalone (incognito mode) or delegates to Mondoo Platform for policy storage, asset tracking, vulnerability data
-
Service Locator:
LocalServicesbundles PolicyHub and PolicyResolver, can wrap upstream services for seamless online/offline operation -
Collector Pattern: Multiple observers can attach to execution; examples: BufferedCollector, FuncCollector, PolicyServiceCollector
-
Migration System: Bundles include versioned migrations (CREATE/MODIFY/DELETE) for policy evolution
- Forbidden packages: Do not use
github.com/pkg/errors(usegithub.com/cockroachdb/errors) orgithub.com/mitchellh/mapstructure(usegithub.com/go-viper/mapstructure/v2) - cnquery dependency: When proto files reference cnquery types, ensure cnquery repo is present via
make prep/repos
Use github.com/cockroachdb/errors for error handling:
import "github.com/cockroachdb/errors"
// Wrap errors with context
return errors.Wrap(err, "failed to load policy")
// Create new errors
return errors.New("invalid policy structure")Never edit these files manually:
*.pb.go- Generated from proto files*.ranger.go- Generated ranger-rpc code*.vtproto.pb.go- Optimized vtproto marshaling*_gen.go- Generated viago generate
Regenerate with make cnspec/generate after source changes.
Policy files (.mql.yaml) structure:
policies:
- uid: example-policy
name: Example Policy
version: 1.0.0
groups:
- title: Security Checks
filters: asset.platform == "linux"
checks:
- uid: example-check
title: Example Check
impact: 80
mql: |
users.where(name == "root").list {
shell != "/bin/bash"
}Key concepts:
- uid: Unique identifier for policies, checks, queries
- filters: MQL expressions that determine applicability
- impact: Risk score 0-100 for prioritization
- checks: Scoring queries (pass/fail)
- queries: Data collection queries (no scoring)
Formatting requirement: All desc (description) and remediation fields in policy files must be valid Markdown. These fields are rendered as Markdown in the UI, so use proper Markdown syntax for headings, lists, code blocks, links, etc.
Test policy files:
# Lint before committing
cnspec policy lint ./content/your-policy.mql.yaml
# Test locally
cnspec scan local -f ./content/your-policy.mql.yamlMQL (Mondoo Query Language) syntax examples:
# Resource access
users.where(name == "root")
# Filtering and assertions
sshd.config.params["PermitRootLogin"] == "no"
# List operations
processes.list { name pid }
# Relationships
files("/etc").where(name == /\.conf$/)For MQL resources available per provider, see MQL resources documentation.
When adding/modifying policies:
- Lint the policy:
cnspec policy lint <file> - Test against target:
cnspec scan <target> -f <policy-file> - Check for regressions: Run existing policy tests in
content/directory - Verify scoring: Ensure impact ratings and scoring systems work correctly
To test against specific providers:
# Local system
cnspec scan local
# Docker
cnspec scan docker image ubuntu:22.04
# AWS (uses local AWS CLI config)
cnspec scan aws
# Kubernetes
cnspec scan k8s
# SSH
cnspec scan ssh user@hostProvider development happens in separate repos but can be tested with cnspec.
apps/cnspec/: Main CLI application entry pointcmd/: All CLI commands (scan, shell, bundle, etc.)
policy/: Policy engine corescan/: Scanning orchestrationexecutor/: Policy execution enginescandb/: Database for scan results
cli/: CLI componentscomponents/: Reusable UI componentsreporter/: Output formatters (SARIF, JUnit, JSON, etc.)
content/: Default security policies (AWS, Linux, K8s, etc.)internal/: Internal packagesbundle/: Bundle loading and validationdatalakes/: Data storage implementationslsp/: Language Server Protocol support
examples/: Example policy filestest/: Integration testsdocs/: Documentation