Skip to content

Commit 13afb05

Browse files
committed
Flag *Ref/*Refs fields that don't use KubernetesNameRef type
Fields ending in Ref or Refs should use KubernetesNameRef type to reference ORC objects. This catches cases where the naming convention is correct but the type is wrong (e.g., SecurityGroupRefs []OpenStackName should be []KubernetesNameRef). CloudCredentialsRef is excluded as it intentionally uses a different type.
1 parent 4c77b58 commit 13afb05

2 files changed

Lines changed: 80 additions & 0 deletions

File tree

  • tools/orc-api-linter/pkg/analysis/noopenstackidref

tools/orc-api-linter/pkg/analysis/noopenstackidref/analyzer.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ ORC Kubernetes objects, not OpenStack resources directly by UUID.
4040
Fields ending with 'ID' or 'IDs' (like ProjectID, NetworkIDs) in spec structs should
4141
instead use KubernetesNameRef type with a 'Ref' or 'Refs' suffix (like ProjectRef, NetworkRefs).
4242
43+
Additionally, fields ending with 'Ref' or 'Refs' must use the KubernetesNameRef type,
44+
not other types like OpenStackName or string.
45+
4346
See: https://k-orc.cloud/development/api-design/`
4447
)
4548

@@ -48,12 +51,22 @@ See: https://k-orc.cloud/development/api-design/`
4851
// KubernetesNameRef with a "Ref" or "Refs" suffix to reference ORC objects.
4952
var openstackIDPattern = regexp.MustCompile(`IDs?$`)
5053

54+
// refPattern matches field names that end with "Ref" or "Refs".
55+
// These fields should use KubernetesNameRef type.
56+
var refPattern = regexp.MustCompile(`Refs?$`)
57+
5158
// excludedIDPatterns contains field name patterns that end in "ID" or "IDs" but are
5259
// not OpenStack resource references.
5360
var excludedIDPatterns = []string{
5461
"SegmentationID", // VLAN segmentation ID, not an OpenStack resource
5562
}
5663

64+
// excludedRefPatterns contains field name patterns that end in "Ref" or "Refs" but
65+
// intentionally use a different type than KubernetesNameRef.
66+
var excludedRefPatterns = []string{
67+
"CloudCredentialsRef", // References a credentials secret, not an ORC object
68+
}
69+
5770
// excludedStructs contains struct names that should not be checked even though
5871
// they don't have "Status" in their name. These are typically nested types used
5972
// exclusively within status structs.
@@ -105,6 +118,22 @@ func checkField(pass *analysis.Pass, field *ast.Field, qualifiedFieldName string
105118
return
106119
}
107120

121+
// Check if field name ends in Ref/Refs but uses wrong type
122+
if refPattern.MatchString(fieldName) {
123+
// Check if field name is in the Ref exclusion list
124+
if slices.Contains(excludedRefPatterns, fieldName) {
125+
return
126+
}
127+
128+
if !isKubernetesNameRefTypeOrSlice(field.Type) {
129+
pass.Reportf(field.Pos(),
130+
"field %s has Ref suffix but does not use KubernetesNameRef type; "+
131+
"see https://k-orc.cloud/development/api-design/",
132+
qualifiedFieldName)
133+
}
134+
return
135+
}
136+
108137
// Check if field name matches OpenStack ID pattern
109138
if !openstackIDPattern.MatchString(fieldName) {
110139
return
@@ -172,3 +201,16 @@ func isKubernetesNameRefType(expr ast.Expr) bool {
172201

173202
return false
174203
}
204+
205+
// isKubernetesNameRefTypeOrSlice checks if the expression is KubernetesNameRef,
206+
// *KubernetesNameRef, or []KubernetesNameRef. This is used for Ref/Refs fields
207+
// which may be singular or plural.
208+
func isKubernetesNameRefTypeOrSlice(expr ast.Expr) bool {
209+
// Check for []KubernetesNameRef
210+
if arrayType, ok := expr.(*ast.ArrayType); ok {
211+
return isKubernetesNameRefType(arrayType.Elt)
212+
}
213+
214+
// Check for KubernetesNameRef or *KubernetesNameRef
215+
return isKubernetesNameRefType(expr)
216+
}

tools/orc-api-linter/pkg/analysis/noopenstackidref/testdata/src/a/a.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,41 @@ type PluralIDsStatus struct {
147147
// NetworkIDs is allowed in status.
148148
NetworkIDs []string `json:"networkIDs,omitempty"`
149149
}
150+
151+
// ---- Ref/Refs fields with wrong type: should be flagged ----
152+
153+
// OpenStackName simulates the ORC OpenStackName type (wrong type for Refs).
154+
type OpenStackName string
155+
156+
// WrongTypeRefSpec tests that Ref fields with wrong type are flagged.
157+
type WrongTypeRefSpec struct {
158+
// ProjectRef with *string type is wrong - should use *KubernetesNameRef.
159+
ProjectRef *string `json:"projectRef,omitempty"` // want `field WrongTypeRefSpec.ProjectRef has Ref suffix but does not use KubernetesNameRef type`
160+
161+
// NetworkRef with OpenStackName type is wrong - should use KubernetesNameRef.
162+
NetworkRef OpenStackName `json:"networkRef,omitempty"` // want `field WrongTypeRefSpec.NetworkRef has Ref suffix but does not use KubernetesNameRef type`
163+
164+
// SubnetRef is correct - uses KubernetesNameRef.
165+
SubnetRef KubernetesNameRef `json:"subnetRef,omitempty"`
166+
167+
// RouterRef is correct - uses *KubernetesNameRef.
168+
RouterRef *KubernetesNameRef `json:"routerRef,omitempty"`
169+
}
170+
171+
// WrongTypeRefsSpec tests that plural Refs fields with wrong type are flagged.
172+
type WrongTypeRefsSpec struct {
173+
// SecurityGroupRefs with []OpenStackName type is wrong - should use []KubernetesNameRef.
174+
SecurityGroupRefs []OpenStackName `json:"securityGroupRefs,omitempty"` // want `field WrongTypeRefsSpec.SecurityGroupRefs has Ref suffix but does not use KubernetesNameRef type`
175+
176+
// NetworkRefs with []string type is wrong - should use []KubernetesNameRef.
177+
NetworkRefs []string `json:"networkRefs,omitempty"` // want `field WrongTypeRefsSpec.NetworkRefs has Ref suffix but does not use KubernetesNameRef type`
178+
179+
// SubnetRefs is correct - uses []KubernetesNameRef.
180+
SubnetRefs []KubernetesNameRef `json:"subnetRefs,omitempty"`
181+
}
182+
183+
// WrongTypeRefsStatus tests that Refs in status with wrong type are allowed.
184+
type WrongTypeRefsStatus struct {
185+
// SecurityGroupRefs is allowed in status even with wrong type.
186+
SecurityGroupRefs []OpenStackName `json:"securityGroupRefs,omitempty"`
187+
}

0 commit comments

Comments
 (0)