|
| 1 | +# Enterprise Contract CLI - Agent Instructions |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +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. |
| 6 | + |
| 7 | +## Essential Commands |
| 8 | + |
| 9 | +### Building |
| 10 | +```bash |
| 11 | +make build # Build ec binary for current platform (creates dist/ec) |
| 12 | +make dist # Build for all supported architectures |
| 13 | +make clean # Remove build artifacts |
| 14 | +DEBUG_BUILD=1 make build # Build with debugging symbols for gdb/dlv |
| 15 | +make debug-run # Run binary with delve debugger (requires debug build) |
| 16 | +``` |
| 17 | + |
| 18 | +### Testing |
| 19 | +```bash |
| 20 | +make test # Run all tests (unit, integration, generative) |
| 21 | +make acceptance # Run acceptance tests (Cucumber/Gherkin, 20m timeout) |
| 22 | +make scenario_<name> # Run single acceptance scenario (replace spaces with underscores) |
| 23 | +make feature_<name> # Run all scenarios in a single feature file |
| 24 | + |
| 25 | +# Running specific tests |
| 26 | +go test -tags=unit ./internal/evaluator -run TestSpecificFunction |
| 27 | +cd acceptance && go test -test.run 'TestFeatures/scenario_name' |
| 28 | +``` |
| 29 | + |
| 30 | +### Code Quality |
| 31 | +```bash |
| 32 | +make lint # Run all linters (golangci-lint, addlicense, tekton-lint) |
| 33 | +make lint-fix # Auto-fix linting issues |
| 34 | +make ci # Run full CI suite (test + lint-fix + acceptance) |
| 35 | +``` |
| 36 | + |
| 37 | +## Architecture |
| 38 | + |
| 39 | +### Command Structure |
| 40 | +Main commands in `cmd/`: |
| 41 | +- **validate** - Validate container images, attestations, and policies |
| 42 | +- **test** - Test policies against data (similar to conftest) |
| 43 | +- **fetch** - Download and inspect attestations |
| 44 | +- **inspect** - Examine policy bundles and data |
| 45 | +- **track** - Track compliance status |
| 46 | +- **sigstore** - Sigstore-related operations |
| 47 | +- **initialize** - Initialize policy configurations |
| 48 | + |
| 49 | +### Core Components |
| 50 | + |
| 51 | +#### Policy Evaluation (`internal/evaluator/`) |
| 52 | +- **Conftest Evaluator**: Main evaluation engine using OPA/Rego |
| 53 | +- **Pluggable Rule Filtering**: Extensible system for filtering which rules run based on: |
| 54 | + - Pipeline intentions (build vs release vs production) |
| 55 | + - Include/exclude lists (collections, packages, specific rules) |
| 56 | + - Custom metadata criteria |
| 57 | +- **Result Processing**: Complex rule result filtering with scoring, severity promotion/demotion, and effective time handling |
| 58 | + |
| 59 | +**Key Implementation Details:** |
| 60 | +- PolicyResolver interface provides comprehensive policy resolution for pre and post-evaluation filtering |
| 61 | +- UnifiedPostEvaluationFilter implements unified filtering logic |
| 62 | +- Sophisticated scoring system for include/exclude decisions (collections: 10pts, packages: 10pts per level, rules: +100pts, terms: +100pts) |
| 63 | +- Term-based filtering allows fine-grained control (e.g., `tasks.required_untrusted_task_found:clamav-scan`) |
| 64 | +- See `.cursor/rules/rule_filtering_process.mdc` and `.cursor/rules/package_filtering_process.mdc` for detailed documentation |
| 65 | + |
| 66 | +#### Attestation Handling (`internal/attestation/`) |
| 67 | +- Parsing and validation of in-toto attestations |
| 68 | +- SLSA provenance processing (supports both v0.2 and v1.0) |
| 69 | +- Integration with Sigstore for signature verification |
| 70 | + |
| 71 | +#### VSA (Verification Summary Attestation) (`internal/validate/vsa/`) |
| 72 | +VSA creates cryptographically signed attestations containing validation metadata and policy information after successful image validation. |
| 73 | + |
| 74 | +**Layered Architecture:** |
| 75 | +1. Core Interfaces (`interfaces.go`) - Fundamental VSA interfaces |
| 76 | +2. Service Layer (`service.go`) - High-level VSA processing orchestration |
| 77 | +3. Core Logic (`vsa.go`) - VSA data structures and predicate generation |
| 78 | +4. Attestation (`attest.go`) - DSSE envelope creation and signing |
| 79 | +5. Storage (`storage*.go`) - Abstract storage backends (local, Rekor) |
| 80 | +6. Retrieval (`*_retriever.go`) - VSA retrieval mechanisms |
| 81 | +7. Orchestration (`orchestrator.go`) - Complex VSA processing workflows |
| 82 | +8. Validation (`validator.go`) - VSA validation with policy comparison |
| 83 | +9. Command Interface (`cmd/validate/vsa.go`) - CLI for VSA validation |
| 84 | + |
| 85 | +**Key Features:** |
| 86 | +- Policy comparison and equivalence checking |
| 87 | +- DSSE envelope signature verification (enabled by default) |
| 88 | +- Multiple storage backends (local filesystem, Rekor transparency log) |
| 89 | +- VSA expiration checking with configurable thresholds |
| 90 | +- Batch validation from application snapshots with parallel processing |
| 91 | + |
| 92 | +See `.cursor/rules/vsa_functionality.mdc` for comprehensive documentation. |
| 93 | + |
| 94 | +#### Input Processing (`internal/input/`) |
| 95 | +- Multiple input sources: container images, files, Kubernetes resources |
| 96 | +- Automatic detection and parsing of different artifact types |
| 97 | + |
| 98 | +#### Policy Management (`internal/policy/`) |
| 99 | +- OCI-based policy bundle loading |
| 100 | +- Git repository policy fetching |
| 101 | +- Policy metadata extraction and rule discovery |
| 102 | + |
| 103 | +### Key Internal Packages |
| 104 | +- `internal/signature/` - Container image signature verification |
| 105 | +- `internal/image/` - Container image operations and metadata |
| 106 | +- `internal/kubernetes/` - Kubernetes resource processing |
| 107 | +- `internal/utils/` - Common utilities and helpers |
| 108 | +- `internal/rego/` - Rego policy compilation and execution |
| 109 | +- `internal/format/` - Output formatting (JSON, YAML, etc.) |
| 110 | + |
| 111 | +## Module Structure |
| 112 | + |
| 113 | +The project uses multiple Go modules: |
| 114 | +- **Root module** - Main CLI application |
| 115 | +- **acceptance/** - Acceptance test module with Cucumber integration |
| 116 | +- **tools/** - Development tools and utilities |
| 117 | + |
| 118 | +## Testing Strategy |
| 119 | + |
| 120 | +### Test Types |
| 121 | +- **Unit tests** (`-tags=unit`, 10s timeout) - Fast isolated tests |
| 122 | +- **Integration tests** (`-tags=integration`, 15s timeout) - Component integration |
| 123 | +- **Generative tests** (`-tags=generative`, 30s timeout) - Property-based testing |
| 124 | +- **Acceptance tests** (20m timeout) - End-to-end Cucumber scenarios with real artifacts |
| 125 | + - Use `-persist` flag to keep test environment after execution for debugging |
| 126 | + - Use `-restore` to run tests against persisted environment |
| 127 | + - Use `-tags=@focus` to run specific scenarios |
| 128 | + |
| 129 | +### Acceptance Test Framework |
| 130 | +- Uses Cucumber/Gherkin syntax for feature definitions in `features/` directory |
| 131 | +- Steps implemented in Go using Godog framework |
| 132 | +- Self-contained test environment using Testcontainers |
| 133 | +- WireMock for stubbing HTTP APIs (Kubernetes apiserver, Rekor) |
| 134 | +- Snapshots stored in `features/__snapshots__/` (update with `UPDATE_SNAPS=true`) |
| 135 | + |
| 136 | +## Development Environment |
| 137 | + |
| 138 | +### Required Tools |
| 139 | +- Go 1.24.4+ |
| 140 | +- Make |
| 141 | +- Podman/Docker for container operations |
| 142 | +- Node.js for tekton-lint |
| 143 | + |
| 144 | +### Troubleshooting Common Issues |
| 145 | + |
| 146 | +1. **Go checksum mismatch** |
| 147 | + ```bash |
| 148 | + go env -w GOPROXY='https://proxy.golang.org,direct' |
| 149 | + ``` |
| 150 | + |
| 151 | +2. **Container failures** - Ensure podman runs as user service, not system service |
| 152 | + ```bash |
| 153 | + systemctl status podman.socket podman.service |
| 154 | + systemctl disable --now podman.socket podman.service |
| 155 | + systemctl enable --user --now podman.socket podman.service |
| 156 | + ``` |
| 157 | + |
| 158 | +3. **Too many containers** - Increase inotify watches |
| 159 | + ```bash |
| 160 | + echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p |
| 161 | + ``` |
| 162 | + |
| 163 | +4. **Key limits** - Increase max keys |
| 164 | + ```bash |
| 165 | + echo kernel.keys.maxkeys=1000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p |
| 166 | + ``` |
| 167 | + |
| 168 | +5. **Host resolution** - Add to `/etc/hosts`: |
| 169 | + ``` |
| 170 | + 127.0.0.1 apiserver.localhost |
| 171 | + 127.0.0.1 rekor.localhost |
| 172 | + ``` |
| 173 | + |
| 174 | +## Key Configuration |
| 175 | + |
| 176 | +### Policy Sources |
| 177 | +Policies can be loaded from: |
| 178 | +- OCI registries: `oci::quay.io/repo/policy:tag` |
| 179 | +- Git repositories: `git::https://github.com/repo//path` |
| 180 | +- Local files/directories |
| 181 | + |
| 182 | +### Debug Mode |
| 183 | +- Use `--debug` flag or `EC_DEBUG=1` environment variable |
| 184 | +- Debug mode preserves temporary `ec-work-*` directories for inspection |
| 185 | + |
| 186 | +## Special Considerations |
| 187 | + |
| 188 | +### CGO and DNS Resolution |
| 189 | +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. |
| 190 | + |
| 191 | +### Multi-Architecture Support |
| 192 | +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. |
| 193 | + |
| 194 | +### Policy Rule Filtering System |
| 195 | +The evaluation system includes sophisticated rule filtering that operates at multiple levels: |
| 196 | + |
| 197 | +#### Pre-Evaluation Filtering (Package Level) |
| 198 | +1. **Pipeline Intention Filtering** (ECPolicyResolver only) |
| 199 | + - When `pipeline_intention` is set: only include packages with matching metadata |
| 200 | + - When not set: only include general-purpose rules (no pipeline_intention metadata) |
| 201 | + |
| 202 | +2. **Rule-by-Rule Evaluation** |
| 203 | + - Each rule is scored against include/exclude criteria |
| 204 | + - Scoring system: collections (10pts), packages (10pts/level), rules (+100pts), terms (+100pts) |
| 205 | + - Higher score determines inclusion/exclusion |
| 206 | + |
| 207 | +3. **Package-Level Determination** |
| 208 | + - If ANY rule in package is included → Package is included |
| 209 | + - Package runs through conftest evaluation |
| 210 | + |
| 211 | +#### Post-Evaluation Filtering (Result Level) |
| 212 | +- UnifiedPostEvaluationFilter processes all results using same PolicyResolver |
| 213 | +- Filters warnings, failures, exceptions, skipped results |
| 214 | +- Applies severity logic (promotion/demotion based on metadata) |
| 215 | +- Handles effective time filtering (future-effective failures → warnings) |
| 216 | + |
| 217 | +#### Term-Based Filtering |
| 218 | +Terms provide fine-grained control over specific rule instances: |
| 219 | +- Example: `tasks.required_untrusted_task_found:clamav-scan` (scores 210pts) |
| 220 | +- Can override general patterns like `tasks.*` (10pts) |
| 221 | +- Terms are extracted from result metadata during filtering |
| 222 | + |
| 223 | +### Working with Rule Filtering Code |
| 224 | +When modifying policy evaluation or filtering logic: |
| 225 | +1. Read `.cursor/rules/package_filtering_process.mdc` for architecture overview |
| 226 | +2. Read `.cursor/rules/rule_filtering_process.mdc` for detailed filtering flow |
| 227 | +3. Main filtering code is in `internal/evaluator/filters.go` |
| 228 | +4. Integration point is in `internal/evaluator/conftest_evaluator.go` |
| 229 | + |
| 230 | +### Working with VSA Code |
| 231 | +When modifying VSA functionality: |
| 232 | +1. Read `.cursor/rules/vsa_functionality.mdc` for complete documentation |
| 233 | +2. Understand the layered architecture (9 layers from interfaces to CLI) |
| 234 | +3. VSA code is in `internal/validate/vsa/` directory |
| 235 | +4. CLI implementation in `cmd/validate/vsa.go` |
| 236 | +5. Signature verification is enabled by default and implemented via DSSE envelopes |
| 237 | + |
| 238 | +## Additional Documentation |
| 239 | + |
| 240 | +For detailed implementation guides, see: |
| 241 | +- `.cursor/rules/package_filtering_process.mdc` - Pluggable rule filtering system |
| 242 | +- `.cursor/rules/rule_filtering_process.mdc` - Complete rule filtering process |
| 243 | +- `.cursor/rules/vsa_functionality.mdc` - VSA architecture and workflows |
0 commit comments