The ec (Enterprise Contract) CLI is a command-line tool for verifying artifacts and evaluating software supply chain policies. It validates container image signatures, provenance, and enforces policies across various types of software artifacts using Open Policy Agent (OPA)/Rego rules.
make build # Build ec binary for current platform (creates dist/ec)
make dist # Build for all supported architectures
make clean # Remove build artifacts
DEBUG_BUILD=1 make build # Build with debugging symbols for gdb/dlv
make debug-run # Run binary with delve debugger (requires debug build)make test # Run all tests (unit, integration, generative)
make acceptance # Run acceptance tests (Cucumber/Gherkin, 20m timeout)
make scenario_<name> # Run single acceptance scenario (replace spaces with underscores)
make feature_<name> # Run all scenarios in a single feature file
# Running specific tests
go test -tags=unit ./internal/evaluator -run TestSpecificFunction
cd acceptance && go test -test.run 'TestFeatures/scenario_name'make lint # Run all linters (golangci-lint, addlicense, tekton-lint)
make lint-fix # Auto-fix linting issues
make ci # Run full CI suite (test + lint-fix + acceptance)Main commands in cmd/:
- validate - Validate container images, attestations, and policies
- test - Test policies against data (similar to conftest)
- fetch - Download and inspect attestations
- inspect - Examine policy bundles and data
- track - Track compliance status
- sigstore - Sigstore-related operations
- initialize - Initialize policy configurations
- Conftest Evaluator: Main evaluation engine using OPA/Rego
- Pluggable Rule Filtering: Extensible system for filtering which rules run based on:
- Pipeline intentions (build vs release vs production)
- Include/exclude lists (collections, packages, specific rules)
- Custom metadata criteria
- Result Processing: Complex rule result filtering with scoring, severity promotion/demotion, and effective time handling
Key Implementation Details:
- PolicyResolver interface provides comprehensive policy resolution for pre and post-evaluation filtering
- UnifiedPostEvaluationFilter implements unified filtering logic
- Sophisticated scoring system for include/exclude decisions (collections: 10pts, packages: 10pts per level, rules: +100pts, terms: +100pts)
- Term-based filtering allows fine-grained control (e.g.,
tasks.required_untrusted_task_found:clamav-scan) - See
.cursor/rules/rule_filtering_process.mdcand.cursor/rules/package_filtering_process.mdcfor detailed documentation
- Parsing and validation of in-toto attestations
- SLSA provenance processing (supports both v0.2 and v1.0)
- Integration with Sigstore for signature verification
VSA creates cryptographically signed attestations containing validation metadata and policy information after successful image validation.
Layered Architecture:
- Core Interfaces (
interfaces.go) - Fundamental VSA interfaces - Service Layer (
service.go) - High-level VSA processing orchestration - Core Logic (
vsa.go) - VSA data structures and predicate generation - Attestation (
attest.go) - DSSE envelope creation and signing - Storage (
storage*.go) - Abstract storage backends (local, Rekor) - Retrieval (
*_retriever.go) - VSA retrieval mechanisms - Orchestration (
orchestrator.go) - Complex VSA processing workflows - Validation (
validator.go) - VSA validation with policy comparison - Command Interface (
cmd/validate/vsa.go) - CLI for VSA validation
Key Features:
- Policy comparison and equivalence checking
- DSSE envelope signature verification (enabled by default)
- Multiple storage backends (local filesystem, Rekor transparency log)
- VSA expiration checking with configurable thresholds
- Batch validation from application snapshots with parallel processing
See .cursor/rules/vsa_functionality.mdc for comprehensive documentation.
- Multiple input sources: container images, files, Kubernetes resources
- Automatic detection and parsing of different artifact types
- OCI-based policy bundle loading
- Git repository policy fetching
- Policy metadata extraction and rule discovery
internal/signature/- Container image signature verificationinternal/image/- Container image operations and metadatainternal/kubernetes/- Kubernetes resource processinginternal/utils/- Common utilities and helpersinternal/rego/- Rego policy compilation and executioninternal/format/- Output formatting (JSON, YAML, etc.)
The project uses multiple Go modules:
- Root module - Main CLI application
- acceptance/ - Acceptance test module with Cucumber integration
- tools/ - Development tools and utilities
- Unit tests (
-tags=unit, 10s timeout) - Fast isolated tests - Integration tests (
-tags=integration, 15s timeout) - Component integration - Generative tests (
-tags=generative, 30s timeout) - Property-based testing - Acceptance tests (20m timeout) - End-to-end Cucumber scenarios with real artifacts
- Use
-persistflag to keep test environment after execution for debugging - Use
-restoreto run tests against persisted environment - Use
-tags=@focusto run specific scenarios
- Use
- Uses Cucumber/Gherkin syntax for feature definitions in
features/directory - Steps implemented in Go using Godog framework
- Self-contained test environment using Testcontainers
- WireMock for stubbing HTTP APIs (Kubernetes apiserver, Rekor)
- Snapshots stored in
features/__snapshots__/(update withUPDATE_SNAPS=true)
- Go 1.24.4+
- Make
- Podman/Docker for container operations
- Node.js for tekton-lint
-
Go checksum mismatch
go env -w GOPROXY='https://proxy.golang.org,direct' -
Container failures - Ensure podman runs as user service, not system service
systemctl status podman.socket podman.service systemctl disable --now podman.socket podman.service systemctl enable --user --now podman.socket podman.service -
Too many containers - Increase inotify watches
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
-
Key limits - Increase max keys
echo kernel.keys.maxkeys=1000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
-
Host resolution - Add to
/etc/hosts:127.0.0.1 apiserver.localhost 127.0.0.1 rekor.localhost
Policies can be loaded from:
- OCI registries:
oci::quay.io/repo/policy:tag - Git repositories:
git::https://github.com/repo//path - Local files/directories
- Use
--debugflag orEC_DEBUG=1environment variable - Debug mode preserves temporary
ec-work-*directories for inspection
Binaries are built with CGO_ENABLED=0 for OS compatibility, which affects DNS resolution. The Go native resolver cannot resolve second-level localhost domains like apiserver.localhost, requiring manual /etc/hosts entries for acceptance tests.
The build system supports all major platforms and architectures. Use make dist to build for all supported targets or make dist/ec_<os>_<arch> for specific platforms.
The evaluation system includes sophisticated rule filtering that operates at multiple levels:
-
Pipeline Intention Filtering (ECPolicyResolver only)
- When
pipeline_intentionis set: only include packages with matching metadata - When not set: only include general-purpose rules (no pipeline_intention metadata)
- When
-
Rule-by-Rule Evaluation
- Each rule is scored against include/exclude criteria
- Scoring system: collections (10pts), packages (10pts/level), rules (+100pts), terms (+100pts)
- Higher score determines inclusion/exclusion
-
Package-Level Determination
- If ANY rule in package is included → Package is included
- Package runs through conftest evaluation
- UnifiedPostEvaluationFilter processes all results using same PolicyResolver
- Filters warnings, failures, exceptions, skipped results
- Applies severity logic (promotion/demotion based on metadata)
- Handles effective time filtering (future-effective failures → warnings)
Terms provide fine-grained control over specific rule instances:
- Example:
tasks.required_untrusted_task_found:clamav-scan(scores 210pts) - Can override general patterns like
tasks.*(10pts) - Terms are extracted from result metadata during filtering
When modifying policy evaluation or filtering logic:
- Read
.cursor/rules/package_filtering_process.mdcfor architecture overview - Read
.cursor/rules/rule_filtering_process.mdcfor detailed filtering flow - Main filtering code is in
internal/evaluator/filters.go - Integration point is in
internal/evaluator/conftest_evaluator.go
When modifying VSA functionality:
- Read
.cursor/rules/vsa_functionality.mdcfor complete documentation - Understand the layered architecture (9 layers from interfaces to CLI)
- VSA code is in
internal/validate/vsa/directory - CLI implementation in
cmd/validate/vsa.go - Signature verification is enabled by default and implemented via DSSE envelopes
For detailed implementation guides, see:
.cursor/rules/package_filtering_process.mdc- Pluggable rule filtering system.cursor/rules/rule_filtering_process.mdc- Complete rule filtering process.cursor/rules/vsa_functionality.mdc- VSA architecture and workflows