-
Notifications
You must be signed in to change notification settings - Fork 8
HYPERFLEET-387 | refactor: refactor config_loader with better validator #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HYPERFLEET-387 | refactor: refactor config_loader with better validator #21
Conversation
WalkthroughThe PR restructures config loading and validation into a phased Validator (structure, file references, semantic) with loader.go delegating to it and propagating baseDir for secure path resolution. It replaces ad-hoc struct validation with go-playground/validator integration, adds struct-level and custom validators, introduces FieldExpressionDef and ActionBase in config types, and implements parameter type conversion helpers in the executor. Many tests and READMEs were updated to reflect new types, validation entry points, and error messages. Several legacy validator_schema components were removed and replaced by the new validator/struct_validator modules. Sequence Diagram(s)sequenceDiagram
participant CLI as Loader
participant V as Validator
participant FS as FileSystem
participant CEL as CEL/Semantic Engine
CLI->>V: NewValidator(config, baseDir)
CLI->>V: ValidateStructure()
V-->>CLI: structural errors / OK
CLI->>V: ValidateFileReferences()
V->>FS: resolvePath(ref) / loadYAMLFile(ref)
FS-->>V: file contents / error
V-->>CLI: file reference errors / OK
CLI->>V: ValidateSemantic()
V->>CEL: init env, evaluate CEL/templates
CEL-->>V: semantic errors / OK
V-->>CLI: aggregated validation result
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (5)
internal/config_loader/struct_validator.go (1)
30-48: Consider logging custom validation registration errors.The custom validation registrations (lines 35-36) ignore errors using
_. While these registrations are unlikely to fail, consider logging any errors to aid debugging during development:🔎 Optional improvement to log registration errors
func getStructValidator() *validator.Validate { structValidatorOnce.Do(func() { structValidator = validator.New() // Register custom validations - _ = structValidator.RegisterValidation("resourcename", validateResourceName) - _ = structValidator.RegisterValidation("validoperator", validateOperator) + if err := structValidator.RegisterValidation("resourcename", validateResourceName); err != nil { + panic(fmt.Sprintf("failed to register resourcename validation: %v", err)) + } + if err := structValidator.RegisterValidation("validoperator", validateOperator); err != nil { + panic(fmt.Sprintf("failed to register validoperator validation: %v", err)) + } // Use yaml tag names for field names in errors structValidator.RegisterTagNameFunc(func(fld reflect.StructField) string {Note: Using
panicinsync.Onceinitialization is acceptable since these registrations should never fail in production and indicate a programming error if they do.internal/config_loader/README.md (1)
117-124: Add language specifier to fenced code block.The error message example code block at line 119 is missing a language specifier. This was flagged by markdownlint.
🔎 Proposed fix
### Error Messages Validation errors are descriptive: -``` +```text spec.params[0].name is required spec.preconditions[1].apiCall.method "INVALID" is invalid (allowed: GET, POST, PUT, PATCH, DELETE) spec.resources[0].name "my-resource": must start with lowercase letter and contain only letters, numbers, underscores (no hyphens) spec.preconditions[0].capture[0]: must have either 'field' or 'expression' set</details> </blockquote></details> <details> <summary>internal/config_loader/validator.go (1)</summary><blockquote> `606-620`: **Fragile error filtering using substring matching.** The `validateResources` helper filters errors by checking if the message contains "resources" or "Resources". This approach is brittle and may incorrectly include/exclude errors as message formats evolve. Consider tracking error paths more explicitly rather than relying on substring matching, or document this as a temporary backward-compatibility shim that should be removed once callers migrate to the new API. </blockquote></details> <details> <summary>internal/config_loader/types.go (2)</summary><blockquote> `143-149`: **LGTM!** Good extraction of common fields into a shared base type, reducing duplication between `Precondition` and `PostAction`. Minor: Consider adding `validate:"omitempty"` to `Log` field for consistency with `APICall`, though it's not strictly required for a pointer field. --- `160-169`: **LGTM!** Appropriate validation for `Method` (restricted to valid HTTP verbs) and `URL` (required). Consider adding format validation for `URL` (e.g., `validate:"required,url"`) to catch malformed URLs early, though this may be intentionally flexible to allow templated URLs. </blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used**: Organization UI **Review profile**: CHILL **Plan**: Pro <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 2acf251f6d62a3dcc6582452be5fb53a713c25a5 and c02962c68a1df52b85803bbea1ef3b27d4d1e3f5. </details> <details> <summary>⛔ Files ignored due to path filters (1)</summary> * `go.sum` is excluded by `!**/*.sum` </details> <details> <summary>📒 Files selected for processing (21)</summary> * `configs/adapter-config-template.yaml` * `go.mod` * `internal/config_loader/README.md` * `internal/config_loader/loader.go` * `internal/config_loader/loader_test.go` * `internal/config_loader/struct_validator.go` * `internal/config_loader/types.go` * `internal/config_loader/validator.go` * `internal/config_loader/validator_schema.go` * `internal/config_loader/validator_test.go` * `internal/criteria/README.md` * `internal/executor/README.md` * `internal/executor/executor_test.go` * `internal/executor/param_extractor.go` * `internal/executor/param_extractor_test.go` * `internal/executor/post_action_executor_test.go` * `internal/executor/precondition_executor.go` * `test/integration/config-loader/testdata/adapter_config_valid.yaml` * `test/integration/executor/executor_integration_test.go` * `test/integration/executor/executor_k8s_integration_test.go` * `test/testdata/adapter_config_valid.yaml` </details> <details> <summary>💤 Files with no reviewable changes (3)</summary> * test/integration/config-loader/testdata/adapter_config_valid.yaml * test/testdata/adapter_config_valid.yaml * internal/config_loader/validator_schema.go </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>🧠 Learnings (2)</summary> <details> <summary>📓 Common learnings</summary>Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those withenv.*source,Required=true, and no default) occurs at config load time ininternal/config_loader/validator_schema.go. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.</details> <details> <summary>📚 Learning: 2025-12-11T02:06:33.975Z</summary>Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those withenv.*source,Required=true, and no default) occurs at config load time ininternal/config_loader/validator_schema.go. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.**Applied to files:** - `internal/config_loader/struct_validator.go` - `internal/executor/param_extractor.go` - `internal/config_loader/validator.go` - `internal/config_loader/README.md` - `internal/config_loader/validator_test.go` - `internal/config_loader/loader.go` - `internal/config_loader/types.go` </details> </details><details> <summary>🧬 Code graph analysis (8)</summary> <details> <summary>internal/executor/precondition_executor.go (2)</summary><blockquote> <details> <summary>internal/criteria/types.go (2)</summary> * `Operator` (10-10) * `OperatorExists` (28-28) </details> <details> <summary>internal/config_loader/constants.go (1)</summary> * `FieldValue` (72-72) </details> </blockquote></details> <details> <summary>internal/executor/param_extractor.go (1)</summary><blockquote> <details> <summary>internal/executor/types.go (2)</summary> * `NewExecutorError` (374-381) * `PhaseParamExtraction` (21-21) </details> </blockquote></details> <details> <summary>test/integration/executor/executor_k8s_integration_test.go (1)</summary><blockquote> <details> <summary>internal/config_loader/types.go (4)</summary> * `ActionBase` (145-149) * `APICall` (161-169) * `CaptureField` (182-185) * `FieldExpressionDef` (13-18) </details> </blockquote></details> <details> <summary>internal/executor/post_action_executor_test.go (1)</summary><blockquote> <details> <summary>internal/config_loader/types.go (2)</summary> * `ActionBase` (145-149) * `LogAction` (261-264) </details> </blockquote></details> <details> <summary>internal/config_loader/validator.go (5)</summary><blockquote> <details> <summary>internal/config_loader/types.go (2)</summary> * `AdapterConfig` (69-74) * `ValidationErrors` (286-288) </details> <details> <summary>internal/config_loader/struct_validator.go (1)</summary> * `ValidateStruct` (62-82) </details> <details> <summary>internal/config_loader/loader.go (1)</summary> * `SupportedAPIVersions` (26-28) </details> <details> <summary>internal/config_loader/constants.go (13)</summary> * `FieldSpec` (9-9) * `FieldParams` (18-18) * `FieldResources` (20-20) * `FieldPost` (21-21) * `FieldPayloads` (41-41) * `FieldBuildRef` (43-43) * `FieldManifest` (78-78) * `FieldRef` (86-86) * `FieldRefs` (87-87) * `FieldPreconditions` (19-19) * `FieldConditions` (50-50) * `FieldCapture` (49-49) * `FieldExpression` (51-51) </details> <details> <summary>internal/criteria/types.go (2)</summary> * `Operator` (10-10) * `OperatorExists` (28-28) </details> </blockquote></details> <details> <summary>test/integration/executor/executor_integration_test.go (1)</summary><blockquote> <details> <summary>internal/config_loader/types.go (5)</summary> * `ActionBase` (145-149) * `APICall` (161-169) * `CaptureField` (182-185) * `FieldExpressionDef` (13-18) * `LogAction` (261-264) </details> </blockquote></details> <details> <summary>internal/config_loader/loader.go (3)</summary><blockquote> <details> <summary>internal/config_loader/validator.go (2)</summary> * `NewValidator` (34-40) * `ValidateAdapterVersion` (572-584) </details> <details> <summary>internal/config_loader/types.go (1)</summary> * `AdapterConfig` (69-74) </details> <details> <summary>internal/config_loader/constants.go (8)</summary> * `FieldSpec` (9-9) * `FieldResources` (20-20) * `FieldManifest` (78-78) * `FieldRef` (86-86) * `FieldRefs` (87-87) * `FieldPost` (21-21) * `FieldPayloads` (41-41) * `FieldBuildRef` (43-43) </details> </blockquote></details> <details> <summary>internal/executor/executor_test.go (2)</summary><blockquote> <details> <summary>internal/config_loader/types.go (3)</summary> * `ActionBase` (145-149) * `LogAction` (261-264) * `Precondition` (153-158) </details> <details> <summary>internal/executor/types.go (1)</summary> * `StatusSuccess` (35-35) </details> </blockquote></details> </details><details> <summary>🪛 LanguageTool</summary> <details> <summary>internal/executor/README.md</summary> [uncategorized] ~161-~161: If this is a compound adjective that modifies the following noun, use a hyphen. Context: ...oats truncated | | `float`, `float64` | Floating point value | Strings parsed | | `bool` | Boo... (EN_COMPOUND_ADJECTIVE_INTERNAL) </details> </details> <details> <summary>🪛 markdownlint-cli2 (0.18.1)</summary> <details> <summary>internal/config_loader/README.md</summary> 119-119: Fenced code blocks should have a language specified (MD040, fenced-code-language) </details> </details> </details> <details> <summary>🔇 Additional comments (40)</summary><blockquote> <details> <summary>go.mod (2)</summary><blockquote> `55-55`: **Validator v10.30.1 is not listed in official releases—verify this version exists.** The specified validator/v10 v10.30.1 does not appear in the official release history; the latest release is v10.28.0 (Oct 5, 2025). Confirm whether v10.30.1 is a pre-release, development version, or version string error, and consider updating to the latest stable v10.28.0 unless v10.30.1 is intentionally pinned for a specific reason. The golang.org/x package versions (crypto v0.46.0, net v0.47.0, term v0.38.0) appear current and align with or exceed the 2025 security fixes (CVE-2025-22869, CVE-2025-22870, CVE-2025-22872, CVE-2025-47911, CVE-2025-58190). Also applies to: 62-64, 78-78 --- `129-129`: **Versions are stable and mutually compatible.** The golang.org/x library updates are routine maintenance versions with no documented breaking changes. Notably, golang.org/x/net v0.47.0 explicitly requires golang.org/x/sys v0.39.0 in its go.mod, confirming compatibility. These minor version bumps contain security fixes and maintenance updates with no intentional API-breaking changes. </blockquote></details> <details> <summary>configs/adapter-config-template.yaml (1)</summary><blockquote> `76-118`: **LGTM! Clear documentation of parameter type support.** The documentation additions clearly explain the supported parameter types (string, int, float, bool) and provide helpful examples. The commented-out examples for `nodeCount` and `enableFeature` demonstrate practical usage patterns. </blockquote></details> <details> <summary>internal/executor/README.md (1)</summary><blockquote> `155-165`: **LGTM! Clear and comprehensive parameter type documentation.** The new section clearly documents supported parameter types and their conversion behavior. The table format is easy to read and the note about unspecified types is helpful. </blockquote></details> <details> <summary>internal/criteria/README.md (2)</summary><blockquote> `181-203`: **LGTM! Clear documentation of the new GetField method.** The documentation thoroughly explains the new `GetField` method's behavior, return values, and error conditions. The table format for error conditions is particularly helpful. --- `45-45`: All `NewEvaluator` call sites across the codebase have been properly updated to include the `context.Context` parameter as the first argument. Verified 40+ call sites in test files and production code—no outdated signatures remain. </blockquote></details> <details> <summary>internal/executor/post_action_executor_test.go (1)</summary><blockquote> `328-369`: **LGTM! Consistent ActionBase refactoring applied.** The test cases have been correctly updated to use the new `ActionBase` wrapper structure. The nested `ActionBase{Name: ..., Log: ...}` pattern is consistently applied across all test cases and matches the type definition. </blockquote></details> <details> <summary>internal/executor/precondition_executor.go (1)</summary><blockquote> `186-200`: **LGTM! Improved logging for exists operator.** The conditional logging based on operator type improves log clarity. For the `exists` operator, logging the field value (when matched) or "nil or empty" (when failed) is more semantically correct than showing an "expected value", since `exists` checks presence rather than equality. </blockquote></details> <details> <summary>internal/config_loader/loader_test.go (1)</summary><blockquote> `341-341`: **LGTM! Test assertions updated for new validation messages.** The shortened error message expectations using `assert.Contains` are more robust than exact string matches. The substring matching will continue to work even if the full error message format changes slightly. </blockquote></details> <details> <summary>internal/executor/executor_test.go (2)</summary><blockquote> `453-497`: **LGTM! Consistent ActionBase refactoring in test cases.** All test cases have been correctly updated to use the `ActionBase` wrapper structure. The pattern `ActionBase{Name: "..."}` with `Expression` at the `Precondition` level is consistently applied throughout the test file. --- `660-662`: **LGTM! PostAction ActionBase usage is correct.** The `PostAction` test cases correctly nest `Log` under `ActionBase`, matching the type definition and the pattern used throughout the codebase. </blockquote></details> <details> <summary>internal/config_loader/struct_validator.go (4)</summary><blockquote> `24-27`: **LGTM! Well-designed resource name pattern for CEL compatibility.** The regex pattern correctly enforces CEL-compatible resource names by requiring a lowercase letter start and excluding hyphens (which would conflict with CEL's minus operator). The comment clearly explains the rationale. --- `50-58`: **LGTM! Clean custom validation implementations.** Both custom validation functions are simple, correct, and delegate to appropriate validation logic (regex pattern and criteria package). They follow the validator function signature correctly. --- `60-82`: **LGTM! Robust ValidateStruct implementation.** The function correctly handles validation errors with proper type assertions and fallback handling. The use of `formatFullErrorMessage` ensures consistent error formatting across the validation system. --- `84-155`: **LGTM! Comprehensive error formatting with clear messages.** The error formatting functions provide user-friendly, consistent error messages. The `formatFieldPath` function correctly handles embedded structs by removing uppercase type names from the path (e.g., `ActionBase` is removed from the path). The complexity in `formatFieldPath` is justified by the need to handle embedded structs properly for clean error messages. </blockquote></details> <details> <summary>internal/executor/param_extractor_test.go (1)</summary><blockquote> `1-203`: **Well-structured test coverage for type conversion utilities.** The table-driven tests comprehensively cover conversion paths with both success and error cases. Good use of `assert.InDelta` for float comparisons at line 154 to handle floating-point precision. </blockquote></details> <details> <summary>test/integration/executor/executor_k8s_integration_test.go (2)</summary><blockquote> `180-199`: **Precondition and CaptureField structures correctly updated to new API shape.** The test configuration properly uses the new `ActionBase` wrapper for preconditions and the `FieldExpressionDef` embedding for capture fields, aligning with the type definitions in `internal/config_loader/types.go`. --- `283-296`: **PostAction structure correctly updated with ActionBase wrapper.** The PostAction now properly nests the `APICall` within `ActionBase`, consistent with the refactored type structure. </blockquote></details> <details> <summary>internal/config_loader/README.md (1)</summary><blockquote> `1-232`: **Comprehensive documentation for the refactored validation architecture.** The README clearly documents the two-phase validation approach, struct embedding patterns, and validation tag usage. The package structure table and usage examples are helpful. </blockquote></details> <details> <summary>internal/config_loader/loader.go (2)</summary><blockquote> `239-266`: **Good path traversal prevention in resolvePath.** The security check correctly uses `filepath.Rel` and checks for `..` prefix to prevent escaping the base directory. This protects against malicious file references in configurations. --- `128-163`: **Well-structured validation pipeline with clear phase separation.** The pipeline correctly orders validation phases: structural first (fail-fast), then adapter version, file references, and finally semantic validation. The optional `skipSemanticValidation` flag is useful for performance-sensitive contexts. </blockquote></details> <details> <summary>internal/config_loader/validator.go (2)</summary><blockquote> `117-129`: **Environment variable validation at config load time aligns with design intent.** This fail-fast validation for required environment parameters (those with `env.*` source, `Required=true`, and no default) ensures clear error messages before deployment. Based on learnings, this is intentional design. --- `230-251`: **Condition value validation handles operator-specific requirements correctly.** The validation properly enforces that `exists` operator should not have a value set, while `in`/`notIn` require array values. Good separation between structural validation (operator enum) and semantic validation (value requirements). </blockquote></details> <details> <summary>internal/config_loader/validator_test.go (2)</summary><blockquote> `97-109`: **Good addition of tests for `exists` operator value validation.** These new tests verify that the `exists` operator correctly rejects both single values and list values, ensuring the semantic validation catches invalid configurations. --- `557-603`: **Capture field validation tests properly updated for FieldExpressionDef.** Tests correctly use the new `FieldExpressionDef` structure and validate both valid cases (field-only, expression-only) and invalid cases (both set, neither set, missing name). </blockquote></details> <details> <summary>test/integration/executor/executor_integration_test.go (3)</summary><blockquote> `429-447`: **CEL expression evaluation test correctly uses new type structure.** The precondition configuration properly uses `ActionBase` wrapper and `FieldExpressionDef` for capture fields. The CEL expression `clusterPhase == "Ready" && nodeCount >= 3` provides good coverage for CEL-based precondition evaluation. --- `865-927`: **Log action test configuration properly structured.** The test creates a comprehensive configuration with multiple log actions at different levels (info, debug, warning) in both preconditions and post-actions. The `ActionBase` wrapper correctly nests `Log` actions. --- `1-1378`: **Comprehensive integration test coverage for executor functionality.** The test file covers: - Full success flow with preconditions, resources, and post-actions - Precondition not met scenarios - API failures at various phases - CEL expression evaluation - Log actions - Context cancellation - Missing/invalid event handling - Payload build failures Good test isolation and proper cleanup patterns. </blockquote></details> <details> <summary>internal/executor/param_extractor.go (1)</summary><blockquote> `322-329`: The comparison `v != 0` in multi-type cases works correctly. Go's comparison rules successfully handle `interface{}` compared to an untyped `0` for all numeric types (int, int8, int16, int32, int64, uint, uint8, float32, float64). The code does not have a type conversion bug and functions as intended. > Likely an incorrect or invalid review comment. </blockquote></details> <details> <summary>internal/config_loader/types.go (11)</summary><blockquote> `10-18`: **LGTM!** Clean implementation of mutual exclusion using `required_without` and `excluded_with` validation tags. The documentation clearly explains the intent. --- `35-38`: **LGTM!** Good use of composition by embedding `FieldExpressionDef` inline. This ensures consistent validation behavior across all types that need field/expression extraction. --- `68-81`: **LGTM!** Appropriate validation constraints for the top-level config structure. The `eq=AdapterConfig` check ensures proper resource kind validation. --- `83-92`: **LGTM!** Correct use of `validate:"dive"` for slice fields to ensure each element is validated. The `omitempty` on the optional `Post` pointer is appropriate. --- `112-121`: **LGTM!** The validation constraints align with the expected behavior where `Name` and `Source` are required. The `omitempty` YAML tag for serialization doesn't conflict with the `required` validation tag. --- `130-141`: **LGTM!** Consistent mutual exclusion pattern for `Build` and `BuildRef`. The documentation clearly explains the constraint. --- `177-185`: **LGTM!** Clean use of embedded `FieldExpressionDef` ensures consistent validation behavior with other types that need field/expression extraction. --- `249-264`: **LGTM!** Appropriate validation for `PostConfig` using `dive` for slice fields. `PostAction` cleanly reuses `ActionBase` through embedding. --- `275-327`: **LGTM!** Clean validation error handling utilities. The `Extend` method's nil check is good defensive programming. Minor observation: `First()` returns only the message without the path. If callers need the full context, they should access `ve.Errors[0]` directly or consider returning the full `ValidationError`. --- `227-235`: > Likely an incorrect or invalid review comment. --- `187-192`: The custom validator `validoperator` is already properly registered in `internal/config_loader/struct_validator.go` (line 36) as part of the singleton validator initialization using `sync.Once`. The corresponding validator function `validateOperator()` exists and delegates to `criteria.IsValidOperator()`. No action is required. </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
c02962c to
e6b1886
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
internal/config_loader/types.go (1)
237-247: DiscoveryConfig validation enforces ByName or BySelectors requirement.The
required_withouttags correctly enforce that at least one ofByNameorBySelectorsmust be provided. As confirmed in past review discussion, this validation works correctly despite theomitemptytag.
🧹 Nitpick comments (4)
internal/config_loader/loader_test.go (1)
341-341: Consider more specific error message assertions.The error message assertion changed from checking the full message to just "must specify". While this is more flexible, it may miss regressions where the error message becomes less helpful. Consider asserting on a more specific substring like "must specify apiCall" or "expression" to ensure the error message remains informative.
Same applies to lines 1187 and 1208.
internal/config_loader/struct_validator.go (2)
62-78: Consider handling RegisterValidation errors.While the custom validations are unlikely to fail registration, explicitly handling or logging errors from
RegisterValidationwould make debugging easier if issues arise during initialization.🔎 Potential improvement
structValidatorOnce.Do(func() { structValidator = validator.New() // Register custom validations - _ = structValidator.RegisterValidation("resourcename", validateResourceName) - _ = structValidator.RegisterValidation("validoperator", validateOperator) + if err := structValidator.RegisterValidation("resourcename", validateResourceName); err != nil { + panic(fmt.Sprintf("failed to register resourcename validator: %v", err)) + } + if err := structValidator.RegisterValidation("validoperator", validateOperator); err != nil { + panic(fmt.Sprintf("failed to register validoperator validator: %v", err)) + } // Use yaml tag names for field names in errors structValidator.RegisterTagNameFunc(extractYamlTagName)
181-202: Verify embedded struct name removal logic.The
formatFieldPathfunction removes embedded struct names (uppercase parts without indices) to clean up error paths. This works for the currentActionBaseembedding pattern, but ensure it handles all current and future embedded structs correctly.Consider adding a unit test that verifies paths like:
AdapterConfig.Spec.Preconditions[0].ActionBase.Name→spec.preconditions[0].nameAdapterConfig.Spec.Resources[0].Discovery.BySelectors.LabelSelector→ appropriate outputinternal/config_loader/validator.go (1)
606-619: String-based error filtering in validateResources is fragile.The error filtering on lines 612-614 uses
strings.Containsto detect resource-related errors, which could miss errors with different wording or falsely match unrelated errors containing "resources".🔎 Consider returning structured errors or using error types
func validateResources(config *AdapterConfig) error { v := NewValidator(config, "") // Run struct validation for resources first if errs := ValidateStruct(config); errs != nil && errs.HasErrors() { - // Filter for resource-related errors - for _, e := range errs.Errors { - if strings.Contains(e.Message, "resources") || strings.Contains(e.Message, "Resources") { - return fmt.Errorf("%s", e.Message) - } - } + // Return first resource-related error by path prefix + for _, e := range errs.Errors { + if strings.HasPrefix(e.Path, "spec.resources") { + return fmt.Errorf("%s: %s", e.Path, e.Message) + } + } } // Then check for duplicate resource names return v.validateDuplicateResourceNames() }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (21)
configs/adapter-config-template.yamlgo.modinternal/config_loader/README.mdinternal/config_loader/loader.gointernal/config_loader/loader_test.gointernal/config_loader/struct_validator.gointernal/config_loader/types.gointernal/config_loader/validator.gointernal/config_loader/validator_schema.gointernal/config_loader/validator_test.gointernal/criteria/README.mdinternal/executor/README.mdinternal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/param_extractor_test.gointernal/executor/post_action_executor_test.gointernal/executor/precondition_executor.gotest/integration/config-loader/testdata/adapter_config_valid.yamltest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/testdata/adapter_config_valid.yaml
💤 Files with no reviewable changes (3)
- test/testdata/adapter_config_valid.yaml
- internal/config_loader/validator_schema.go
- test/integration/config-loader/testdata/adapter_config_valid.yaml
✅ Files skipped from review due to trivial changes (1)
- configs/adapter-config-template.yaml
🚧 Files skipped from review as they are similar to previous changes (3)
- go.mod
- test/integration/executor/executor_k8s_integration_test.go
- internal/executor/param_extractor_test.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
internal/executor/param_extractor.gointernal/config_loader/README.mdinternal/config_loader/loader.gointernal/config_loader/struct_validator.gointernal/config_loader/validator_test.gointernal/config_loader/types.gointernal/config_loader/validator.go
🧬 Code graph analysis (8)
internal/executor/param_extractor.go (1)
internal/executor/types.go (2)
NewExecutorError(374-381)PhaseParamExtraction(21-21)
internal/executor/precondition_executor.go (2)
internal/criteria/types.go (2)
Operator(10-10)OperatorExists(28-28)internal/config_loader/constants.go (1)
FieldValue(72-72)
internal/config_loader/loader.go (3)
internal/config_loader/validator.go (2)
NewValidator(34-40)ValidateAdapterVersion(572-584)internal/config_loader/types.go (1)
AdapterConfig(69-74)internal/config_loader/constants.go (8)
FieldSpec(9-9)FieldResources(20-20)FieldManifest(78-78)FieldRef(86-86)FieldRefs(87-87)FieldPost(21-21)FieldPayloads(41-41)FieldBuildRef(43-43)
internal/executor/post_action_executor_test.go (1)
internal/config_loader/types.go (2)
ActionBase(145-149)LogAction(261-264)
internal/config_loader/struct_validator.go (2)
internal/config_loader/types.go (2)
AdapterConfig(69-74)ValidationErrors(286-288)internal/criteria/types.go (2)
IsValidOperator(44-51)OperatorStrings(54-60)
internal/executor/executor_test.go (2)
internal/config_loader/types.go (3)
ActionBase(145-149)LogAction(261-264)Precondition(153-158)internal/executor/types.go (1)
StatusSuccess(35-35)
test/integration/executor/executor_integration_test.go (1)
internal/config_loader/types.go (5)
ActionBase(145-149)APICall(161-169)CaptureField(182-185)FieldExpressionDef(13-18)LogAction(261-264)
internal/config_loader/types.go (2)
internal/criteria/types.go (1)
Operator(10-10)internal/k8s_client/discovery.go (2)
Discovery(14-29)DiscoveryConfig(32-42)
🪛 LanguageTool
internal/executor/README.md
[uncategorized] ~161-~161: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...oats truncated | | float, float64 | Floating point value | Strings parsed | | bool | Boo...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
🪛 markdownlint-cli2 (0.18.1)
internal/config_loader/README.md
119-119: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (28)
internal/executor/precondition_executor.go (1)
188-199: LGTM! Improved logging for exists operator.The logging changes appropriately handle the
existsoperator which doesn't have an expected value. For matched conditions, it now logs only the field value, and for failed conditions, it provides a clearer "field is nil or empty" message instead of confusing comparisons.internal/executor/post_action_executor_test.go (1)
330-364: LGTM! Tests updated for ActionBase embedding.The test data consistently reflects the new structure where
PostActionembedsActionBase. The changes are mechanical and maintain test coverage.internal/executor/README.md (1)
144-165: LGTM! Clear parameter type documentation.The new "Supported Parameter Types" section provides clear guidance on type conversion behavior. The table is well-structured and the note about retaining original types is helpful.
Minor: Consider "floating-point value" instead of "Floating point value" for consistency (though this is a nitpick).
internal/executor/param_extractor.go (2)
32-56: LGTM! Clean defaulting and type conversion flow.The defaulting logic correctly handles nil and empty string cases, and the type conversion is appropriately gated on non-nil values with proper error handling for required vs. non-required parameters.
Note: The duplicate defaulting logic mentioned in past reviews appears to have been resolved in this refactor.
165-330: Type conversion utilities look solid.The conversion functions handle a comprehensive set of type cases with proper error messages. Key strengths:
- uint64 overflow check (lines 209-211) prevents silent truncation
- Bool conversion handles common truthy/falsy strings beyond strconv.ParseBool
- Consistent error messages reference the input value and type
internal/executor/executor_test.go (1)
453-497: LGTM! Tests consistently updated for ActionBase embedding.All precondition test literals now use the
ActionBasewrapper, maintaining test coverage while reflecting the new type structure. The changes are mechanical and consistent.internal/config_loader/struct_validator.go (1)
26-29: Good: Resource name pattern enforces CEL compatibility.The regex
^[a-z][a-zA-Z0-9_]*$correctly prevents hyphens which would conflict with CEL's minus operator. The pattern is well-commented.internal/config_loader/README.md (2)
78-124: Excellent validation documentation!The two-phase validation explanation with detailed examples and error message formats is very helpful for users. The custom validators table and validation tag examples are clear and comprehensive.
Minor: Line 119 has a fenced code block without a language specifier (static analysis hint). Consider adding the language for proper rendering.
141-173: Clear documentation of new patterns.The struct embedding section and
ValidationErrorsusage examples provide excellent guidance for understanding the refactored architecture. The code examples are practical and easy to follow.internal/config_loader/loader.go (3)
129-163: Well-structured validation pipeline with clear phase separation.The refactored validation pipeline cleanly separates concerns: structural validation (fail-fast), adapter version validation, file reference validation, and semantic validation. This modular approach improves maintainability and allows selective validation.
170-200: File reference loading handles single vs multiple refs correctly.The logic correctly differentiates between single
ref(backward compatible, populatesresource.Manifest) and multiplerefs(populatesresource.ManifestItems). The error messages include appropriate path context for debugging.
239-266: Path containment check doesn't account for symlinks.The
resolvePathfunction validates that the logical path stays within the base directory usingfilepath.Rel, but this check operates on path strings without resolving symlinks. A symlink within the base directory could resolve to a location outside it, allowingos.Statto access files beyond the intended boundary.If symlink-following is a security concern in your deployment, consider using
filepath.EvalSymlinksto resolve the target path before the containment check:// Resolve symlinks after cleaning targetPath, err := filepath.EvalSymlinks(targetPath) if err != nil { return "", fmt.Errorf("path %q cannot be resolved: %w", refPath, err) } // Then check if the resolved path is within base directory rel, err := filepath.Rel(baseClean, targetPath)However, this approach will fail on broken symlinks. If your use case requires handling broken symlinks gracefully, consider using
os.Lstatinstead ofos.Statin the calling code to avoid following symlinks entirely.internal/config_loader/validator_test.go (3)
97-109: Good addition of edge case tests for theexistsoperator.These tests verify that the
existsoperator correctly rejects configurations where a value is provided, ensuring proper validation of operator semantics.
477-490: Updated test assertions for ValidateStruct return type.The test correctly handles the new
*ValidationErrorsreturn type fromValidateStruct, checking for nil before accessingHasErrors().
606-648: New tests verify yaml field name mapping and cache population.These tests ensure the field name cache is correctly populated during validator initialization, which is essential for accurate error path reporting in validation messages.
internal/criteria/README.md (2)
45-57: Documentation updated for two-value NewEvaluator return.The example correctly shows the updated
NewEvaluatorsignature returning(evaluator, error). Note that the example ignores the error with_- in production code, this should be handled.
181-203: Clear documentation of GetField error semantics.The table clearly distinguishes between parse errors (returned as second value), field-not-found (nil Value, no error), and runtime extraction failures (result.Error). This distinction is important for callers to handle appropriately.
test/integration/executor/executor_integration_test.go (3)
429-447: Integration test correctly uses ActionBase wrapper for preconditions.The test properly constructs
Preconditionwith the newActionBasewrapper containingNameandAPICall, andCaptureFieldentries usingFieldExpressionDeffor field extraction.
865-927: LogAction integration tests demonstrate new ActionBase structure.The tests correctly construct log-only preconditions and post-actions using
ActionBase.Log, validating that log actions work independently of API calls.
1110-1127: Precondition with CEL expression and captures correctly structured.The test properly combines
ActionBase(withAPICall),Capture(withFieldExpressionDef), andConditionsin a single precondition, demonstrating the flexible validation model.internal/config_loader/validator.go (4)
42-65: Structural validation with fail-fast behavior is well-designed.The two-phase approach (struct tag validation followed by custom validators) provides clear separation. Returning on first error is appropriate for structural issues that indicate fundamental configuration problems.
116-129: Environment variable validation at load time is intentional design.Based on learnings, this fail-fast validation ensures environment variables are set before deployment, providing clear error messages early. This is the correct approach for required
env.*parameters.
230-251: Improved exists operator validation rejects values correctly.The updated logic correctly ensures that the
existsoperator doesn't accept values, matching the semantic that it only checks for field presence. This addresses the edge case where users might incorrectly provide a value.
410-444: CEL environment initialization handles dynamic variables well.The logic correctly deduplicates root variables and adds fallback declarations for
resourcesandadapterif not already defined. The capacity estimation at line 411 is a minor optimization detail.internal/config_loader/types.go (4)
10-18: FieldExpressionDef provides clean mutual exclusivity pattern.The inline embedding pattern with
required_withoutandexcluded_withtags enforces that exactly one ofFieldorExpressionmust be set. This is reused effectively inValueDefandCaptureField.
270-327: ValidationErrors provides comprehensive error aggregation utilities.The
ValidationErrorstype withAdd,Extend,First,Count, andHasErrorsmethods provides a clean API for collecting and reporting multiple validation errors. The formattedError()output is user-friendly.
255-258: PostAction simplified to embed ActionBase.The refactored
PostActionnow only embedsActionBase, eliminating duplication withPreconditionwhile maintaining the same capabilities (Name, APICall, Log).
143-158: Nested field references in validation tags are correctly supported.The go-playground/validator library supports nested field references through embedded structs using dotted notation (e.g.,
ActionBase.APICall). Therequired_without_allvalidator correctly resolves these references. Integration tests in the codebase (executor_k8s_integration_test.go, config_criteria_integration_test.go) validate Precondition structs with these validation rules, and they pass successfully.Likely an incorrect or invalid review comment.
e6b1886 to
c3051bc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@internal/config_loader/README.md`:
- Around line 117-124: Update the fenced code block that shows example
validation errors in internal/config_loader/README.md to include a language
specifier (e.g., "text") for proper rendering; locate the block containing the
four validation lines starting with "spec.params[0].name is required" and change
the opening fence from ``` to ```text so the errors render with the correct
formatting.
In `@internal/executor/param_extractor.go`:
- Around line 221-222: The uint conversion branch in the function handling
numeric type extraction (the switch case handling "case uint") lacks an overflow
check and can silently wrap on 64-bit platforms; modify the case for uint in the
same function (the conversion logic that returns int64) to check if v >
uint(math.MaxInt64) and return an overflow error (matching the existing uint64
branch behavior), otherwise cast to int64 and return the value.
♻️ Duplicate comments (1)
internal/config_loader/struct_validator.go (1)
204-204: Extra blank line.There's an extra blank line at the end of the file.
🧹 Nitpick comments (6)
internal/executor/README.md (1)
155-164: Consider clarifying type equivalence and addressing the grammar suggestion.The type conversion documentation is helpful, but could benefit from minor improvements:
Type equivalence: The table lists
int, int64andfloat, float64together, but it's unclear if they're equivalent or have different behaviors. The example comment "Convert to int64" when usingtype: "int"suggests they're treated the same. Consider clarifying: "Bothintandint64result in int64 values; bothfloatandfloat64result in float64 values."Grammar (static analysis): "Floating point value" should be "Floating-point value" (compound adjective).
Optional: Consider briefly mentioning error handling behavior (e.g., "Invalid conversions result in validation errors at config load time").
📝 Suggested documentation improvements
#### Supported Parameter Types | Type | Description | Conversion Notes | |------|-------------|-----------------| | `string` | String value (default) | Any value converted to string | -| `int`, `int64` | Integer value | Strings parsed, floats truncated | -| `float`, `float64` | Floating point value | Strings parsed | +| `int`, `int64` | Integer value (both result in int64) | Strings parsed, floats truncated | +| `float`, `float64` | Floating-point value (both result in float64) | Strings parsed | | `bool` | Boolean value | Supports: `true/false`, `yes/no`, `on/off`, `1/0` | -If `type` is not specified, the value retains its original type from the source. +If `type` is not specified, the value retains its original type from the source. Invalid type conversions result in validation errors at config load time.internal/config_loader/struct_validator.go (2)
68-69: Consider handling RegisterValidation errors.Silently ignoring errors from
RegisterValidationcould hide issues if custom validators fail to register (e.g., duplicate tag names, invalid validator functions). Consider at minimum logging these errors during initialization.Proposed fix
- _ = structValidator.RegisterValidation("resourcename", validateResourceName) - _ = structValidator.RegisterValidation("validoperator", validateOperator) + if err := structValidator.RegisterValidation("resourcename", validateResourceName); err != nil { + panic(fmt.Sprintf("failed to register resourcename validator: %v", err)) + } + if err := structValidator.RegisterValidation("validoperator", validateOperator); err != nil { + panic(fmt.Sprintf("failed to register validoperator validator: %v", err)) + }
181-202: Embedded struct name filtering is effective but fragile.The logic to skip embedded struct names (uppercase, no index brackets) works for current patterns like
ActionBase, but could incorrectly filter out legitimate field names in edge cases. Consider documenting this assumption or using a more explicit approach.internal/config_loader/loader.go (1)
169-203: Consider adding size limits for loaded YAML files.The
loadYAMLFilefunction reads entire files into memory without size constraints. For defense-in-depth, consider adding a maximum file size check to prevent potential resource exhaustion if a referenced file is unexpectedly large.💡 Optional: Add file size limit
func loadYAMLFile(baseDir, refPath string) (map[string]interface{}, error) { fullPath, err := resolvePath(baseDir, refPath) if err != nil { return nil, err } + // Check file size to prevent resource exhaustion + info, err := os.Stat(fullPath) + if err != nil { + return nil, fmt.Errorf("failed to stat file %q: %w", fullPath, err) + } + const maxFileSize = 10 * 1024 * 1024 // 10 MB + if info.Size() > maxFileSize { + return nil, fmt.Errorf("file %q exceeds maximum size of %d bytes", fullPath, maxFileSize) + } + data, err := os.ReadFile(fullPath)internal/config_loader/validator.go (1)
596-609: Backward compatibility helper has fragile string matching.The
validateResourcesfunction filters errors by checking if the message contains "resources" or "Resources". This string-based filtering is fragile and could miss relevant errors or include unrelated ones.💡 Consider using error path instead of message content
func validateResources(config *AdapterConfig) error { v := NewValidator(config, "") // Run struct validation for resources first if errs := ValidateStruct(config); errs != nil && errs.HasErrors() { // Filter for resource-related errors for _, e := range errs.Errors { - if strings.Contains(e.Message, "resources") || strings.Contains(e.Message, "Resources") { + if strings.Contains(e.Path, "resources") || strings.Contains(e.Path, "Resources") { return fmt.Errorf("%s", e.Message) } } } // Then check for duplicate resource names return v.validateDuplicateResourceNames() }internal/config_loader/types.go (1)
143-155: Potential inconsistency: Manual Validate() vs struct tags.The
Payload.Validate()method duplicates the mutual exclusivity logic already expressed in the struct validation tags on Lines 135 and 138. This could lead to inconsistent error messages.Consider removing the manual
Validate()method since the struct tags (required_without,excluded_with) already enforce this constraint, or ensure the method is not called when struct validation is used.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (20)
configs/adapter-config-template.yamlgo.modinternal/config_loader/README.mdinternal/config_loader/loader.gointernal/config_loader/loader_test.gointernal/config_loader/struct_validator.gointernal/config_loader/types.gointernal/config_loader/validator.gointernal/config_loader/validator_schema.gointernal/config_loader/validator_test.gointernal/criteria/README.mdinternal/executor/README.mdinternal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/param_extractor_test.gointernal/executor/post_action_executor_test.gotest/integration/config-loader/testdata/adapter_config_valid.yamltest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/testdata/adapter_config_valid.yaml
💤 Files with no reviewable changes (3)
- test/integration/config-loader/testdata/adapter_config_valid.yaml
- test/testdata/adapter_config_valid.yaml
- internal/config_loader/validator_schema.go
✅ Files skipped from review due to trivial changes (1)
- configs/adapter-config-template.yaml
🚧 Files skipped from review as they are similar to previous changes (4)
- internal/config_loader/loader_test.go
- test/integration/executor/executor_k8s_integration_test.go
- test/integration/executor/executor_integration_test.go
- internal/executor/param_extractor_test.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
go.modinternal/config_loader/validator.gointernal/executor/param_extractor.gointernal/config_loader/README.mdinternal/config_loader/struct_validator.gointernal/config_loader/validator_test.gointernal/config_loader/loader.gointernal/config_loader/types.go
🧬 Code graph analysis (7)
internal/executor/post_action_executor_test.go (1)
internal/config_loader/types.go (2)
ActionBase(159-163)LogAction(273-276)
internal/executor/executor_test.go (2)
internal/config_loader/types.go (3)
ActionBase(159-163)LogAction(273-276)Precondition(167-172)internal/executor/types.go (1)
StatusSuccess(35-35)
internal/executor/param_extractor.go (1)
internal/executor/types.go (2)
NewExecutorError(375-382)PhaseParamExtraction(21-21)
internal/config_loader/struct_validator.go (2)
internal/config_loader/types.go (2)
AdapterConfig(69-74)ValidationErrors(298-300)internal/criteria/types.go (2)
IsValidOperator(44-51)OperatorStrings(54-60)
internal/config_loader/validator_test.go (2)
internal/config_loader/types.go (7)
ActionBase(159-163)Condition(202-206)APICall(175-183)CaptureField(196-199)FieldExpressionDef(13-18)Precondition(167-172)Payload(130-141)internal/config_loader/struct_validator.go (1)
ValidateStruct(92-112)
internal/config_loader/loader.go (3)
internal/config_loader/validator.go (2)
NewValidator(34-40)ValidateAdapterVersion(562-574)internal/config_loader/types.go (1)
AdapterConfig(69-74)internal/config_loader/constants.go (7)
FieldSpec(9-9)FieldResources(20-20)FieldManifest(78-78)FieldRef(85-85)FieldPost(21-21)FieldPayloads(41-41)FieldBuildRef(43-43)
internal/config_loader/types.go (3)
internal/criteria/types.go (1)
Operator(10-10)internal/k8s_client/discovery.go (2)
Discovery(14-29)DiscoveryConfig(32-42)pkg/errors/error.go (1)
Errors(77-95)
🪛 LanguageTool
internal/executor/README.md
[uncategorized] ~161-~161: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...oats truncated | | float, float64 | Floating point value | Strings parsed | | bool | Boo...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
🪛 markdownlint-cli2 (0.18.1)
internal/config_loader/README.md
119-119: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (34)
internal/executor/README.md (1)
144-150: LGTM! Clear examples of type conversion.The parameter examples effectively demonstrate the new type conversion feature with practical use cases.
internal/executor/param_extractor.go (7)
6-8: LGTM!The new imports are appropriate for the type conversion functionality -
mathfor overflow bounds checking andstrconvfor string parsing.
32-39: LGTM!The defaulting logic correctly handles both
nilvalues and empty strings, applying the default when appropriate.
41-56: LGTM!The type conversion integration is well-structured with appropriate error handling that distinguishes between required and non-required parameters.
165-181: LGTM!The type router function is clean, provides good error messages, and sensibly maps both
int/int64andfloat/float64to consistent implementations.
183-201: LGTM!The string conversion handles all numeric types appropriately, using
strconv.FormatFloatfor floats to preserve precision and providing a sensible%vfallback for unknown types.
253-294: LGTM!The float64 conversion handles all numeric types correctly. The inherent precision loss for large integers (beyond 2^53) is a standard limitation of float64 representation.
319-322: Critical bug: Multi-type switch cases break zero comparison.When a type switch case lists multiple types (
int, int8, int16, int32, int64), the variablevretains typeinterface{}. The comparisonv != 0compares an interface value againstint(0), which only matches when the underlying type is exactlyint. For other integer types likeint8(0), the comparison returnstrue(types differ) instead offalse.Example:
int8(0)will incorrectly convert totruebecauseinterface{int8}(0) != int(0)evaluates totruedue to type mismatch.🐛 Proposed fix - separate cases for each integer type
- case int, int8, int16, int32, int64: - return v != 0, nil - case uint, uint8, uint16, uint32, uint64: - return v != 0, nil + case int: + return v != 0, nil + case int8: + return v != 0, nil + case int16: + return v != 0, nil + case int32: + return v != 0, nil + case int64: + return v != 0, nil + case uint: + return v != 0, nil + case uint8: + return v != 0, nil + case uint16: + return v != 0, nil + case uint32: + return v != 0, nil + case uint64: + return v != 0, nilAlternatively, use reflection or convert to a common type:
- case int, int8, int16, int32, int64: - return v != 0, nil - case uint, uint8, uint16, uint32, uint64: - return v != 0, nil + case int: + return v != 0, nil + case int8: + return v != 0, nil + case int16: + return v != 0, nil + case int32: + return v != 0, nil + case int64: + return v != 0, nil + case uint: + return v != 0, nil + case uint8: + return v != 0, nil + case uint16: + return v != 0, nil + case uint32: + return v != 0, nil + case uint64: + return v != 0, nilLikely an incorrect or invalid review comment.
go.mod (2)
62-84: Indirect dependencies look appropriate.The added indirect dependencies (
mimetype,locales,universal-translator,go-urn) are standard transitive dependencies forgo-playground/validator/v10. Thegolang.org/x/*updates are minor version bumps.
8-8: No action required; validator version is current.Version
v10.30.1is the latest release (December 24, 2025) and is valid.internal/criteria/README.md (2)
45-45: Documentation correctly updated for new API signature.The
NewEvaluatorexamples properly reflect the new signature withcontext.Background()as the first parameter and the two-value return pattern(evaluator, _).
181-203: Clear and comprehensive GetField documentation.The error condition table effectively documents the distinction between parse errors (2nd return), runtime extraction errors (
result.Error), and field-not-found cases. This clarity will help developers handle edge cases correctly.internal/executor/post_action_executor_test.go (2)
328-347: Tests correctly updated for ActionBase wrapper pattern.The test cases properly construct
PostActionwith the embeddedActionBasestruct, correctly placingNameandLogfields withinActionBase. The pattern is consistent across all test cases.
362-369: Test with payloads correctly structured.The "with payloads" test case properly uses the
ActionBasewrapper while also testingPayloadsat thePostConfiglevel.internal/config_loader/struct_validator.go (2)
42-60: Recursive field cache building handles edge cases well.The
buildFieldNameCachefunction properly handles pointers, slices, arrays, maps, and structs recursively with cycle detection via thevisitedmap.
92-112: ValidateStruct implementation is clean.The function correctly uses the singleton validator, handles both
validator.ValidationErrorsand generic errors, and returnsnilfor valid structs. The error aggregation intoValidationErrorsaligns with the broader validation architecture.internal/config_loader/README.md (2)
78-107: Excellent two-phase validation documentation.The documentation clearly explains the structural vs. semantic validation phases, provides practical examples of validation tags, and documents mutual exclusivity patterns. This will help users understand how to properly configure their adapters.
141-173: Struct embedding and ValidationErrors documentation is comprehensive.The documentation for
ActionBase,FieldExpressionDef, andValidationErrorsAPI is clear and includes practical code examples.internal/config_loader/loader.go (2)
129-163: LGTM! Well-structured validation pipeline.The four-phase validation approach (structural → adapter version → file references → semantic) is clean and follows fail-fast principles appropriately. The conditional file reference validation when
baseDiris set is a good design choice.
225-252: Path traversal protection has a potential bypass for absolute paths.When
refPathis absolute (Line 235-236), the code cleans it but doesn't verify it's within the base directory before the relative path check. An absolute path like/etc/passwdwould passfilepath.Relsuccessfully if it doesn't start with..relative to baseDir.However, the subsequent check on Line 247-248 correctly catches this since an absolute path outside baseDir will produce a relative path starting with
... The logic is sound.internal/executor/executor_test.go (2)
453-456: LGTM! Test literals correctly updated for ActionBase wrapper.The precondition test cases are properly updated to use the new
ActionBaseembedded struct syntax. The test coverage for sequential execution behavior remains intact.
656-658: LGTM! PostAction test literals correctly use nested LogAction.The
LogActionis now correctly nested insideActionBase.LogwithinPostAction, matching the new type structure defined intypes.go.internal/config_loader/validator_test.go (4)
26-35: LGTM! Test helper correctly uses ActionBase wrapper.The
withConditionhelper function properly constructs preconditions with the newActionBase{Name: ...}syntax.
493-526: LGTM! Comprehensive coverage for CaptureField validation.The test cases properly cover:
- Valid field-only captures
- Valid expression-only captures
- Invalid both field and expression set
- Invalid neither field nor expression set
- Missing capture name
The updated assertions match the new error messages from struct validation tags.
528-570: Good addition: Tests for YAML field name resolution.These new tests verify that the
yamlFieldNamefunction correctly maps Go field names to their YAML equivalents, and that the field name cache is properly populated during validator initialization.
554-569: The flakiness concern is unfounded. The code usessync.Onceto guarantee thread-safe, single initialization offieldNameCacheviagetStructValidator(), even with parallel test execution. After initialization, the cache is read-only, and the field mappings are deterministic (derived from the staticAdapterConfigstruct).The actual coupling concern—that tests access a private unexported variable—is a code design issue, not a flakiness risk.
Likely an incorrect or invalid review comment.
internal/config_loader/validator.go (4)
22-40: LGTM! Clean Validator struct design.The
Validatorstruct encapsulates all validation state cleanly, including config, baseDir, error collection, defined variables, and CEL environment. The constructor properly initializes the error collector.
116-129: Environment variable validation at config load time aligns with design intent.This fail-fast validation for required environment variables is intentional per the project's design - environment variables must be set before deployment. Based on learnings, this is the expected behavior.
228-234: Good enhancement: Validation thatexistsoperator should not have a value.The new validation correctly enforces that the
existsoperator checks for field presence only, and should not have a value or values set. This prevents configuration mistakes.
405-438: CEL environment initialization handles variable roots correctly.The logic properly extracts root variable names from dotted paths and avoids duplicate declarations. The fallback additions for
resourcesandadaptervariables ensure CEL expressions can reference these standard contexts.internal/config_loader/types.go (4)
10-18: LGTM! Clean FieldExpressionDef type for DRY field/expression handling.The mutual exclusivity is well-enforced via
required_withoutandexcluded_withvalidation tags. This type is reused appropriately acrossValueDefandCaptureField.
287-339: LGTM! Well-designed ValidationErrors type.The
ValidationErrorstype provides useful methods:
Addfor collecting errors with pathsExtendfor merging error collectionsFirstfor fail-fast scenariosHasErrorsfor conditional checks- Clear error formatting with path context
242-258: DiscoveryConfig validation for BySelectors has been discussed.Per past review comments, the
omitemptyonBySelectorsvalidation tag was tested and works correctly - therequired_withoutcheck still enforces that eitherByNameorBySelectorsmust be set. The current implementation is correct.
157-172: Validation tags are correctly implemented.The dotted notation
ActionBase.APICallis the correct and supported syntax for referencing fields in an embedded struct within go-playground/validator v10. The validator expects exported Go field names joined with dots to reference nested/embedded fields, and this pattern works correctly withrequired_without_allvalidation tags.Likely an incorrect or invalid review comment.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
|
|
||
| Validation errors are descriptive: | ||
| ``` | ||
| spec.params[0].name is required | ||
| spec.preconditions[1].apiCall.method must be one of: GET, POST, PUT, PATCH, DELETE | ||
| spec.preconditions[1].apiCall.method "INVALID" is invalid (allowed: GET, POST, PUT, PATCH, DELETE) | ||
| spec.resources[0].name "my-resource": must start with lowercase letter and contain only letters, numbers, underscores (no hyphens) | ||
| spec.preconditions[0].capture[0]: must have either 'field' or 'expression' set | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add language specifier to code block.
The fenced code block for error message examples should have a language specifier for proper rendering.
Proposed fix
Validation errors are descriptive:
-```
+```text
spec.params[0].name is required
spec.preconditions[1].apiCall.method "INVALID" is invalid (allowed: GET, POST, PUT, PATCH, DELETE)
spec.resources[0].name "my-resource": must start with lowercase letter and contain only letters, numbers, underscores (no hyphens)
spec.preconditions[0].capture[0]: must have either 'field' or 'expression' set</details>
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.18.1)</summary>
119-119: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
In @internal/config_loader/README.md around lines 117 - 124, Update the fenced
code block that shows example validation errors in
internal/config_loader/README.md to include a language specifier (e.g., "text")
for proper rendering; locate the block containing the four validation lines
starting with "spec.params[0].name is required" and change the opening fence
from totext so the errors render with the correct formatting.
</details>
<!-- fingerprinting:phantom:poseidon:ocelot -->
<!-- This is an auto-generated comment by CodeRabbit -->
c3051bc to
d352d3d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@internal/executor/param_extractor.go`:
- Around line 319-326: The switch in internal/executor/param_extractor.go is
comparing interface values to an int literal which fails for non-int numeric
types; update the multi-type cases (the block handling int, int8, int16, int32,
int64; uint variants; float32; float64) to use separate case arms or explicit
type assertions so each branch binds a typed variable (e.g., for case int8: v :=
v.(int8)) and compare to a zero of that exact type (e.g., v != int8(0)); ensure
the same for uint/float branches so the comparisons check the concrete typed
value rather than comparing interface types.
♻️ Duplicate comments (3)
internal/executor/param_extractor.go (1)
221-222: Missing overflow check foruinton 64-bit platforms.On 64-bit systems,
uintis 64-bit and can hold values exceedingmath.MaxInt64. Theuint64case correctly checks for overflow (lines 209-211), but this case does not, leading to silent overflow when converting largeuintvalues.🔧 Proposed fix - add overflow check for uint
case uint: + if uint64(v) > math.MaxInt64 { + return 0, fmt.Errorf("uint value %d overflows int64", v) + } return int64(v), nilinternal/config_loader/README.md (1)
118-124: Add a language specifier to the fenced error block.This is already flagged previously (MD040); keeping consistent formatting helps rendering.
internal/config_loader/types.go (1)
165-172: Embedded-field references in validation tags may not resolve.
required_without_all=ActionBase.APICallmight be ignored by go-playground/validator because embedded fields are typically referenced by promoted name (APICall). If so, the “at least one of APICall/Expression/Conditions” constraint can be weakened. Consider switching toAPICallin the tag.🔧 Suggested adjustment
- Conditions []Condition `yaml:"conditions,omitempty" validate:"dive,required_without_all=ActionBase.APICall Expression"` - Expression string `yaml:"expression,omitempty" validate:"required_without_all=ActionBase.APICall Conditions"` + Conditions []Condition `yaml:"conditions,omitempty" validate:"dive,required_without_all=APICall Expression"` + Expression string `yaml:"expression,omitempty" validate:"required_without_all=APICall Conditions"`Does go-playground/validator v10 allow validation tag references to embedded fields using "ActionBase.APICall", or should embedded fields be referenced by the promoted name "APICall"?
🧹 Nitpick comments (2)
internal/config_loader/struct_validator.go (1)
69-70: Consider handlingRegisterValidationerrors.The errors from
RegisterValidationare silently ignored. While these calls are unlikely to fail in practice (valid function, unique name), logging or returning an error would help diagnose issues if the validator setup ever fails unexpectedly.Suggested improvement
- _ = structValidator.RegisterValidation("resourcename", validateResourceName) - _ = structValidator.RegisterValidation("validoperator", validateOperator) + if err := structValidator.RegisterValidation("resourcename", validateResourceName); err != nil { + panic(fmt.Sprintf("failed to register resourcename validation: %v", err)) + } + if err := structValidator.RegisterValidation("validoperator", validateOperator); err != nil { + panic(fmt.Sprintf("failed to register validoperator validation: %v", err)) + }internal/config_loader/loader.go (1)
225-251: Consider symlink-aware baseDir confinement if this is a security boundary.
resolvePathblocks..traversal, but a symlink insidebaseDircould still point outside. If untrusted configs are a concern, consider resolving symlinks before theRelcheck or documenting the trust model.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (21)
configs/adapter-config-template.yamlgo.modinternal/config_loader/README.mdinternal/config_loader/loader.gointernal/config_loader/loader_test.gointernal/config_loader/struct_validator.gointernal/config_loader/types.gointernal/config_loader/validator.gointernal/config_loader/validator_schema.gointernal/config_loader/validator_test.gointernal/criteria/README.mdinternal/executor/README.mdinternal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/param_extractor_test.gointernal/executor/post_action_executor_test.gopkg/logger/with_error_field_test.gotest/integration/config-loader/testdata/adapter_config_valid.yamltest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/testdata/adapter_config_valid.yaml
💤 Files with no reviewable changes (3)
- test/integration/config-loader/testdata/adapter_config_valid.yaml
- test/testdata/adapter_config_valid.yaml
- internal/config_loader/validator_schema.go
✅ Files skipped from review due to trivial changes (1)
- pkg/logger/with_error_field_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
- internal/executor/param_extractor_test.go
- internal/executor/post_action_executor_test.go
- internal/executor/executor_test.go
- configs/adapter-config-template.yaml
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
internal/config_loader/struct_validator.gogo.modinternal/config_loader/loader.gointernal/config_loader/loader_test.gointernal/config_loader/README.mdinternal/config_loader/validator.gointernal/config_loader/types.gointernal/config_loader/validator_test.gointernal/executor/param_extractor.go
🧬 Code graph analysis (7)
internal/config_loader/loader.go (3)
internal/config_loader/validator.go (2)
NewValidator(34-40)ValidateAdapterVersion(525-537)internal/config_loader/types.go (1)
AdapterConfig(69-74)internal/config_loader/constants.go (7)
FieldSpec(9-9)FieldResources(20-20)FieldManifest(78-78)FieldRef(85-85)FieldPost(21-21)FieldPayloads(41-41)FieldBuildRef(43-43)
test/integration/executor/executor_k8s_integration_test.go (1)
internal/config_loader/types.go (4)
ActionBase(159-163)APICall(175-183)CaptureField(196-199)FieldExpressionDef(13-18)
internal/config_loader/validator.go (5)
internal/config_loader/types.go (2)
AdapterConfig(69-74)ValidationErrors(298-300)internal/config_loader/struct_validator.go (1)
ValidateStruct(115-135)internal/config_loader/loader.go (1)
SupportedAPIVersions(26-28)internal/config_loader/constants.go (10)
FieldSpec(9-9)FieldPost(21-21)FieldPayloads(41-41)FieldBuildRef(43-43)FieldResources(20-20)FieldManifest(78-78)FieldRef(85-85)FieldPreconditions(19-19)FieldCapture(49-49)FieldExpression(51-51)internal/criteria/types.go (2)
Operator(10-10)OperatorExists(28-28)
test/integration/executor/executor_integration_test.go (1)
internal/config_loader/types.go (5)
ActionBase(159-163)APICall(175-183)CaptureField(196-199)FieldExpressionDef(13-18)LogAction(273-276)
internal/config_loader/types.go (2)
internal/criteria/types.go (1)
Operator(10-10)internal/k8s_client/discovery.go (2)
Discovery(14-29)DiscoveryConfig(32-42)
internal/config_loader/validator_test.go (2)
internal/config_loader/types.go (7)
ActionBase(159-163)Condition(202-206)APICall(175-183)CaptureField(196-199)FieldExpressionDef(13-18)Precondition(167-172)Payload(130-141)internal/config_loader/struct_validator.go (1)
ValidateStruct(115-135)
internal/executor/param_extractor.go (1)
internal/executor/types.go (2)
NewExecutorError(375-382)PhaseParamExtraction(21-21)
🪛 LanguageTool
internal/executor/README.md
[uncategorized] ~161-~161: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...oats truncated | | float, float64 | Floating point value | Strings parsed | | bool | Boo...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
🪛 markdownlint-cli2 (0.18.1)
internal/config_loader/README.md
119-119: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (29)
internal/executor/param_extractor.go (6)
1-13: LGTM!The new
mathandstrconvimports are appropriate for the type conversion functionality being added.
32-56: LGTM!The defaulting logic correctly handles both
niland empty string cases. The type conversion integration follows the same error-handling pattern as extraction failures—required parameters return errors while non-required parameters fall back to defaults. This is consistent and well-structured.
165-181: LGTM!The
convertParamTypedispatcher is clean and clearly documents supported types in the error message. The supported type set (string, int/int64, float/float64, bool) covers common configuration parameter needs.
183-201: LGTM!String conversion handles all numeric types correctly. Using
strconv.FormatFloatpreserves precision, and the%vfallback for unknown types is a reasonable safety net.
253-294: LGTM!Float conversion handles all numeric types correctly. The potential precision loss for very large
int64/uint64values (>2^53) converting tofloat64is inherent to IEEE 754 and acceptable for typical configuration parameter use cases.
301-318: LGTM!The string-to-bool conversion provides good coverage:
strconv.ParseBoolhandles standard representations (true/false,1/0,t/f), and the fallback handles common alternatives (yes/no,y/n,on/off). The empty string returningfalseis a sensible default.go.mod (2)
8-8: v10.30.1 is the current stable version and has no known security vulnerabilities.This is the latest release (Dec 24, 2025). While the validator library may depend on golang.org/x/crypto, your PR already includes v0.46.0, which exceeds the v0.31.0 threshold required to mitigate CVE-2024-45337.
136-142: No security concerns identified. The versions specified forgolang.org/x/crypto,golang.org/x/net,golang.org/x/sys, andgolang.org/x/termare current and do not contain known vulnerabilities. These appear to be routine transitive updates pulled in bygo mod tidy.test/integration/executor/executor_integration_test.go (7)
427-443: LGTM!The
ActionBasewrapper pattern andFieldExpressionDefembedding are correctly applied. The CEL expression properly references the captured fields defined in theCaptureslice.
864-899: LGTM!The test properly covers three precondition patterns:
- Log-only action (diagnostic logging)
- Log before API call
- Full API call with capture and conditions
All patterns correctly use the
ActionBasewrapper with appropriate optional fields.
901-926: LGTM!Post-actions correctly use
ActionBasewrapper for log-only actions, testing both info and warning log levels.
1109-1125: LGTM!The precondition correctly uses the
ActionBasewrapper andFieldExpressionDefembedding patterns. The intentional failure setup (viamockAPI.SetFailPrecondition(true)) properly tests theadapter.executionErrorCEL access.
1159-1171: LGTM!Post-action correctly uses
ActionBasewrapper. The test effectively validates that CEL expressions can accessadapter.executionErrorfields in payload building.
1299-1311: LGTM!Post-action correctly uses
ActionBasewrapper. The test properly validates that payload build failures block subsequent post-action execution (verified by assertion on line 1348).
1278-1284: The precondition pattern without APICall/Capture is valid.This precondition correctly evaluates conditions against parameters. The
clusterIdparameter is extracted from event data during the parameter extraction phase and made available to the condition evaluator viaGetCELVariables(). Conditions are designed to evaluate against parameters, captured fields, and other CEL variables—not exclusively from API responses. No changes needed.internal/executor/README.md (1)
144-164: Documentation updates look good.The new parameter examples and "Supported Parameter Types" section clearly document the type conversion capabilities. This aligns well with the broader parameter extraction enhancements in this PR.
Minor nit from static analysis: Consider hyphenating "Floating point" to "Floating-point" on line 161 for grammatical correctness (compound adjective modifying "value").
test/integration/executor/executor_k8s_integration_test.go (2)
180-199: Test updates correctly reflect new type structure.The precondition construction properly uses the new
ActionBasewrapper forNameandAPICall, andCaptureFieldwith embeddedFieldExpressionDef. This aligns with the type definitions ininternal/config_loader/types.go.
283-295: PostAction construction updated correctly.The
PostActionnow properly wrapsNameandAPICallwithinActionBase, consistent with the refactored type structure.internal/criteria/README.md (2)
45-57: API documentation updated for newNewEvaluatorsignature.The example correctly shows the updated signature with
context.Background()as the first parameter. The error handling pattern is clear.
181-203: Well-documentedGetFieldmethod and error handling semantics.The table clearly distinguishes between parse errors (returned as second value) vs runtime extraction errors (in
result.Error), and the "field not found" case returningnilvalues. This is helpful for understanding the API contract.internal/config_loader/struct_validator.go (3)
94-111: Environment variable validation at config load time is correct.This aligns with the intentional design for fail-fast behavior - environment variables must be set before deployment. Based on learnings, this validation occurs at config load time to ensure clear error messages when required env vars are missing.
137-186: Comprehensive error message formatting.The
formatFullErrorMessagefunction handles various validation tags with clear, user-friendly messages. The handling of embedded struct prefixes (e.g.,ActionBase.APICall→apiCall) inrequired_without_allis particularly well thought out.
215-251: Clean handling of embedded struct names in error paths.The
embeddedStructNamesmap correctly removes internal Go struct names (ActionBase,FieldExpressionDef) from error paths, ensuring YAML-friendly paths are shown to users.internal/config_loader/loader_test.go (3)
341-342: Error message expectation updated for new validation format.The expected error message now matches the new
required_without_allformatting fromstruct_validator.go. This correctly reflects the two-phase validation architecture.
1052-1063: Good use of helper function for test config construction.The
configWithResourceshelper reduces boilerplate and makes the test cases more readable by focusing on the resources being tested rather than full config scaffolding.
1193-1204: Test assertions properly updated for new validation API.The tests now correctly use
ValidateStruct(config)and checkerrs.HasErrors()for error presence, with specific error message assertions maintained. This maintains test quality while adapting to the new validation entry points.internal/config_loader/loader.go (1)
128-203: Clear, staged validation flow with explicit file-reference loading.The phased pipeline and the dedicated load step make the execution order and error context easy to follow.
internal/config_loader/validator_test.go (1)
528-569: Nice coverage for YAML field-name mapping and cache population.These tests help lock down error-path stability after the refactor.
internal/config_loader/validator.go (1)
68-90: The requiredenv.*parameter validation already exists and is functioning correctly. ThevalidateParameterEnvRequired()function instruct_validator.go(lines 94-111) validates that required parameters sourced fromenv.*have their environment variables set at load time. This validation is registered as a struct-level validator and is invoked during theValidateStructure()phase, which is the first step in the validation pipeline called fromloader.go. The validation properly checks forRequired=truecombined withSourcestarting withenv., usesos.Getenv()to verify the variable exists, and reports an error if the environment variable is not set and no default is provided. No action is needed.Likely an incorrect or invalid review comment.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
d352d3d to
bd2624c
Compare
bd2624c to
70ce5c7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/executor/param_extractor.go (1)
20-55: Convert defaults through the same type coercion path.Defaults applied after extraction/conversion failures bypass
convertParamType, so params can remain the wrong type (e.g., default"3"stays string even whentype: int). Consider funnelling defaults through the conversion logic for consistency.♻️ Proposed fix
- if err != nil { - if param.Required { - return NewExecutorError(PhaseParamExtraction, param.Name, - fmt.Sprintf("failed to extract required parameter '%s' from source '%s'", param.Name, param.Source), err) - } - // Use default for non-required params if extraction fails - if param.Default != nil { - execCtx.Params[param.Name] = param.Default - } - continue - } + if err != nil { + if param.Required { + return NewExecutorError(PhaseParamExtraction, param.Name, + fmt.Sprintf("failed to extract required parameter '%s' from source '%s'", param.Name, param.Source), err) + } + // Use default for non-required params if extraction fails + value = param.Default + if value == nil { + continue + } + } @@ - if convErr != nil { + if convErr != nil { if param.Required { return NewExecutorError(PhaseParamExtraction, param.Name, fmt.Sprintf("failed to convert parameter '%s' to type '%s'", param.Name, param.Type), convErr) } - // Use default for non-required params if conversion fails - if param.Default != nil { - execCtx.Params[param.Name] = param.Default - } - continue + // Use default for non-required params if conversion fails + if param.Default == nil { + continue + } + value = param.Default + converted, convErr = convertParamType(value, param.Type) + if convErr != nil { + continue + } } value = converted
🤖 Fix all issues with AI agents
In `@internal/config_loader/loader.go`:
- Around line 144-153: Parse() currently skips ValidateFileReferences() and
loadFileReferences() when cfg.baseDir is empty, silently ignoring file
references; update Parse() to detect when the validator reports any file
references exist (use validator.HasFileReferences() or call
ValidateFileReferences() in a non-fatal/inspection mode) and if file references
are present but cfg.baseDir == "" return an explicit error stating baseDir is
required for file references. Specifically, add a guard in the Parse() path
before skipping file handling that checks for file refs and returns a clear
error (mentioning Parse(), WithBaseDir, cfg.baseDir, ValidateFileReferences(),
loadFileReferences(), and Load()) so callers must set WithBaseDir or use Load()
to proceed.
In `@internal/config_loader/types.go`:
- Around line 168-172: The Conditions field's validator currently uses
"dive,required_without_all=ActionBase.APICall Expression" which runs element
validation before the field-level required_without_all check; change the tag so
the field-level constraint runs first (e.g., put required_without_all before
dive) on the Conditions field in the struct (the Conditions field that
references CaptureField and uses validate tags) so an empty slice triggers the
required_without_all validation before element-level diving.
In `@internal/config_loader/validator.go`:
- Around line 15-16: The templateVarRegex currently doesn't account for Go
template trim delimiters (`{{-` and `-}}`); update the regexp assigned to
templateVarRegex so it allows an optional hyphen immediately after the opening
braces and/or immediately before the closing braces while preserving capturing
of the variable path and optional pipe/filter segment (i.e., make the openings
`\{\{\-?\s*` and closings `\s*\-?\}\}` and keep the existing capture group
`([a-zA-Z_][a-zA-Z0-9_\.]*)` and optional pipe part intact).
♻️ Duplicate comments (2)
internal/executor/param_extractor.go (1)
322-329: Fix numericboolconversion for non-inttypes.In a multi-type type switch case,
visinterface{};v != 0compares different dynamic types and returnstruefor zero values ofint8,uint8, etc. Split the cases so each branch compares the concrete type.🐛 Proposed fix
- case int, int8, int16, int32, int64: - return v != 0, nil - case uint, uint8, uint16, uint32, uint64: - return v != 0, nil - case float32: - return v != 0, nil - case float64: - return v != 0, nil + case int: + return v != 0, nil + case int8: + return v != 0, nil + case int16: + return v != 0, nil + case int32: + return v != 0, nil + case int64: + return v != 0, nil + case uint: + return v != 0, nil + case uint8: + return v != 0, nil + case uint16: + return v != 0, nil + case uint32: + return v != 0, nil + case uint64: + return v != 0, nil + case float32: + return v != 0, nil + case float64: + return v != 0, nilinternal/config_loader/README.md (1)
118-124: Add a language specifier to the fenced error block.This keeps markdownlint happy and ensures consistent rendering.
Proposed fix
-``` +```text spec.params[0].name is required spec.preconditions[1].apiCall.method "INVALID" is invalid (allowed: GET, POST, PUT, PATCH, DELETE) spec.resources[0].name "my-resource": must start with lowercase letter and contain only letters, numbers, underscores (no hyphens) spec.preconditions[0].capture[0]: must have either 'field' or 'expression' set
🧹 Nitpick comments (2)
internal/config_loader/loader_test.go (1)
1053-1058: Prefer the canonical API version constant in test helpers.Using
APIVersionV1Alpha1here avoids future drift if API version validation becomes stricter.♻️ Proposed tweak
- APIVersion: "hyperfleet.openshift.io/v1alpha1", + APIVersion: APIVersionV1Alpha1,internal/config_loader/struct_validator.go (1)
42-59: Avoid field-name collisions infieldNameCache.The cache is keyed only by Go field name, so later entries can overwrite earlier ones when different structs reuse the same field name with different YAML tags, leading to misleading error messages. Consider keying by fully-qualified type + field (or storing per-type maps) and updating
yamlFieldNameaccordingly.Also applies to: 198-213
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (21)
configs/adapter-config-template.yamlgo.modinternal/config_loader/README.mdinternal/config_loader/loader.gointernal/config_loader/loader_test.gointernal/config_loader/struct_validator.gointernal/config_loader/types.gointernal/config_loader/validator.gointernal/config_loader/validator_schema.gointernal/config_loader/validator_test.gointernal/criteria/README.mdinternal/executor/README.mdinternal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/param_extractor_test.gointernal/executor/post_action_executor_test.gopkg/logger/with_error_field_test.gotest/integration/config-loader/testdata/adapter_config_valid.yamltest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/testdata/adapter_config_valid.yaml
💤 Files with no reviewable changes (3)
- test/testdata/adapter_config_valid.yaml
- test/integration/config-loader/testdata/adapter_config_valid.yaml
- internal/config_loader/validator_schema.go
✅ Files skipped from review due to trivial changes (1)
- internal/executor/param_extractor_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
- internal/executor/post_action_executor_test.go
- internal/criteria/README.md
- test/integration/executor/executor_k8s_integration_test.go
- go.mod
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
internal/executor/param_extractor.gointernal/config_loader/README.mdinternal/config_loader/struct_validator.gointernal/config_loader/validator_test.gointernal/config_loader/validator.gointernal/config_loader/types.gointernal/config_loader/loader.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
internal/config_loader/types.go
🧬 Code graph analysis (9)
internal/executor/param_extractor.go (1)
internal/executor/types.go (2)
NewExecutorError(375-382)PhaseParamExtraction(21-21)
internal/config_loader/struct_validator.go (2)
internal/config_loader/types.go (3)
Parameter(114-121)AdapterConfig(69-74)ValidationErrors(298-300)internal/criteria/types.go (2)
IsValidOperator(44-51)OperatorStrings(54-60)
internal/config_loader/validator_test.go (2)
internal/config_loader/types.go (7)
ActionBase(159-163)Condition(202-206)APICall(175-183)CaptureField(196-199)FieldExpressionDef(13-18)Precondition(167-172)Payload(130-141)internal/config_loader/struct_validator.go (1)
ValidateStruct(115-135)
internal/config_loader/validator.go (4)
internal/config_loader/types.go (2)
AdapterConfig(69-74)ValidationErrors(298-300)internal/config_loader/struct_validator.go (1)
ValidateStruct(115-135)internal/config_loader/loader.go (1)
SupportedAPIVersions(26-28)internal/config_loader/constants.go (11)
FieldSpec(9-9)FieldPost(21-21)FieldPayloads(41-41)FieldBuildRef(43-43)FieldResources(20-20)FieldManifest(78-78)FieldRef(85-85)FieldPreconditions(19-19)FieldConditions(50-50)FieldCapture(49-49)FieldExpression(51-51)
internal/executor/executor_test.go (2)
internal/config_loader/types.go (3)
ActionBase(159-163)LogAction(273-276)Precondition(167-172)internal/executor/types.go (1)
StatusSuccess(35-35)
test/integration/executor/executor_integration_test.go (1)
internal/config_loader/types.go (5)
ActionBase(159-163)APICall(175-183)CaptureField(196-199)FieldExpressionDef(13-18)LogAction(273-276)
internal/config_loader/loader_test.go (3)
internal/config_loader/types.go (7)
Resource(242-247)AdapterConfig(69-74)Metadata(77-81)AdapterConfigSpec(84-92)AdapterInfo(95-97)DiscoveryConfig(250-254)SelectorConfig(257-259)internal/k8s_client/discovery.go (2)
Discovery(14-29)DiscoveryConfig(32-42)internal/config_loader/struct_validator.go (1)
ValidateStruct(115-135)
internal/config_loader/types.go (2)
internal/criteria/types.go (1)
Operator(10-10)internal/k8s_client/discovery.go (2)
Discovery(14-29)DiscoveryConfig(32-42)
internal/config_loader/loader.go (3)
internal/config_loader/validator.go (2)
NewValidator(34-40)ValidateAdapterVersion(525-537)internal/config_loader/types.go (1)
AdapterConfig(69-74)internal/config_loader/constants.go (7)
FieldSpec(9-9)FieldResources(20-20)FieldManifest(78-78)FieldRef(85-85)FieldPost(21-21)FieldPayloads(41-41)FieldBuildRef(43-43)
🪛 LanguageTool
internal/executor/README.md
[uncategorized] ~161-~161: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...oats truncated | | float, float64 | Floating point value | Strings parsed | | bool | Boo...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
🔇 Additional comments (17)
pkg/logger/with_error_field_test.go (1)
86-91: Formatting-only change looks good.No behavioral impact noticed.
configs/adapter-config-template.yaml (1)
76-117: Docs update is clear and consistent with the new typing behavior.Thanks for adding supported type guidance and examples.
internal/executor/README.md (1)
144-164: Nice documentation update for typed params.The examples and type table align well with the new conversion helpers.
internal/executor/executor_test.go (1)
453-491: ActionBase-wrapped test fixtures look consistent.The updated literals align with the embedded ActionBase shape for preconditions/post-actions and skip-reason coverage.
Also applies to: 656-658, 727-739
internal/config_loader/validator_test.go (2)
31-33: Test updates align with ActionBase and FieldExpressionDef refactor.The fixture updates and structural-validation expectations look consistent with the new embedded shapes.
Also applies to: 40-46, 52-62, 97-109, 127-142, 170-175, 193-193, 321-323, 484-525
387-409: Nice coverage for payload validation errors and YAML name caching.The added assertions and cache tests strengthen behavior and error-message fidelity.
Also applies to: 450-457, 475-476, 528-569
internal/config_loader/validator.go (4)
22-92: Validator orchestration is clear and cohesive.
The structural → file-reference → semantic split and fail-fast vs aggregation choices read well.
112-167: File-reference validation is robust.
Resolved-path checks and aggregated error formatting look solid.
181-239: Semantic validation coverage is comprehensive.
Nice handling across condition values, capture expressions, template vars (incl. payload builds), CEL parsing, and K8s manifest checks.Also applies to: 245-335, 368-425, 465-508
514-556: Helper APIs are tidy and useful.test/integration/executor/executor_integration_test.go (2)
427-439: Test fixtures updated cleanly for ActionBase/FieldExpressionDef.Also applies to: 866-922, 1111-1169
1250-1310: No action required—the test will correctly detect the payload build failure.The config is created directly in the test, bypassing semantic validation entirely. At runtime,
renderTemplate()uses Go'shtml/templatewithmissingkey=error, which will catch the undefined variable{{ .nonExistentParam }}and fail during payload building, exactly as the test expects. The test assertions are correct: failure in thePhasePostActionsphase with zero post actions executed.internal/config_loader/types.go (5)
10-66: FieldExpressionDef/ValueDef refactor is clean.
Inline embedding keeps value-extraction definitions consistent and easy to parse.
68-155: Core config validation tags look well-scoped.
The tightened requirements for key adapter fields and payload exclusivity read well.
157-163: ActionBase consolidation + stricter APICall/operator validation look good.Also applies to: 173-199, 201-207
241-282: Resource/Discovery/Post config validation updates look good.
283-339: ValidationErrors utilities are clean and reusable.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| // 3. File reference validation and loading (only if baseDir is set) | ||
| if cfg.baseDir != "" { | ||
| if err := validateFileReferences(config, cfg.baseDir); err != nil { | ||
| if err := validator.ValidateFileReferences(); err != nil { | ||
| return fmt.Errorf("file reference validation failed: %w", err) | ||
| } | ||
|
|
||
| // Load file references (manifest.ref, buildRef) after validation passes | ||
| if err := loadFileReferences(config, cfg.baseDir); err != nil { | ||
| return fmt.Errorf("failed to load file references: %w", err) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
rg -n --type=go '\bconfig_loader\.Parse\s*\(' -A 3Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 65
🏁 Script executed:
# Also search for Parse calls within the same package (might be just Parse without qualifier)
rg -n --type=go -C 3 '\.Parse\s*\(' internal/config_loader/Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 548
🏁 Script executed:
# Check the actual implementation of Parse in loader.go
cat internal/config_loader/loader.goRepository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 7749
🏁 Script executed:
# Search for all Parse calls (not just config_loader.Parse)
rg -n 'Parse\(' --type=go -B 2 -A 2 | head -100Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 5744
🏁 Script executed:
# Specifically look for imports and uses of the loader package
rg -n 'config_loader' --type=go | head -50Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 5965
🏁 Script executed:
# Check if Parse is exported (capital P) vs internal
rg -n '^func Parse' internal/config_loader/Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 272
🏁 Script executed:
# Check the Parse() calls in loader_test.go to see if any test cases include file references
grep -A 50 'func TestParse' internal/config_loader/loader_test.go | head -80Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 1733
🏁 Script executed:
# Look at one of the test cases that calls Parse
sed -n '160,180p' internal/config_loader/loader_test.goRepository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 497
🏁 Script executed:
# Search for tests that might include buildRef or manifest.ref
rg -n 'buildRef|manifest\.ref|ManifestRef' internal/config_loader/loader_test.go -B 3 -A 3Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 4837
🏁 Script executed:
# Check if there are any Parse calls outside of tests
rg -n 'config_loader\.Parse\(' --type=goRepository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 65
🏁 Script executed:
# Look at the actual test to see if Parse calls with file refs include WithBaseDir
sed -n '750,950p' internal/config_loader/loader_test.goRepository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 4550
🏁 Script executed:
# Specifically look for Parse calls with file references in tests
rg -B 10 'buildRef|ManifestRef' internal/config_loader/loader_test.go | grep -A 10 'Parse('Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 65
🏁 Script executed:
# Check if Parse is documented or exported in godoc
rg -n 'Parse' internal/config_loader/loader.go | head -20Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 252
🏁 Script executed:
# Look at the complete Parse function and comments
sed -n '100,130p' internal/config_loader/loader.goRepository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 1062
🏁 Script executed:
# Check if there are any comments on Parse documenting its usage
sed -n '95,110p' internal/config_loader/loader.goRepository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 580
Consider failing fast when file references are present but baseDir is empty.
Parse() without WithBaseDir skips ValidateFileReferences() and loadFileReferences(). While current code correctly uses Load() (which auto-sets baseDir) for actual file loading, the API allows direct Parse() calls without baseDir where file refs would be silently skipped. Add a guard to fail explicitly when refs are detected but baseDir is empty:
Suggested fix
- // 3. File reference validation and loading (only if baseDir is set)
- if cfg.baseDir != "" {
+ // 3. File reference validation and loading
+ if cfg.baseDir != "" {
if err := validator.ValidateFileReferences(); err != nil {
return fmt.Errorf("file reference validation failed: %w", err)
}
if err := loadFileReferences(config, cfg.baseDir); err != nil {
return fmt.Errorf("failed to load file references: %w", err)
}
+ } else if hasFileReferences(config) {
+ return fmt.Errorf("file references require baseDir; pass WithBaseDir or use Load()")
}+// hasFileReferences reports whether config contains manifest.ref or buildRef entries.
+func hasFileReferences(config *AdapterConfig) bool {
+ for i := range config.Spec.Resources {
+ if config.Spec.Resources[i].GetManifestRef() != "" {
+ return true
+ }
+ }
+ if config.Spec.Post != nil {
+ for i := range config.Spec.Post.Payloads {
+ if config.Spec.Post.Payloads[i].BuildRef != "" {
+ return true
+ }
+ }
+ }
+ return false
+}🤖 Prompt for AI Agents
In `@internal/config_loader/loader.go` around lines 144 - 153, Parse() currently
skips ValidateFileReferences() and loadFileReferences() when cfg.baseDir is
empty, silently ignoring file references; update Parse() to detect when the
validator reports any file references exist (use validator.HasFileReferences()
or call ValidateFileReferences() in a non-fatal/inspection mode) and if file
references are present but cfg.baseDir == "" return an explicit error stating
baseDir is required for file references. Specifically, add a guard in the
Parse() path before skipping file handling that checks for file refs and returns
a clear error (mentioning Parse(), WithBaseDir, cfg.baseDir,
ValidateFileReferences(), loadFileReferences(), and Load()) so callers must set
WithBaseDir or use Load() to proceed.
| ActionBase `yaml:",inline"` | ||
| Capture []CaptureField `yaml:"capture,omitempty" validate:"dive"` | ||
| Conditions []Condition `yaml:"conditions,omitempty" validate:"dive,required_without_all=ActionBase.APICall Expression"` | ||
| Expression string `yaml:"expression,omitempty" validate:"required_without_all=ActionBase.APICall Conditions"` | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, let's look at the actual code at the specified location
cd internal/config_loader && sed -n '165,175p' types.goRepository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 657
🏁 Script executed:
# Let's see more context around these lines to understand the struct
cd internal/config_loader && sed -n '155,180p' types.goRepository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 1297
🏁 Script executed:
# Let's find where the validator package is defined and check its behavior
rg "required_without_all" --type go -A 2 -B 2Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 1192
🏁 Script executed:
# Check if there are any tests or examples showing validator tag ordering
fd -e go | xargs rg "validate:.*dive.*required" --type goRepository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 238
🏁 Script executed:
# Search for the validator package to understand version and behavior
rg "github.com/go-playground/validator" --type goRepository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 167
🏁 Script executed:
# Let's check the struct_validator.go to understand how required_without_all is implemented
cat -n internal/config_loader/struct_validator.go | head -150Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 6067
🏁 Script executed:
# Search for how the validation is actually executed
rg "Validate\|StructValidator" internal/config_loader/ -A 5 -B 2Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 65
🏁 Script executed:
# Check if there are any tests showing the expected validation behavior
fd -e go -path "*test*" | xargs rg "Precondition\|required_without_all" 2>/dev/null | head -20Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 251
🌐 Web query:
go-playground validator v10 dive tag behavior with required_without_all order
💡 Result:
Short answer: tag order matters. The validator parses tags left-to-right, so place the conditional/element logic before the rule you want to apply.
- To apply a rule to slice/array/map elements, put dive before the rule(s) you want run on each element (e.g. "dive,required"). [1]
- For conditional required variants, the position relative to omitempty matters — required (and required_* rules) must come before omitempty. [2]
- Combine both concerns by ordering tags so the conditional check or dive appears before the target validator (e.g. for elements: "dive,required_without_all=OtherField", or for optional fields: "required_without_all=A B,omitempty" as appropriate). [1][2]
Sources:
- go-playground/validator docs (dive + required/conditional required). [1]
- Stack Overflow answer noting required must come before omitempty. [2]
References:
[1] https://pkg.go.dev/github.com/go-playground/validator/v10
[2] https://stackoverflow.com/questions/75193648/need-to-validate-two-fields-in-go-playground-validator-v10
🏁 Script executed:
# Let's see more of struct_validator.go to understand how required_without_all is handled
sed -n '143,200p' internal/config_loader/struct_validator.goRepository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 2796
🏁 Script executed:
# Look for tests or validation examples that show how the validator handles these tags
find . -name "*.go" -type f | xargs rg "required_without_all" -B 5 -A 5Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 2406
🏁 Script executed:
# Check if there's any documentation or comments about tag ordering in the validator implementation
rg "dive" internal/config_loader/ -B 3 -A 3Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 2122
🏁 Script executed:
# Let's look for any tests or usage examples of Precondition to understand the expected behavior
find . -name "*.go" -type f | xargs rg "Precondition" -B 2 -A 2 | head -80Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 6339
🏁 Script executed:
# Check if there are YAML test files that show valid/invalid Precondition configs
find . -name "*.yaml" -o -name "*.yml" | xargs rg -l "precondition" 2>/dev/null | head -5Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 364
🏁 Script executed:
# Let's understand the semantics: is required_without_all meant for field-level or element-level validation?
# Check if there are similar patterns elsewhere in the code
rg "validate:.*required_without_all" -B 2 -A 2Repository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 619
🏁 Script executed:
# Let's check the go-playground/validator documentation or source understanding by looking at actual validator behavior
# Create a minimal test to understand how dive + required_without_all works
python3 << 'EOF'
# The question is: does "dive,required_without_all" apply the required_without_all check at the field level or element level?
# According to go-playground/validator docs:
# - dive: tells validator to recursively apply tags to each element in slice/array/map
# - required_without_all: checks if the field is required when all specified other fields are absent
# The semantic intent here is:
# "The Conditions field is required if both APICall and Expression are absent"
# This is a FIELD-LEVEL check, not an element-level check
# With "dive,required_without_all=...":
# 1. dive runs first, processing elements
# 2. required_without_all would try to run on each element (semantically wrong)
# 3. On an empty slice, dive has no elements to process, so required_without_all might not run at the field level
# With "required_without_all=...,dive":
# 1. required_without_all runs first at field level (correct)
# 2. dive runs on elements
# 3. Empty slice would still trigger the field-level check
print("Analysis confirms: the reviewer is identifying a real tag ordering bug")
print("Current: dive,required_without_all=... (wrong order for field-level constraint)")
print("Should be: required_without_all=...,dive (field-level check first, then element processing)")
EOFRepository: openshift-hyperfleet/hyperfleet-adapter
Length of output: 325
Reorder field-level constraint before element processing.
The required_without_all check enforces that Conditions is required if both APICall and Expression are absent—a field-level constraint. With dive,required_without_all=..., the validator processes elements first; on an empty Conditions slice, the field-level check never executes, allowing a Precondition with no APICall, Expression, or Conditions to pass validation.
🔧 Fix: apply field-level constraint before dive
- Conditions []Condition `yaml:"conditions,omitempty" validate:"dive,required_without_all=ActionBase.APICall Expression"`
+ Conditions []Condition `yaml:"conditions,omitempty" validate:"required_without_all=ActionBase.APICall Expression,dive"`🤖 Prompt for AI Agents
In `@internal/config_loader/types.go` around lines 168 - 172, The Conditions
field's validator currently uses "dive,required_without_all=ActionBase.APICall
Expression" which runs element validation before the field-level
required_without_all check; change the tag so the field-level constraint runs
first (e.g., put required_without_all before dive) on the Conditions field in
the struct (the Conditions field that references CaptureField and uses validate
tags) so an empty slice triggers the required_without_all validation before
element-level diving.
| // templateVarRegex matches Go template variables like {{ .varName }} or {{ .nested.var }} | ||
| var templateVarRegex = regexp.MustCompile(`\{\{\s*\.([a-zA-Z_][a-zA-Z0-9_\.]*)\s*(?:\|[^}]*)?\}\}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Template variable regex misses trim delimiters ({{- / -}}).
The current regex doesn't match Go's whitespace-trimming syntax. Since {{- expr and expr -}} are standard Go template syntax for controlling whitespace, templates using these forms won't be validated. Update the regex to allow optional - after {{ and before }}:
-var templateVarRegex = regexp.MustCompile(`\{\{\s*\.([a-zA-Z_][a-zA-Z0-9_\.]*)\s*(?:\|[^}]*)?\}\}`)
+var templateVarRegex = regexp.MustCompile(`\{\{\-?\s*\.([a-zA-Z_][a-zA-Z0-9_\.]*)\s*(?:\|[^}]*)?\s*\-?\}\}`)🤖 Prompt for AI Agents
In `@internal/config_loader/validator.go` around lines 15 - 16, The
templateVarRegex currently doesn't account for Go template trim delimiters
(`{{-` and `-}}`); update the regexp assigned to templateVarRegex so it allows
an optional hyphen immediately after the opening braces and/or immediately
before the closing braces while preserving capturing of the variable path and
optional pipe/filter segment (i.e., make the openings `\{\{\-?\s*` and closings
`\s*\-?\}\}` and keep the existing capture group `([a-zA-Z_][a-zA-Z0-9_\.]*)`
and optional pipe part intact).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/executor/param_extractor.go (1)
20-55: Convert defaults throughparam.Typeon error paths.Line 21-53: when extraction or conversion fails for non‑required params,
param.Defaultis written directly, skipping type conversion and producing inconsistent types vs the success path. Consider routing defaults throughconvertParamType(or centralizing default+conversion) soparam.Typeis always honored.🔧 Suggested fix
- if err != nil { - if param.Required { - return NewExecutorError(PhaseParamExtraction, param.Name, - fmt.Sprintf("failed to extract required parameter '%s' from source '%s'", param.Name, param.Source), err) - } - // Use default for non-required params if extraction fails - if param.Default != nil { - execCtx.Params[param.Name] = param.Default - } - continue - } + if err != nil { + if param.Required { + return NewExecutorError(PhaseParamExtraction, param.Name, + fmt.Sprintf("failed to extract required parameter '%s' from source '%s'", param.Name, param.Source), err) + } + // Fall back to default (type conversion below keeps param.Type consistent) + value = param.Default + } @@ - if value != nil && param.Type != "" { - converted, convErr := convertParamType(value, param.Type) - if convErr != nil { - if param.Required { - return NewExecutorError(PhaseParamExtraction, param.Name, - fmt.Sprintf("failed to convert parameter '%s' to type '%s'", param.Name, param.Type), convErr) - } - // Use default for non-required params if conversion fails - if param.Default != nil { - execCtx.Params[param.Name] = param.Default - } - continue - } - value = converted - } + if value != nil && param.Type != "" { + converted, convErr := convertParamType(value, param.Type) + if convErr != nil { + if param.Required { + return NewExecutorError(PhaseParamExtraction, param.Name, + fmt.Sprintf("failed to convert parameter '%s' to type '%s'", param.Name, param.Type), convErr) + } + if param.Default != nil { + converted, convErr = convertParamType(param.Default, param.Type) + if convErr != nil { + return NewExecutorError(PhaseParamExtraction, param.Name, + fmt.Sprintf("failed to convert default for parameter '%s' to type '%s'", param.Name, param.Type), convErr) + } + value = converted + } else { + value = nil + } + } else { + value = converted + } + }
🤖 Fix all issues with AI agents
In `@internal/config_loader/loader_test.go`:
- Around line 1052-1062: The helper configWithResources returns an AdapterConfig
with APIVersion set to "hyperfleet.openshift.io/v1alpha1" which doesn't match
the supported constant; update the APIVersion value in configWithResources to
the supported "hyperfleet.redhat.com/v1alpha1" so AdapterConfig (and its
validation in ValidateStruct) uses the correct API group; locate the APIVersion
field inside the configWithResources function and replace the incorrect string
with the supported constant/string.
In `@internal/config_loader/loader.go`:
- Around line 225-249: The resolvePath function must prevent symlink escapes by
resolving symlinks before the containment check: after computing baseAbs (and
before computing targetPath) call filepath.EvalSymlinks on baseAbs (store e.g.
baseResolved), and after computing targetPath call filepath.EvalSymlinks on
targetPath (store targetResolved); then compute filepath.Rel between
baseResolved and targetResolved and reject paths that escape (rel starts with
".." or an error). Update error messages to reference refPath and propagate
EvalSymlinks errors appropriately; keep using resolvePath, baseDir, refPath,
baseAbs/baseClean and targetPath as anchors when editing.
In `@internal/config_loader/README.md`:
- Around line 145-150: The example ActionBase struct in the README is missing
the Log field used by post-actions; update the ActionBase definition in the
documentation to include the Log field (e.g., Log *LogConfig or similar
name/type used elsewhere) so examples and embedding references to ActionBase.Log
compile and make sense—locate the ActionBase struct in the README and add the
Log field with the correct YAML tag and type consistent with the codebase so
post-actions that reference ActionBase.Log are documented accurately.
In `@internal/executor/README.md`:
- Around line 144-162: Update the "Supported Parameter Types" table row for
`float`, `float64` to hyphenate the compound adjective: change the Description
text from "Floating point value" to "Floating-point value" (locate the table
under the "Supported Parameter Types" heading and the `float`, `float64` row).
♻️ Duplicate comments (4)
internal/config_loader/README.md (1)
118-124: Add a language hint to the validation-error example block.
This still trips fenced-code language linting.🧹 Suggested fix
-``` +```text spec.params[0].name is required spec.preconditions[1].apiCall.method "INVALID" is invalid (allowed: GET, POST, PUT, PATCH, DELETE) spec.resources[0].name "my-resource": must start with lowercase letter and contain only letters, numbers, underscores (no hyphens) spec.preconditions[0].capture[0]: must have either 'field' or 'expression' set</details> </blockquote></details> <details> <summary>internal/config_loader/loader.go (1)</summary><blockquote> `144-153`: **Avoid silently skipping file-reference handling when baseDir is empty.** `Parse()` callers can supply buildRef/manifest.ref; with an empty baseDir the pipeline skips validation/loading, leaving unresolved refs. <details> <summary>🛡️ Suggested guard</summary> ```diff - // 3. File reference validation and loading (only if baseDir is set) - if cfg.baseDir != "" { + // 3. File reference validation and loading + if cfg.baseDir != "" { if err := validator.ValidateFileReferences(); err != nil { return fmt.Errorf("file reference validation failed: %w", err) } if err := loadFileReferences(config, cfg.baseDir); err != nil { return fmt.Errorf("failed to load file references: %w", err) } + } else if hasFileReferences(config) { + return fmt.Errorf("file references require baseDir; pass WithBaseDir or use Load()") }+func hasFileReferences(config *AdapterConfig) bool { + for i := range config.Spec.Resources { + if config.Spec.Resources[i].GetManifestRef() != "" { + return true + } + } + if config.Spec.Post != nil { + for i := range config.Spec.Post.Payloads { + if config.Spec.Post.Payloads[i].BuildRef != "" { + return true + } + } + } + return false +}internal/config_loader/validator.go (1)
15-16: Support Go template trim delimiters ({{-/-}}).
Templates using whitespace trimming won’t be validated by the current regex.🔧 Proposed fix
-var templateVarRegex = regexp.MustCompile(`\{\{\s*\.([a-zA-Z_][a-zA-Z0-9_\.]*)\s*(?:\|[^}]*)?\}\}`) +var templateVarRegex = regexp.MustCompile(`\{\{\-?\s*\.([a-zA-Z_][a-zA-Z0-9_\.]*)\s*(?:\|[^}]*)?\s*\-?\}\}`)internal/config_loader/types.go (1)
157-172: Ensure field-levelrequired_without_allruns beforedive.
Withdive,required_without_all=..., an empty slice can bypass the field-level constraint.🔧 Proposed fix
- Conditions []Condition `yaml:"conditions,omitempty" validate:"dive,required_without_all=ActionBase.APICall Expression"` + Conditions []Condition `yaml:"conditions,omitempty" validate:"required_without_all=ActionBase.APICall Expression,dive"`
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (21)
configs/adapter-config-template.yamlgo.modinternal/config_loader/README.mdinternal/config_loader/loader.gointernal/config_loader/loader_test.gointernal/config_loader/struct_validator.gointernal/config_loader/types.gointernal/config_loader/validator.gointernal/config_loader/validator_schema.gointernal/config_loader/validator_test.gointernal/criteria/README.mdinternal/executor/README.mdinternal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/param_extractor_test.gointernal/executor/post_action_executor_test.gopkg/logger/with_error_field_test.gotest/integration/config-loader/testdata/adapter_config_valid.yamltest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/testdata/adapter_config_valid.yaml
💤 Files with no reviewable changes (3)
- test/integration/config-loader/testdata/adapter_config_valid.yaml
- internal/config_loader/validator_schema.go
- test/testdata/adapter_config_valid.yaml
🚧 Files skipped from review as they are similar to previous changes (5)
- pkg/logger/with_error_field_test.go
- internal/executor/post_action_executor_test.go
- internal/executor/param_extractor_test.go
- configs/adapter-config-template.yaml
- test/integration/executor/executor_integration_test.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
internal/executor/param_extractor.gogo.modinternal/config_loader/README.mdinternal/config_loader/loader_test.gointernal/config_loader/loader.gointernal/config_loader/struct_validator.gointernal/config_loader/validator_test.gointernal/config_loader/validator.gointernal/config_loader/types.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
internal/config_loader/types.go
🧬 Code graph analysis (6)
internal/executor/param_extractor.go (1)
internal/executor/types.go (2)
NewExecutorError(375-382)PhaseParamExtraction(21-21)
test/integration/executor/executor_k8s_integration_test.go (1)
internal/config_loader/types.go (4)
ActionBase(159-163)APICall(175-183)CaptureField(196-199)FieldExpressionDef(13-18)
internal/executor/executor_test.go (2)
internal/config_loader/types.go (3)
ActionBase(159-163)LogAction(273-276)Precondition(167-172)internal/executor/types.go (1)
StatusSuccess(35-35)
internal/config_loader/validator_test.go (2)
internal/config_loader/types.go (7)
ActionBase(159-163)Condition(202-206)APICall(175-183)CaptureField(196-199)FieldExpressionDef(13-18)Precondition(167-172)Payload(130-141)internal/config_loader/struct_validator.go (1)
ValidateStruct(115-135)
internal/config_loader/validator.go (5)
internal/config_loader/types.go (2)
AdapterConfig(69-74)ValidationErrors(298-300)internal/config_loader/struct_validator.go (1)
ValidateStruct(115-135)internal/config_loader/loader.go (1)
SupportedAPIVersions(26-28)internal/config_loader/constants.go (10)
FieldSpec(9-9)FieldPost(21-21)FieldPayloads(41-41)FieldBuildRef(43-43)FieldResources(20-20)FieldManifest(78-78)FieldRef(85-85)FieldPreconditions(19-19)FieldCapture(49-49)FieldExpression(51-51)internal/criteria/types.go (2)
Operator(10-10)OperatorExists(28-28)
internal/config_loader/types.go (2)
internal/criteria/types.go (1)
Operator(10-10)internal/k8s_client/discovery.go (2)
Discovery(14-29)DiscoveryConfig(32-42)
🪛 LanguageTool
internal/executor/README.md
[uncategorized] ~161-~161: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...oats truncated | | float, float64 | Floating point value | Strings parsed | | bool | Boo...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
🪛 markdownlint-cli2 (0.18.1)
internal/config_loader/README.md
119-119: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (33)
test/integration/executor/executor_k8s_integration_test.go (2)
182-195: ActionBase + FieldExpressionDef wiring matches new config schema.Line 182-195 aligns Precondition/CaptureField literals with the new ActionBase and FieldExpressionDef types, which should satisfy struct validation.
285-292: PostAction ActionBase update looks correct.Line 285-292 mirrors the new ActionBase structure for post-actions and should keep validation consistent.
internal/criteria/README.md (2)
45-45: Evaluator examples reflect the context-aware constructor.Line 45, 227, and 257 show NewEvaluator with an explicit context, consistent with the updated API.
Also applies to: 227-227, 257-257
144-155: ExtractValueResult/GetField error semantics are clearly documented.Line 144-155 and 181-203 document parse vs runtime extraction errors and the GetField contract clearly.
Also applies to: 181-203
internal/executor/param_extractor.go (1)
165-354: Conversion helpers are comprehensive and readable.Line 165-354 covers string/int/float/bool conversions with overflow guarding for unsigned ints; this is clear and robust.
go.mod (1)
8-8: Dependency versions are acceptable and confirmed as current.The validator/v10 v10.30.1 addition at line 8 is the latest available release (24 Dec 2025) with no published security advisories. The transitive dependencies (mimetype v1.4.12, locales v0.14.1, universal-translator v0.18.1, go-urn v1.4.0 at lines 62–70 and 84) are standard validator transitive deps. The golang.org/x/ version bumps (crypto v0.46.0, net v0.47.0, sys v0.39.0, term v0.38.0 at lines 136–142) are current releases from post-security-fix branches with no identified issues. All versions are reflected in go.mod.
internal/executor/executor_test.go (3)
451-492: ActionBase wrapping keeps precondition tests aligned with updated config types.
The updated fixtures mirror the embedded ActionBase shape while preserving the sequential-stop assertions.
655-658: Post-action fixtures correctly use ActionBase embedding.
Log actions are still exercised while matching the new struct layout.
725-739: Skip-reason scenarios updated appropriately for ActionBase.
These cases remain consistent with the new precondition representation.internal/config_loader/struct_validator.go (1)
94-110: Env-required parameter validation stays fail-fast.
The check correctly enforces required env params when no default is provided. Based on learnings, this preserves the intended fail-fast behavior.internal/config_loader/validator_test.go (8)
30-109: Good coverage for operator validation paths, includingexistssemantics.
119-186: Template variable tests align with ActionBase refactor and capture-variable flow.
189-213: CEL expression tests look consistent with the new validator entry point.
317-335: Multi-error aggregation path is exercised appropriately.
356-413: Payload struct validation coverage looks solid.
444-476: Parse-level payload validation assertions are consistent with new errors.
479-525: Capture field tests correctly reflect FieldExpressionDef mutual exclusivity.
528-569: YAML field-name cache tests add useful guardrails.internal/config_loader/validator.go (8)
22-92: Validator phases and error handling look consistent with the refactor.
112-167: File reference validation is clear and well-scoped to baseDir.
181-213: Condition value validation (incl.exists) is correctly enforced.
227-239: Capture-field CEL validation path is clear and targeted.
245-341: Template variable validation flow reads well after ActionBase changes.
368-425: CEL environment initialization and validation traversal look solid.
465-508: K8s manifest structural validation paths look consistent.
514-556: Helper APIs and test shims are clean and focused.internal/config_loader/types.go (7)
10-38: FieldExpressionDef + ValueDef embedding is a clean simplification.
68-121: Top-level struct validation tags look consistent and helpful.
130-155: Payload validation rules and error messages are clear.
175-205: APICall/CaptureField/Condition validation tightening looks good.
243-265: Resource/Discovery/Post validation tags look consistent with the new rules.
269-270: PostAction embedding via ActionBase is clean.
283-339: ValidationErrors container is straightforward and useful.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| // Helper to create a valid config with given resources | ||
| configWithResources := func(resources []Resource) *AdapterConfig { | ||
| return &AdapterConfig{ | ||
| APIVersion: "hyperfleet.openshift.io/v1alpha1", | ||
| Kind: "AdapterConfig", | ||
| Metadata: Metadata{Name: "test-adapter"}, | ||
| Spec: AdapterConfigSpec{ | ||
| Adapter: AdapterInfo{Version: "1.0.0"}, | ||
| Resources: resources, | ||
| }, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
APIVersion value doesn’t match the supported constant.
hyperfleet.openshift.io/v1alpha1 is inconsistent with the supported hyperfleet.redhat.com/v1alpha1, which can cause ValidateStruct to fail before the discovery assertions run.
✅ Suggested fix
- APIVersion: "hyperfleet.openshift.io/v1alpha1",
+ APIVersion: APIVersionV1Alpha1,📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Helper to create a valid config with given resources | |
| configWithResources := func(resources []Resource) *AdapterConfig { | |
| return &AdapterConfig{ | |
| APIVersion: "hyperfleet.openshift.io/v1alpha1", | |
| Kind: "AdapterConfig", | |
| Metadata: Metadata{Name: "test-adapter"}, | |
| Spec: AdapterConfigSpec{ | |
| Adapter: AdapterInfo{Version: "1.0.0"}, | |
| Resources: resources, | |
| }, | |
| } | |
| // Helper to create a valid config with given resources | |
| configWithResources := func(resources []Resource) *AdapterConfig { | |
| return &AdapterConfig{ | |
| APIVersion: APIVersionV1Alpha1, | |
| Kind: "AdapterConfig", | |
| Metadata: Metadata{Name: "test-adapter"}, | |
| Spec: AdapterConfigSpec{ | |
| Adapter: AdapterInfo{Version: "1.0.0"}, | |
| Resources: resources, | |
| }, | |
| } |
🤖 Prompt for AI Agents
In `@internal/config_loader/loader_test.go` around lines 1052 - 1062, The helper
configWithResources returns an AdapterConfig with APIVersion set to
"hyperfleet.openshift.io/v1alpha1" which doesn't match the supported constant;
update the APIVersion value in configWithResources to the supported
"hyperfleet.redhat.com/v1alpha1" so AdapterConfig (and its validation in
ValidateStruct) uses the correct API group; locate the APIVersion field inside
the configWithResources function and replace the incorrect string with the
supported constant/string.
| // resolvePath resolves a relative path against the base directory and validates | ||
| // that the resolved path does not escape the base directory. | ||
| func resolvePath(baseDir, refPath string) (string, error) { | ||
| baseAbs, err := filepath.Abs(baseDir) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to resolve base directory: %w", err) | ||
| } | ||
| baseClean := filepath.Clean(baseAbs) | ||
|
|
||
| var targetPath string | ||
| if filepath.IsAbs(refPath) { | ||
| targetPath = filepath.Clean(refPath) | ||
| } else { | ||
| targetPath = filepath.Clean(filepath.Join(baseClean, refPath)) | ||
| } | ||
|
|
||
| // Check if target path is within base directory | ||
| rel, err := filepath.Rel(baseClean, targetPath) | ||
| if err != nil { | ||
| return "", fmt.Errorf("path %q escapes base directory", refPath) | ||
| } | ||
|
|
||
| if strings.HasPrefix(rel, "..") { | ||
| return "", fmt.Errorf("path %q escapes base directory", refPath) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Harden resolvePath against symlink escapes.
Lexical Clean/Rel checks don’t prevent a ref from pointing at a symlink inside baseDir that resolves outside.
🔒 Suggested hardening
- baseAbs, err := filepath.Abs(baseDir)
+ baseAbs, err := filepath.EvalSymlinks(baseDir)
if err != nil {
return "", fmt.Errorf("failed to resolve base directory: %w", err)
}
baseClean := filepath.Clean(baseAbs)
@@
- // Check if target path is within base directory
- rel, err := filepath.Rel(baseClean, targetPath)
+ targetReal, err := filepath.EvalSymlinks(targetPath)
+ if err != nil {
+ return "", err
+ }
+ // Check if target path is within base directory
+ rel, err := filepath.Rel(baseClean, targetReal)
if err != nil {
return "", fmt.Errorf("path %q escapes base directory", refPath)
}
@@
- return targetPath, nil
+ return targetReal, nil🤖 Prompt for AI Agents
In `@internal/config_loader/loader.go` around lines 225 - 249, The resolvePath
function must prevent symlink escapes by resolving symlinks before the
containment check: after computing baseAbs (and before computing targetPath)
call filepath.EvalSymlinks on baseAbs (store e.g. baseResolved), and after
computing targetPath call filepath.EvalSymlinks on targetPath (store
targetResolved); then compute filepath.Rel between baseResolved and
targetResolved and reject paths that escape (rel starts with ".." or an error).
Update error messages to reference refPath and propagate EvalSymlinks errors
appropriately; keep using resolvePath, baseDir, refPath, baseAbs/baseClean and
targetPath as anchors when editing.
| ```go | ||
| // ActionBase - common fields for actions (preconditions, post-actions) | ||
| type ActionBase struct { | ||
| Name string `yaml:"name" validate:"required"` | ||
| APICall *APICall `yaml:"apiCall,omitempty"` | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Document ActionBase.Log in the struct embedding example.
The snippet omits the Log field that post-actions rely on.
📝 Suggested update
type ActionBase struct {
Name string `yaml:"name" validate:"required"`
APICall *APICall `yaml:"apiCall,omitempty"`
+ Log *LogAction `yaml:"log,omitempty"`
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ```go | |
| // ActionBase - common fields for actions (preconditions, post-actions) | |
| type ActionBase struct { | |
| Name string `yaml:"name" validate:"required"` | |
| APICall *APICall `yaml:"apiCall,omitempty"` | |
| } |
🤖 Prompt for AI Agents
In `@internal/config_loader/README.md` around lines 145 - 150, The example
ActionBase struct in the README is missing the Log field used by post-actions;
update the ActionBase definition in the documentation to include the Log field
(e.g., Log *LogConfig or similar name/type used elsewhere) so examples and
embedding references to ActionBase.Log compile and make sense—locate the
ActionBase struct in the README and add the Log field with the correct YAML tag
and type consistent with the codebase so post-actions that reference
ActionBase.Log are documented accurately.
| - name: "nodeCount" | ||
| source: "event.spec.nodes" | ||
| type: "int" # Convert to int64 | ||
| - name: "enableFeature" | ||
| source: "env.ENABLE_FEATURE" | ||
| type: "bool" # Convert to bool | ||
| default: false | ||
| ``` | ||
|
|
||
| </details> | ||
|
|
||
| #### Supported Parameter Types | ||
|
|
||
| | Type | Description | Conversion Notes | | ||
| |------|-------------|-----------------| | ||
| | `string` | String value (default) | Any value converted to string | | ||
| | `int`, `int64` | Integer value | Strings parsed, floats truncated | | ||
| | `float`, `float64` | Floating point value | Strings parsed | | ||
| | `bool` | Boolean value | Supports: `true/false`, `yes/no`, `on/off`, `1/0` | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hyphenate compound adjective in type table.
Line 161: “Floating point value” should be “Floating‑point value.”
✏️ Suggested edit
-| `float`, `float64` | Floating point value | Strings parsed |
+| `float`, `float64` | Floating-point value | Strings parsed |📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: "nodeCount" | |
| source: "event.spec.nodes" | |
| type: "int" # Convert to int64 | |
| - name: "enableFeature" | |
| source: "env.ENABLE_FEATURE" | |
| type: "bool" # Convert to bool | |
| default: false | |
| ``` | |
| </details> | |
| #### Supported Parameter Types | |
| | Type | Description | Conversion Notes | | |
| |------|-------------|-----------------| | |
| | `string` | String value (default) | Any value converted to string | | |
| | `int`, `int64` | Integer value | Strings parsed, floats truncated | | |
| | `float`, `float64` | Floating point value | Strings parsed | | |
| | `bool` | Boolean value | Supports: `true/false`, `yes/no`, `on/off`, `1/0` | | |
| | Type | Description | Conversion Notes | | |
| |------|-------------|-----------------| | |
| | `string` | String value (default) | Any value converted to string | | |
| | `int`, `int64` | Integer value | Strings parsed, floats truncated | | |
| | `float`, `float64` | Floating-point value | Strings parsed | | |
| | `bool` | Boolean value | Supports: `true/false`, `yes/no`, `on/off`, `1/0` | |
🧰 Tools
🪛 LanguageTool
[uncategorized] ~161-~161: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...oats truncated | | float, float64 | Floating point value | Strings parsed | | bool | Boo...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
🤖 Prompt for AI Agents
In `@internal/executor/README.md` around lines 144 - 162, Update the "Supported
Parameter Types" table row for `float`, `float64` to hyphenate the compound
adjective: change the Description text from "Floating point value" to
"Floating-point value" (locate the table under the "Supported Parameter Types"
heading and the `float`, `float64` row).
| // Validator | ||
| // ----------------------------------------------------------------------------- | ||
| // Phase 2: Custom validations that can't be expressed via struct tags | ||
| if err := v.validateAPIVersionSupported(); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this check belongs here within ValidateStructure or if it similar to the ValidateAdapterVersion in the runValidationPipeline since is checking more about the semantics than the required fields/format
If that is the case, the validateStructure function could be removed for a direct call to ValidateStruct
| } | ||
|
|
||
| // Semantic validation (optional, can be skipped for performance) | ||
| // 4. Semantic validation (optional, can be skipped for performance) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the performance cost of this semantic validation?
Is it performed only on starting the adapter?
If it is small I would prefer to validate always and reduce cognitive load of knowing if this can be skipped or not
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. We should. I can cover this in my config standardizing PR.
|
/lgtm |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: rh-amarin The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
abca166
into
openshift-hyperfleet:main
Summary by CodeRabbit
New Features
Improvements
Documentation
Tests
✏️ Tip: You can customize this high-level summary in your review settings.