Conversation
|
Skipping CI for Draft Pull Request. |
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The new rhcosOSImageRegexp is much stricter than the previous version and assumes a very specific
4.<minor>[.<suffix>]layout; consider adding tests for older/variant osImage formats (e.g. including additional patch segments or different separators) or relaxing the regex to avoid breaking RHCOS detection on existing clusters. - extractRHELMajorVersion currently defaults to "9" on parse failure, which could silently misclassify RHEL CPEs; it may be safer to return an empty value and handle the fallback explicitly where it is used, or log and skip the RHEL CPE path instead of assuming 9.
- The new ocpVersion parameter passed into attachRPMtoRHCOS and buildRHCOSIndexReport is not used for any logic (only logged and then ignored); if there is no planned use, you could simplify the signatures back down to reduce cognitive load and avoid confusion.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new rhcosOSImageRegexp is much stricter than the previous version and assumes a very specific `4.<minor>[.<suffix>]` layout; consider adding tests for older/variant osImage formats (e.g. including additional patch segments or different separators) or relaxing the regex to avoid breaking RHCOS detection on existing clusters.
- extractRHELMajorVersion currently defaults to "9" on parse failure, which could silently misclassify RHEL CPEs; it may be safer to return an empty value and handle the fallback explicitly where it is used, or log and skip the RHEL CPE path instead of assuming 9.
- The new ocpVersion parameter passed into attachRPMtoRHCOS and buildRHCOSIndexReport is not used for any logic (only logged and then ignored); if there is no planned use, you could simplify the signatures back down to reduce cognitive load and avoid confusion.
## Individual Comments
### Comment 1
<location path="sensor/common/compliance/node_inventory_handler_impl.go" line_range="491-494" />
<code_context>
+// isNewRHCOSVersionSchema returns true if the RHCOS version follows the RHEL-style
+// (9.x, 10.x) rather than the OCP-style (4xx.x).
+// RHCOS 4.19+ reports versions like "9.6.20260217-1" instead of "418.94.202501011408".
+func isNewRHCOSVersionSchema(version string) bool {
+ if len(version) == 0 {
+ return false
+ }
+ parts := strings.SplitN(version, ".", 2)
+ if len(parts) < 2 {
+ return false
+ }
+ major, err := strconv.Atoi(parts[0])
+ if err != nil {
+ return false
+ }
+ // RHEL versions are 8.x, 9.x, 10.x (single/double digit major)
+ // OCP-derived versions are 412.x, 413.x, 418.x (triple digit major)
+ return major < 100
</code_context>
<issue_to_address>
**suggestion:** Align `isNewRHCOSVersionSchema` comment with the actual heuristic
The logic currently classifies any version with `major < 100` as using the new schema, but the comment frames this specifically as RHEL (8/9/10) vs OCP 4xx. That’s a broader heuristic than the comment implies. Please either (a) tighten the check to the expected ranges (e.g., known RHEL/OCP majors) or (b) update the comment to clearly document the actual behavior ("major < 100" = RHEL-style, `>= 100` = OCP-style).
```suggestion
// isNewRHCOSVersionSchema returns true if the RHCOS version is interpreted as
// "RHEL-style" (major < 100, e.g. 8.x, 9.x, 10.x) rather than "OCP-style"
// (major >= 100, e.g. 412.x, 418.x).
// RHCOS 4.19+ reports versions like "9.6.20260217-1" instead of "418.94.202501011408".
func isNewRHCOSVersionSchema(version string) bool {
```
</issue_to_address>
### Comment 2
<location path="sensor/common/compliance/node_inventory_handler_impl.go" line_range="475" />
<code_context>
return []int32{v[0], v[1], 0, 0, 0, 0, 0, 0, 0, 0}
}
-func noop(_, _ string, rpm *v4.IndexReport) *v4.IndexReport {
+// extractRHELMajorVersion extracts the major version from a RHEL-style version string.
+// For example, "9.6.20260217-1" returns "9".
</code_context>
<issue_to_address>
**issue (complexity):** Consider simplifying the new RHCOS handling by narrowing the wrapper function signatures and centralizing version and repository selection logic into focused helpers.
You can preserve the new behavior while significantly reducing complexity by tightening the function signatures and consolidating the version/repo logic.
### 1. Drop `ocpVersion` from the wrapper function type
`ocpVersion` is only used for logging in `sendNodeIndex` and is not consulted in `buildRHCOSIndexReport`. Passing it through multiple layers just to satisfy a function type increases cognitive load.
You can keep `GetRHCOSVersion` as-is (it may be useful elsewhere) but narrow the wrapper function to exactly what’s needed:
```go
// Narrowed wrapper type: only pass what is actually needed downstream.
type indexWrapperFunc func(version, arch string, rpm *v4.IndexReport) *v4.IndexReport
func noop(_ , _ string, rpm *v4.IndexReport) *v4.IndexReport {
return rpm
}
func (c *nodeInventoryHandlerImpl) sendNodeIndex(toC chan<- *message.ExpiringMessage, indexWrap *index.IndexReportWrap) {
// ...
isRHCOS, ocpVersion, version, err := c.nodeRHCOSMatcher.GetRHCOSVersion(indexWrap.NodeName)
// keep ocpVersion for logging only
log.Debugf("Node=%q discovered RHCOS=%t ocp-version=%q rhcos-version=%q", indexWrap.NodeName, isRHCOS, ocpVersion, version)
irWrapperFunc := indexWrapperFunc(noop)
arch := c.archCache[indexWrap.NodeName]
if isRHCOS {
// ...
irWrapperFunc = attachRPMtoRHCOS
}
toC <- message.New(¢ral.MsgFromSensor{
Msg: ¢ral.MsgFromSensor_Event{
Event: ¢ral.SensorEvent{
// ...
Resource: ¢ral.SensorEvent_IndexReport{
IndexReport: irWrapperFunc(version, arch, indexWrap.IndexReport),
},
},
},
})
}
```
And adjust `attachRPMtoRHCOS` accordingly:
```go
func attachRPMtoRHCOS(version, arch string, rpm *v4.IndexReport) *v4.IndexReport {
idCandidate := 600
// ... unchanged ...
strID := strconv.Itoa(idCandidate)
oci := buildRHCOSIndexReport(strID, version, arch)
// ... unchanged ...
return oci
}
```
This removes unused parameters from `noop` and `attachRPMtoRHCOS` while keeping the same behavior (ocpVersion is still logged).
### 2. Collapse the version-schema helpers into one utility
`isNewRHCOSVersionSchema` and `extractRHELMajorVersion` both parse the same `version` string. You can do this once and return both the scheme and the major:
```go
type rhcosVersionScheme struct {
RHELMajor string
IsRHEL bool
}
// parseRHCOSVersionSchema parses the version once and indicates whether it is RHEL-style.
func parseRHCOSVersionSchema(version string) rhcosVersionScheme {
parts := strings.SplitN(version, ".", 2)
if len(parts) < 2 {
return rhcosVersionScheme{RHELMajor: "9", IsRHEL: false}
}
majorStr := parts[0]
majorInt, err := strconv.Atoi(majorStr)
if err != nil {
return rhcosVersionScheme{RHELMajor: "9", IsRHEL: false}
}
// RHEL: 8.x, 9.x, 10.x; OCP-style: 412.x, 418.x, ...
if majorInt < 100 {
return rhcosVersionScheme{RHELMajor: majorStr, IsRHEL: true}
}
return rhcosVersionScheme{RHELMajor: "9", IsRHEL: false}
}
```
Then `buildRHCOSIndexReport` only calls this once.
### 3. Extract a repo config helper to remove duplication in `buildRHCOSIndexReport`
Right now `buildRHCOSIndexReport` sets `repoKey`, `repoName`, `repoURI`, `repoCPE` with a default and overrides them conditionally, then uses the same values multiple times. A small struct plus a helper makes the function shorter and clearer:
```go
type rhcosRepoConfig struct {
Name string
Key string
URI string
CPE string
}
func determineRHCOSRepo(version string) rhcosRepoConfig {
scheme := parseRHCOSVersionSchema(version)
// Default: golden image repo
cfg := rhcosRepoConfig{
Name: goldenName,
Key: goldenKey,
URI: goldenURI,
CPE: "cpe:2.3:*",
}
if scheme.IsRHEL {
// RHCOS 4.19+ RHEL-style versions
rhelMajor := scheme.RHELMajor
cfg.Key = rhelCPEKey
cfg.Name = fmt.Sprintf("cpe:/o:redhat:enterprise_linux:%s::baseos", rhelMajor)
cfg.URI = ""
cfg.CPE = fmt.Sprintf("cpe:2.3:o:redhat:enterprise_linux:%s:*:baseos:*:*:*:*:*", rhelMajor)
log.Debugf("RHCOS 4.19+ detected (version=%s): using RHEL %s CPE repository for vulnerability matching", version, rhelMajor)
}
return cfg
}
```
Then `buildRHCOSIndexReport` becomes:
```go
func buildRHCOSIndexReport(id, version, arch string) *v4.IndexReport {
repo := determineRHCOSRepo(version)
return &v4.IndexReport{
// ...
Contents: &v4.Contents{
Packages: map[string]*v4.Package{
id: {
// ...
Source: &v4.Package{
Id: id,
Name: "rhcos",
Kind: "source",
Version: version,
Cpe: repo.CPE,
},
Arch: arch,
Cpe: repo.CPE,
},
},
PackagesDEPRECATED: []*v4.Package{
{
// same fields, use repo.CPE
},
},
Repositories: map[string]*v4.Repository{
id: {
Id: id,
Name: repo.Name,
Key: repo.Key,
Uri: repo.URI,
Cpe: repo.CPE,
},
},
RepositoriesDEPRECATED: []*v4.Repository{
{
Id: id,
Name: repo.Name,
Key: repo.Key,
Uri: repo.URI,
Cpe: repo.CPE,
},
},
// ...
},
}
}
```
This keeps all the new behavior (including the RHEL CPE selection and logging) but:
- Removes unused parameters from `noop` and `attachRPMtoRHCOS`.
- Centralizes version parsing into one helper.
- Encapsulates repo selection and removes duplicated assignment.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| // isNewRHCOSVersionSchema returns true if the RHCOS version follows the RHEL-style | ||
| // (9.x, 10.x) rather than the OCP-style (4xx.x). | ||
| // RHCOS 4.19+ reports versions like "9.6.20260217-1" instead of "418.94.202501011408". | ||
| func isNewRHCOSVersionSchema(version string) bool { |
There was a problem hiding this comment.
suggestion: Align isNewRHCOSVersionSchema comment with the actual heuristic
The logic currently classifies any version with major < 100 as using the new schema, but the comment frames this specifically as RHEL (8/9/10) vs OCP 4xx. That’s a broader heuristic than the comment implies. Please either (a) tighten the check to the expected ranges (e.g., known RHEL/OCP majors) or (b) update the comment to clearly document the actual behavior ("major < 100" = RHEL-style, >= 100 = OCP-style).
| // isNewRHCOSVersionSchema returns true if the RHCOS version follows the RHEL-style | |
| // (9.x, 10.x) rather than the OCP-style (4xx.x). | |
| // RHCOS 4.19+ reports versions like "9.6.20260217-1" instead of "418.94.202501011408". | |
| func isNewRHCOSVersionSchema(version string) bool { | |
| // isNewRHCOSVersionSchema returns true if the RHCOS version is interpreted as | |
| // "RHEL-style" (major < 100, e.g. 8.x, 9.x, 10.x) rather than "OCP-style" | |
| // (major >= 100, e.g. 412.x, 418.x). | |
| // RHCOS 4.19+ reports versions like "9.6.20260217-1" instead of "418.94.202501011408". | |
| func isNewRHCOSVersionSchema(version string) bool { |
| return []int32{v[0], v[1], 0, 0, 0, 0, 0, 0, 0, 0} | ||
| } | ||
|
|
||
| func noop(_, _ string, rpm *v4.IndexReport) *v4.IndexReport { |
There was a problem hiding this comment.
issue (complexity): Consider simplifying the new RHCOS handling by narrowing the wrapper function signatures and centralizing version and repository selection logic into focused helpers.
You can preserve the new behavior while significantly reducing complexity by tightening the function signatures and consolidating the version/repo logic.
1. Drop ocpVersion from the wrapper function type
ocpVersion is only used for logging in sendNodeIndex and is not consulted in buildRHCOSIndexReport. Passing it through multiple layers just to satisfy a function type increases cognitive load.
You can keep GetRHCOSVersion as-is (it may be useful elsewhere) but narrow the wrapper function to exactly what’s needed:
// Narrowed wrapper type: only pass what is actually needed downstream.
type indexWrapperFunc func(version, arch string, rpm *v4.IndexReport) *v4.IndexReport
func noop(_ , _ string, rpm *v4.IndexReport) *v4.IndexReport {
return rpm
}
func (c *nodeInventoryHandlerImpl) sendNodeIndex(toC chan<- *message.ExpiringMessage, indexWrap *index.IndexReportWrap) {
// ...
isRHCOS, ocpVersion, version, err := c.nodeRHCOSMatcher.GetRHCOSVersion(indexWrap.NodeName)
// keep ocpVersion for logging only
log.Debugf("Node=%q discovered RHCOS=%t ocp-version=%q rhcos-version=%q", indexWrap.NodeName, isRHCOS, ocpVersion, version)
irWrapperFunc := indexWrapperFunc(noop)
arch := c.archCache[indexWrap.NodeName]
if isRHCOS {
// ...
irWrapperFunc = attachRPMtoRHCOS
}
toC <- message.New(¢ral.MsgFromSensor{
Msg: ¢ral.MsgFromSensor_Event{
Event: ¢ral.SensorEvent{
// ...
Resource: ¢ral.SensorEvent_IndexReport{
IndexReport: irWrapperFunc(version, arch, indexWrap.IndexReport),
},
},
},
})
}And adjust attachRPMtoRHCOS accordingly:
func attachRPMtoRHCOS(version, arch string, rpm *v4.IndexReport) *v4.IndexReport {
idCandidate := 600
// ... unchanged ...
strID := strconv.Itoa(idCandidate)
oci := buildRHCOSIndexReport(strID, version, arch)
// ... unchanged ...
return oci
}This removes unused parameters from noop and attachRPMtoRHCOS while keeping the same behavior (ocpVersion is still logged).
2. Collapse the version-schema helpers into one utility
isNewRHCOSVersionSchema and extractRHELMajorVersion both parse the same version string. You can do this once and return both the scheme and the major:
type rhcosVersionScheme struct {
RHELMajor string
IsRHEL bool
}
// parseRHCOSVersionSchema parses the version once and indicates whether it is RHEL-style.
func parseRHCOSVersionSchema(version string) rhcosVersionScheme {
parts := strings.SplitN(version, ".", 2)
if len(parts) < 2 {
return rhcosVersionScheme{RHELMajor: "9", IsRHEL: false}
}
majorStr := parts[0]
majorInt, err := strconv.Atoi(majorStr)
if err != nil {
return rhcosVersionScheme{RHELMajor: "9", IsRHEL: false}
}
// RHEL: 8.x, 9.x, 10.x; OCP-style: 412.x, 418.x, ...
if majorInt < 100 {
return rhcosVersionScheme{RHELMajor: majorStr, IsRHEL: true}
}
return rhcosVersionScheme{RHELMajor: "9", IsRHEL: false}
}Then buildRHCOSIndexReport only calls this once.
3. Extract a repo config helper to remove duplication in buildRHCOSIndexReport
Right now buildRHCOSIndexReport sets repoKey, repoName, repoURI, repoCPE with a default and overrides them conditionally, then uses the same values multiple times. A small struct plus a helper makes the function shorter and clearer:
type rhcosRepoConfig struct {
Name string
Key string
URI string
CPE string
}
func determineRHCOSRepo(version string) rhcosRepoConfig {
scheme := parseRHCOSVersionSchema(version)
// Default: golden image repo
cfg := rhcosRepoConfig{
Name: goldenName,
Key: goldenKey,
URI: goldenURI,
CPE: "cpe:2.3:*",
}
if scheme.IsRHEL {
// RHCOS 4.19+ RHEL-style versions
rhelMajor := scheme.RHELMajor
cfg.Key = rhelCPEKey
cfg.Name = fmt.Sprintf("cpe:/o:redhat:enterprise_linux:%s::baseos", rhelMajor)
cfg.URI = ""
cfg.CPE = fmt.Sprintf("cpe:2.3:o:redhat:enterprise_linux:%s:*:baseos:*:*:*:*:*", rhelMajor)
log.Debugf("RHCOS 4.19+ detected (version=%s): using RHEL %s CPE repository for vulnerability matching", version, rhelMajor)
}
return cfg
}Then buildRHCOSIndexReport becomes:
func buildRHCOSIndexReport(id, version, arch string) *v4.IndexReport {
repo := determineRHCOSRepo(version)
return &v4.IndexReport{
// ...
Contents: &v4.Contents{
Packages: map[string]*v4.Package{
id: {
// ...
Source: &v4.Package{
Id: id,
Name: "rhcos",
Kind: "source",
Version: version,
Cpe: repo.CPE,
},
Arch: arch,
Cpe: repo.CPE,
},
},
PackagesDEPRECATED: []*v4.Package{
{
// same fields, use repo.CPE
},
},
Repositories: map[string]*v4.Repository{
id: {
Id: id,
Name: repo.Name,
Key: repo.Key,
Uri: repo.URI,
Cpe: repo.CPE,
},
},
RepositoriesDEPRECATED: []*v4.Repository{
{
Id: id,
Name: repo.Name,
Key: repo.Key,
Uri: repo.URI,
Cpe: repo.CPE,
},
},
// ...
},
}
}This keeps all the new behavior (including the RHEL CPE selection and logging) but:
- Removes unused parameters from
noopandattachRPMtoRHCOS. - Centralizes version parsing into one helper.
- Encapsulates repo selection and removes duplicated assignment.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #19376 +/- ##
=======================================
Coverage 49.64% 49.64%
=======================================
Files 2698 2698
Lines 203066 203117 +51
=======================================
+ Hits 100809 100845 +36
- Misses 94734 94750 +16
+ Partials 7523 7522 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Images are ready for the commit at 9d995a5. To use with deploy scripts, first |
Description
change me!
User-facing documentation
Testing and quality
Automated testing
How I validated my change
change me!