Skip to content

Commit fe70af9

Browse files
bcrochetacornett21
authored andcommitted
build: set CGO_ENABLED=0 for Mac cross-compilation
Mac builds were missing CGO_ENABLED=0, unlike the Linux build template. This ensures consistent static builds across all platforms.
1 parent d780b67 commit fe70af9

2 files changed

Lines changed: 238 additions & 1 deletion

File tree

AGENTS.md

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
# AGENTS.md
2+
3+
Guidance for agentic coding agents working in this repository.
4+
5+
## Project Overview
6+
7+
OpenShift Preflight is a Go CLI tool for Red Hat Software Certification that validates partner-submitted containers and operator bundles. Module: `github.com/redhat-openshift-ecosystem/openshift-preflight`.
8+
9+
## Build Commands
10+
11+
```bash
12+
make build # Build the preflight binary
13+
make build-multi-arch-linux # Build for amd64, arm64, ppc64le, s390x
14+
make build-multi-arch-mac # Build for amd64, arm64 (Darwin)
15+
```
16+
17+
All builds use `CGO_ENABLED=0` and `-trimpath`. Version metadata is injected via `-ldflags`.
18+
19+
## Test Commands
20+
21+
```bash
22+
make test # Run all unit tests (excludes e2e)
23+
make cover # Run tests with -race and coverage report
24+
make test-e2e # End-to-end tests (requires live OpenShift cluster)
25+
```
26+
27+
The `-tags testing` build tag is **required** for all unit test runs.
28+
29+
### Running a Single Package's Tests
30+
31+
```bash
32+
go test -v -tags testing \
33+
-ldflags "-X github.com/redhat-openshift-ecosystem/openshift-preflight/version.commit=bar \
34+
-X github.com/redhat-openshift-ecosystem/openshift-preflight/version.version=foo" \
35+
./internal/policy/container/
36+
```
37+
38+
### Running a Single Ginkgo Spec or Describe Block
39+
40+
Use `--ginkgo.focus` to filter by description string. Run from the package directory:
41+
42+
```bash
43+
go test -v -tags testing \
44+
-ldflags "-X github.com/redhat-openshift-ecosystem/openshift-preflight/version.commit=bar \
45+
-X github.com/redhat-openshift-ecosystem/openshift-preflight/version.version=foo" \
46+
-run TestContainer \
47+
--ginkgo.focus="HasLicense" \
48+
./internal/policy/container/
49+
```
50+
51+
The `-run` value must match the `TestXxx` suite function name defined in the `*_suite_test.go` file for that package. Common mappings:
52+
53+
| `-run` flag | Package path |
54+
|------------------------|-------------------------------------|
55+
| `TestInternalEngine` | `./internal/engine/` |
56+
| `TestContainer` | `./internal/policy/container/` |
57+
| `TestOperator` | `./internal/policy/operator/` |
58+
| `TestRuntime` | `./internal/runtime/` |
59+
60+
## Code Quality Commands
61+
62+
```bash
63+
make lint # golangci-lint run --build-tags testing
64+
make fmt # gofumpt -l -w . (must produce no diff)
65+
make vet # go vet -tags testing ./...
66+
make tidy # go mod tidy (must produce no diff)
67+
```
68+
69+
All PRs must pass lint, fmt, vet, and tidy with no diffs.
70+
71+
## Code Style
72+
73+
### Formatting
74+
75+
- Formatter: **gofumpt** (stricter than `gofmt`). Run `make fmt` before committing.
76+
- Do not manually format; let `gofumpt` handle it.
77+
78+
### Import Organization
79+
80+
Three groups, separated by blank lines, enforced by `goimports` with local prefix:
81+
82+
```go
83+
import (
84+
// 1. Standard library
85+
"context"
86+
"fmt"
87+
88+
// 2. Third-party dependencies
89+
"github.com/go-logr/logr"
90+
"github.com/google/go-containerregistry/pkg/crane"
91+
92+
// 3. Project-local (github.com/redhat-openshift-ecosystem/openshift-preflight/...)
93+
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/check"
94+
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/image"
95+
)
96+
```
97+
98+
### Required Import Aliases
99+
100+
The `importas` linter enforces these aliases — use them exactly:
101+
102+
| Import path | Alias |
103+
|------------------------------------------------------------------|---------------------|
104+
| `k8s.io/api/core/v1` | `corev1` |
105+
| `k8s.io/apimachinery/pkg/apis/meta/v1` | `metav1` |
106+
| `k8s.io/apimachinery/pkg/api/errors` | `apierrors` |
107+
| `github.com/operator-framework/api/pkg/operators/v1alpha1` | `operatorsv1alpha1` |
108+
| `github.com/operator-framework/api/pkg/operators/v1` | `operatorsv1` |
109+
| `github.com/openshift/api/image/v1` | `imagestreamv1` |
110+
111+
Ginkgo and Gomega use dot imports in test files (allowed by lint config):
112+
```go
113+
import (
114+
. "github.com/onsi/ginkgo/v2"
115+
. "github.com/onsi/gomega"
116+
)
117+
```
118+
119+
### Naming Conventions
120+
121+
- Types and exported symbols: `PascalCase`
122+
- Unexported implementation types: `camelCase` (e.g., `craneEngine`)
123+
- Interfaces are exported; implementations may be unexported
124+
- Check structs: name matches the `Name()` return (e.g., `HasLicenseCheck``"HasLicense"`)
125+
- Constructors: `New<Type>(...)` returning the interface or concrete type
126+
- Method receivers: short abbreviation of the receiver type (e.g., `p *HasLicenseCheck`, `c *craneEngine`)
127+
- Package-level sentinel errors: `var errSomething = errors.New("...")`
128+
129+
### Error Handling
130+
131+
- Wrap errors with `fmt.Errorf("context: %w", err)` to preserve the chain
132+
- Use `%v` for non-wrapped formatting, `%w` when callers may use `errors.Is`/`errors.As`
133+
- Use `errors.Is(err, target)` for sentinel comparisons — never compare error strings
134+
- Non-fatal errors (informational): log with `logger.Error(err, "message")` and continue
135+
- Fatal errors: wrap and return up the call stack
136+
- Validation failures (check did not pass, no code error): return `false, nil`
137+
138+
```go
139+
// Compile-time interface satisfaction check — place near the type definition
140+
var _ check.Check = &HasLicenseCheck{}
141+
```
142+
143+
### Check Implementation Pattern
144+
145+
```go
146+
var _ check.Check = &MyCheck{}
147+
148+
type MyCheck struct{}
149+
150+
func (p *MyCheck) Validate(ctx context.Context, imgRef image.ImageReference) (bool, error) { ... }
151+
func (p *MyCheck) Name() string { return "MyCheck" }
152+
func (p *MyCheck) Metadata() check.Metadata { return check.Metadata{ ... } }
153+
func (p *MyCheck) Help() check.HelpText { return check.HelpText{ ... } }
154+
func (p *MyCheck) RequiredFilePatterns() []string { return []string{...} }
155+
```
156+
157+
## Testing Patterns (Ginkgo/Gomega)
158+
159+
Every package has a suite bootstrap file `*_suite_test.go`:
160+
161+
```go
162+
package mypkg
163+
164+
import (
165+
"testing"
166+
. "github.com/onsi/ginkgo/v2"
167+
. "github.com/onsi/gomega"
168+
)
169+
170+
func TestMyPkg(t *testing.T) {
171+
RegisterFailHandler(Fail)
172+
RunSpecs(t, "MyPkg Suite")
173+
}
174+
```
175+
176+
Individual spec files follow this structure:
177+
178+
```go
179+
var _ = Describe("MyCheck", func() {
180+
var check MyCheck
181+
182+
BeforeEach(func() {
183+
check = MyCheck{}
184+
})
185+
186+
Context("when the condition is met", func() {
187+
It("should pass validation", func() {
188+
ok, err := check.Validate(context.TODO(), imgRef)
189+
Expect(err).ToNot(HaveOccurred())
190+
Expect(ok).To(BeTrue())
191+
})
192+
})
193+
})
194+
```
195+
196+
- Use `Describe` / `Context` / `When` for nesting (semantically equivalent in Ginkgo)
197+
- `It` for leaf test cases
198+
- `DeferCleanup(...)` preferred over `AfterEach` for resource cleanup
199+
- `DescribeTable` + `Entry` for table-driven tests
200+
- Fakes: unexported structs implementing the target interface, defined in suite or spec file
201+
- Kubernetes fakes: `sigs.k8s.io/controller-runtime/pkg/client/fake` builder
202+
- Container image fakes: `github.com/google/go-containerregistry/pkg/v1/fake.FakeImage`
203+
204+
## Commit Conventions
205+
206+
Use conventional commits:
207+
208+
```
209+
<subsystem>: <what changed>
210+
211+
Body explaining why the change was made.
212+
213+
Refs: #<issue-number>
214+
```
215+
216+
Examples: `engine: add layer extraction span attributes`, `check: fix nil pointer in HasLicense`
217+
218+
## Git Hygiene
219+
220+
**Never use `git add .`** — always stage individual files explicitly:
221+
222+
```bash
223+
# Good
224+
git add internal/engine/engine.go internal/engine/engine_test.go
225+
226+
# Bad — may stage unintended artifacts
227+
git add .
228+
```
229+
230+
## Key Architecture Notes
231+
232+
- **Policies** (`internal/policy/`) define collections of checks for containers and operators
233+
- **Engine** (`internal/engine/`) orchestrates check execution using `crane` for image operations
234+
- **Checks** implement `internal/check.Check` interface: `Validate`, `Name`, `Metadata`, `Help`
235+
- **Configuration** uses `PFLT_` env var prefix via Viper; see `internal/config/` and `internal/viper/`
236+
- **Artifacts** output to `artifacts/` directory by default (`PFLT_ARTIFACTS` overrides)
237+
- **Logging**: use the `logr` logger from context (`logr.FromContextOrDiscard(ctx)`); log levels are warn/info/debug/trace

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ build-multi-arch-mac: $(addprefix build-mac-,$(ARCHITECTURES_MAC))
3333
define MAC_ARCHITECTURE_template
3434
.PHONY: build-mac-$(1)
3535
build-mac-$(1):
36-
GOOS=darwin GOARCH=$(1) go build -o $(BINARY)-darwin-$(1) -trimpath -ldflags "-s -w -X github.com/redhat-openshift-ecosystem/openshift-preflight/version.commit=$(VERSION) \
36+
GOOS=darwin GOARCH=$(1) CGO_ENABLED=0 go build -o $(BINARY)-darwin-$(1) -trimpath -ldflags "-s -w -X github.com/redhat-openshift-ecosystem/openshift-preflight/version.commit=$(VERSION) \
3737
-X github.com/redhat-openshift-ecosystem/openshift-preflight/version.version=$(RELEASE_TAG)" cmd/preflight/main.go
3838
endef
3939

0 commit comments

Comments
 (0)