|
| 1 | +--- |
| 2 | +applyTo: |
| 3 | + - "cmd/containerd-shim-runhcs-v1/**/*.go" |
| 4 | + - "cmd/containerd-shim-lcow-v2/**/*.go" |
| 5 | + - "internal/hcsoci/**/*.go" |
| 6 | + - "internal/uvm/**/*.go" |
| 7 | + - "internal/layers/**/*.go" |
| 8 | + - "internal/hcs/**/*.go" |
| 9 | + - "internal/gcs/**/*.go" |
| 10 | + - "internal/cow/**/*.go" |
| 11 | + - "internal/resources/**/*.go" |
| 12 | + - "internal/jobcontainers/**/*.go" |
| 13 | + - "internal/guest/**/*.go" |
| 14 | + - "internal/shim/**/*.go" |
| 15 | + - "internal/controller/**/*.go" |
| 16 | + - "internal/vm/**/*.go" |
| 17 | +--- |
| 18 | + |
| 19 | +# V2 Shim — Code Review Rules |
| 20 | + |
| 21 | +Review rules for the containerd shim v2 path: shim binaries, HCS/OCI bridge, |
| 22 | +UVM lifecycle, resource management, guest compute service, VM controller, |
| 23 | +and container/process abstractions. |
| 24 | + |
| 25 | +The **primary lens** is Go conventions and best practices. The hcsshim-specific |
| 26 | +rules below extend — never override — standard Go guidelines. |
| 27 | + |
| 28 | +--- |
| 29 | + |
| 30 | +## Go Conventions & Best Practices |
| 31 | + |
| 32 | +### Naming |
| 33 | +- Follow [Effective Go](https://go.dev/doc/effective_go) naming: MixedCaps, no underscores in Go names. |
| 34 | +- Package names are lowercase, single-word, no plurals. Avoid stutter (`hcs.HCSSystem` -> `hcs.System`). |
| 35 | +- Interfaces named after the method when single-method (`io.Reader`, not `io.IReader`). |
| 36 | +- Acronyms are all-caps (`ID`, `HTTP`, `UVM`), not `Id`, `Http`. |
| 37 | + |
| 38 | +### Exported vs Unexported |
| 39 | +- **If an exported symbol has no callers outside its package, unexport it.** |
| 40 | +- Flag new exports that are only used internally — keep the API surface minimal. |
| 41 | +- Exported types, functions, and methods MUST have doc comments (`// TypeName ...`). |
| 42 | +- Doc comments start with the symbol name and describe *what*, not *how*. |
| 43 | + |
| 44 | +### Error Handling |
| 45 | +- Use `%w` for error wrapping with `fmt.Errorf`; flag bare `%v` on error values. |
| 46 | +- Return errors, don't panic. Panics are only for truly unrecoverable programmer bugs. |
| 47 | +- Check every returned error. Flag `_ = fn()` where `fn` returns an error (unless in cleanup with a log). |
| 48 | +- Use `errors.Is` / `errors.As` for sentinel and type checks, never `==`. |
| 49 | +- Prefer typed errors or sentinel errors over string matching. |
| 50 | + |
| 51 | +### Resource Management |
| 52 | +- Every `io.Closer` must be `Close()`d — prefer `defer obj.Close()` immediately after creation. |
| 53 | +- If `Close()` can fail and it matters, capture the error: `defer func() { retErr = obj.Close() }()`. |
| 54 | +- Every handle (`os.File`, `syscall.Handle`, `windows.Handle`) must be closed in error paths. |
| 55 | +- Flag resources created in a loop without per-iteration cleanup. |
| 56 | + |
| 57 | +### Concurrency |
| 58 | +- Always pass `context.Context` as the first parameter; never store it in a struct. |
| 59 | +- Goroutines must respect `ctx.Done()`. Flag goroutines without cancellation. |
| 60 | +- Protect shared mutable state with `sync.Mutex` or channels. Flag unprotected access. |
| 61 | +- Never capture loop variables in goroutine closures without rebinding (pre-Go 1.22). |
| 62 | +- Prefer `sync.Once` for lazy initialization over manual bool + mutex patterns. |
| 63 | + |
| 64 | +### Interfaces |
| 65 | +- Keep interfaces small (1-3 methods). Accept interfaces, return concrete types. |
| 66 | +- Define interfaces at the consumer, not the implementer. |
| 67 | +- Flag empty interfaces (`interface{}`/`any`) when a specific type would work. |
| 68 | + |
| 69 | +### Tests |
| 70 | +- Test helpers must call `t.Helper()`. |
| 71 | +- Use `t.Cleanup()` for teardown instead of manual defers when appropriate. |
| 72 | +- Use table-driven tests for repetitive cases. |
| 73 | +- Test names: `TestFunctionName_Condition_ExpectedResult`. |
| 74 | +- Use `cmp.Diff` for struct comparison; `maps.Clone()` for copying maps. |
| 75 | +- Use `functional` build tag for tests needing a live VM or container. |
| 76 | + |
| 77 | +### Packages & Imports |
| 78 | +- Group imports: stdlib, external, internal. Use `goimports` ordering. |
| 79 | +- No circular dependencies. Flag new cross-package imports that break layering. |
| 80 | +- Internal packages should not leak implementation details through exported types. |
| 81 | + |
| 82 | +--- |
| 83 | + |
| 84 | +## hcsshim-Specific Rules |
| 85 | + |
| 86 | +### Resource Lifecycle (CRITICAL) |
| 87 | + |
| 88 | +- Every allocated resource MUST be registered with `r.Add(...)` or `r.SetLayers(...)`. |
| 89 | +- Flag any `ResourceCloser` returned from a helper that is NOT added to the resource tracker. |
| 90 | +- Flag resources allocated inside a loop where early `return` could skip `r.Add(...)`. |
| 91 | +- `CreateContainer` and similar orchestrators MUST `defer` a call to |
| 92 | + `resources.ReleaseResources(ctx, r, vm, true)` on error. |
| 93 | +- `ResourceCloserList.Release()` releases in REVERSE order. Do not manually reorder. |
| 94 | + |
| 95 | +### HCS / UVM Object Lifecycle |
| 96 | + |
| 97 | +- Every `hcs.System` or `cow.Container` MUST be `Close()`d. |
| 98 | +- Every `cow.Process` MUST be `Close()`d after `Wait()` completes. |
| 99 | +- `uvm.CreateLCOW` / `uvm.CreateWCOW` returns a UVM that MUST be `Close()`d on error. |
| 100 | +- `uvm.Start()` must be called after creation; flag orphaned UVMs. |
| 101 | +- Flag SCSI, vSMB, vPMEM, or Plan9 mounts added to a UVM but not tracked for cleanup. |
| 102 | + |
| 103 | +### Memory & Handle Leaks |
| 104 | + |
| 105 | +- Flag `syscall.Handle` or `windows.Handle` values not closed in error paths. |
| 106 | +- Flag goroutines that capture a `*cow.Process` or `*hcs.System` without ensuring |
| 107 | + the object outlives the goroutine. |
| 108 | + |
| 109 | +### Concurrency (hcsshim-specific) |
| 110 | + |
| 111 | +- `hcs.System` operations are NOT goroutine-safe. Flag concurrent access without sync. |
| 112 | +- UVM device maps (`scsiLocations`, `vsmb`, `plan9`, `vpmem`) are mutex-protected; |
| 113 | + flag direct map access without holding the lock. |
| 114 | + |
| 115 | +### Package Layering |
| 116 | + |
| 117 | +Flag these violations: |
| 118 | +- `internal/cow` importing anything above it (must be pure abstraction). |
| 119 | +- `internal/hcs` importing from `internal/hcsoci` or `internal/uvm`. |
| 120 | +- `internal/resources` importing from shim-level packages. |
| 121 | +- `cmd/` directly importing `internal/hcs` instead of going through `internal/hcsoci`. |
| 122 | +- `internal/controller/vm` importing from `internal/hcsoci`. |
| 123 | + |
| 124 | +### VM Controller & State Machine |
| 125 | + |
| 126 | +- Every state transition MUST be validated against allowed transitions. |
| 127 | +- Flag direct state assignment that bypasses the transition validation function. |
| 128 | +- Terminal states (`stopped`, `failed`) must not allow further transitions. |
| 129 | +- `vmmanager.LifetimeManager` and `guestmanager.Manager` MUST handle idempotent `Stop()`/`Close()`. |
| 130 | +- Flag implementations that panic or return untyped errors on double-close. |
| 131 | + |
| 132 | +### LCOW Shim V2 Service |
| 133 | + |
| 134 | +- Every containerd RPC handler MUST have proper context propagation and cancellation. |
| 135 | +- Flag handlers that block indefinitely without respecting `ctx.Done()`. |
| 136 | +- Flag missing cleanup in `Delete` — all resources from `Create` must be released. |
| 137 | +- The shim MUST NOT leak UVM references across task boundaries. |
| 138 | + |
| 139 | +--- |
| 140 | + |
| 141 | +## Review Output |
| 142 | + |
| 143 | +- Max 2 comments per concern; group related items. |
| 144 | +- Use **[BLOCKER]** only for resource leaks, correctness, safety, or API-breaking issues. |
| 145 | +- Use **[ISSUE]** for likely bugs or pattern deviations. |
| 146 | +- Use **[SUGGESTION]** for non-blocking improvements. |
0 commit comments