Skip to content

ci: add test helper for regex validation via CRD #438

Description

@chlunde

What problem are you facing?

AI generated code likes to add tests for everything, including the regexes. As they're not available to Go code directly Claude typically copies the regex from the comment into a variable. This could cause drift and regressions.

How could Crossplane help solve your problem?

We should consider adding a generic crdtest package or similar that could extract regex from CRDs and test them.

Example:

package v1alpha1

import (
	"regexp"
	"testing"
)

// routineArgumentPattern must match the +kubebuilder:validation:items:Pattern
// marker on Routine.Arguments. It's the only thing standing between that
// field and arbitrary SQL, since the reconciler splices each argument
// unquoted into a GRANT/REVOKE statement -- see quotedSignatures in
// pkg/controller/namespaced/postgresql/grant/reconciler.go. Keep this in
// sync with the marker by hand; there is no way to read kubebuilder markers
// back out of the compiled type at runtime.
const routineArgumentPattern = `^[a-zA-Z_][a-zA-Z0-9_$]*(\.[a-zA-Z_][a-zA-Z0-9_$]*)?$`

func TestRoutineArgumentPattern(t *testing.T) {
	re := regexp.MustCompile(routineArgumentPattern)

	cases := map[string]struct {
		arg     string
		matches bool
	}{
		"PlainIdentifier": {
			arg:     "text",
			matches: true,
		},
		"SchemaQualifiedCompositeType": {
			arg:     "aws_commons._s3_uri_1",
			matches: true,
		},
		"SchemaQualifiedWithUnderscoresAndDollar": {
			arg:     "my_schema$1.my_type$2",
			matches: true,
		},
		"EmptyString": {
			arg:     "",
			matches: false,
		},
		"LeadingDigit": {
			arg:     "1text",
			matches: false,
		},
		"TrailingDot": {
			arg:     "aws_commons.",
			matches: false,
		},
		"LeadingDot": {
			arg:     ".aws_commons",
			matches: false,
		},
		"TwoDots": {
			arg:     "a.b.c",
			matches: false,
		},
		"EmbeddedSpace": {
			arg:     "foo bar",
			matches: false,
		},
		"SpaceAroundDot": {
			arg:     "foo. bar",
			matches: false,
		},
		"SQLInjectionSemicolon": {
			arg:     "text; DROP TABLE users",
			matches: false,
		},
		"SQLInjectionQuote": {
			arg:     `text" OR "1"="1`,
			matches: false,
		},
		"SQLInjectionParens": {
			arg:     "text)--",
			matches: false,
		},
	}

	for name, tc := range cases {
		t.Run(name, func(t *testing.T) {
			got := re.MatchString(tc.arg)
			if got != tc.matches {
				t.Errorf("routineArgumentPattern.MatchString(%q) = %v, want %v", tc.arg, got, tc.matches)
			}
		})
	}
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions