Skip to content

V2#22

Open
alekc wants to merge 6 commits intomainfrom
v2
Open

V2#22
alekc wants to merge 6 commits intomainfrom
v2

Conversation

@alekc
Copy link
Copy Markdown
Owner

@alekc alekc commented Jul 28, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Added new MultiRunner custom resource for managing multiple runner instances
    • Introduced v1beta2 API with simplified token-based authentication structure
    • Token configuration now handled directly via token and token_secret fields
  • Documentation

    • Updated configuration examples to reference v1beta2 API version

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 19, 2026

📝 Walkthrough

Walkthrough

This pull request upgrades the GitLab Runner Operator's API from v1beta1 to v1beta2, introduces a new MultiRunner custom resource, refactors the Runner controller to use Kubernetes Secrets for authentication instead of GitLab API registration, updates build tooling with newer controller-gen and kustomize versions, and adds corresponding CRD manifests, RBAC rules, and webhooks.

Changes

Cohort / File(s) Summary
Build Configuration
Makefile, PROJECT
Updated shell flags for error handling, introduced repo-local configuration variables (REPOSITORY_ROOT, BIN_DIR, CONTROLLER_GEN_VERSION, ENVTEST_*), replaced go-get-tool with go-install-tool macro, upgraded tool versions (controller-gen v0.4.1→v0.13.0, kustomize v3.8.7→v5.1.1), updated CRD_OPTIONS to use crdVersions=v1, added tidy target, and declared new MultiRunner API resource.
API v1beta2 Definitions
api/v1beta2/groupversion_info.go, api/v1beta2/multirunner_types.go, api/v1beta2/runner_types.go, api/v1beta2/runner_webhook.go, api/v1beta2/webhook_*.go
Migrated API package from v1beta1 to v1beta2; added complete MultiRunner CRD types with spec/status; refactored RunnerSpec to replace nested RegistrationConfig with top-level Token and TokenSecret fields; changed LastRegistrationTags to pointer slice; updated webhook method signatures to return admission.Warnings; regenerated deepcopy helpers for both MultiRunner and Runner types.
CRD & RBAC Manifests
config/crd/bases/gitlab.k8s.alekc.dev_*.yaml, config/crd/kustomization.yaml, config/crd/patches/*.yaml, config/rbac/*.yaml
Added MultiRunner CRD manifest with v1beta2 version and status subresource; updated Runner CRD from v1beta1 to v1beta2 and removed registration_config schema in favor of token/token_secret fields; added webhook and cert-injection patches for MultiRunner; introduced multirunner-editor-role and multirunner-viewer-role RBAC rules; extended manager-role with MultiRunner permissions.
Webhook & Configuration
config/webhook/manifests.yaml, config/manager/kustomization.yaml, config/config.go
Updated MutatingWebhookConfiguration and ValidatingWebhookConfiguration from v1beta1 to v1beta2 endpoints and review versions; bumped kustomization apiVersion; changed KubernetesConfig reference from v1beta1 to v1beta2.
Sample Manifests
config/samples/gitlab_v1beta*.yaml
Added MultiRunner sample manifest; updated Runner sample apiVersion from v1beta1 to v1beta2.
Controllers
controllers/multirunner_controller.go, controllers/runner_controller.go, controllers/runner_controller_test.go, controllers/suite_test.go
Added new MultiRunnerReconciler with Reconcile and SetupWithManager methods; refactored RunnerReconciler to use Kubernetes Secrets for token retrieval instead of GitLab API registration (commented out RegisterNewRunnerOnGitlab, RemoveRunnerFromGitlab, getGitlabApiClient); added getTokenFromSecret helper; disabled registration-condition tests; updated test suite to v1beta2 and removed custom Ginkgo reporters.
Internal Utilities
internal/api/gitlab.go, internal/api/gitlab_test.go, internal/api/mocked_client.go, internal/generate/config.go, internal/validate/validate.go, main.go
Removed Register method from GitlabClient interface and disabled related mock implementations; updated parameter types from v1beta1.Runner to v1beta2.Runner throughout; switched main.go to initialize v1beta2 scheme and setup v1beta2 Runner webhooks; removed explicit metrics binding and port options from manager config.
Dependencies
go.mod, README.md
Bumped major transitive and direct dependencies (logr, gomega, go-gitlab, Kubernetes modules, controller-runtime); updated README example apiVersions from v1beta1 to v1beta2.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant K8sAPI as Kubernetes API
    participant RunnerCtrl as Runner Controller
    participant SecretMgr as Secret Manager
    participant KubeClient as Kubernetes Client

    Note over RunnerCtrl: Old (v1beta1) - GitLab-managed
    User->>K8sAPI: Create Runner with RegistrationConfig
    K8sAPI->>RunnerCtrl: Trigger Reconcile
    RunnerCtrl->>RunnerCtrl: Call RegisterNewRunnerOnGitlab<br/>(GitLab API registration)
    RunnerCtrl->>K8sAPI: Store AuthenticationToken<br/>in Runner.Status

    Note over RunnerCtrl: New (v1beta2) - Secret-managed
    User->>K8sAPI: Create Runner with Token & TokenSecret
    K8sAPI->>RunnerCtrl: Trigger Reconcile
    RunnerCtrl->>SecretMgr: Read Token from<br/>referenced Secret
    SecretMgr->>KubeClient: Retrieve Secret by name
    KubeClient->>RunnerCtrl: Return Secret data["token"]
    RunnerCtrl->>K8sAPI: Populate Status.AuthenticationToken<br/>from Secret or Spec.Token
    RunnerCtrl->>RunnerCtrl: Registration/Deregistration<br/>logic disabled
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A whisker-twitch of joy! 🐰
New MultiRunner hops along,
Secrets replace the registry dance,
v1beta2 bounds with strength,
The operator's tale grows long!
🍀✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title "V2" is extremely vague and does not clearly convey the actual scope of changes, which involves upgrading the API from v1beta1 to v1beta2, adding a new MultiRunner controller, and updating dependencies. Consider renaming the title to something more specific like "Upgrade API to v1beta2 and add MultiRunner controller" or "API v1beta1 to v1beta2 migration with new MultiRunner resource".
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v2
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

@alekc
Copy link
Copy Markdown
Owner Author

alekc commented Mar 19, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 19, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (9)
README.md (2)

29-40: ⚠️ Potential issue | 🟠 Major

Documentation examples use removed registration_config field.

The apiVersion was updated to v1beta2, but the examples still use registration_config which was replaced with token and token_secret fields in v1beta2. This will confuse users.

Suggested update for configuration section
 apiVersion: gitlab.k8s.alekc.dev/v1beta2
 kind: Runner
 metadata:
   name: runner-sample
 spec:
   environment:
     - "bar=foo"
   concurrent: 1
   log_level: info
   gitlab_instance_url: https://gitlab.com
-  registration_config: {}
+  token_secret: "gitlab-runner-token"  # Reference to a Secret containing the runner token

All examples in this file (minimum configuration, secret-based token, volumes) need similar updates to use token or token_secret instead of registration_config.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 29 - 40, Update the README examples that target
apiVersion v1beta2 to replace the removed registration_config field with the new
token/token_secret fields: locate examples named "minimum configuration",
"secret-based token", and "volumes" (and any snippets containing
registration_config) and change them to specify either token: "<literal-token>"
for inline tokens or token_secret: { name: "<k8s-secret-name>", key: "<key>" }
for secret-based tokens; ensure any explanatory text and example YAML keys
mention token/token_secret instead of registration_config so the examples match
the v1beta2 API.

56-65: ⚠️ Potential issue | 🟠 Major

Minimum configuration example uses deprecated structure.

This example needs to be updated to reflect the v1beta2 API changes.

Suggested fix
 apiVersion: gitlab.k8s.alekc.dev/v1beta2
 kind: Runner
 metadata:
   name: runner-sample
 spec:
-  registration_config:
-    token: "xxx"
-    tag_list:
-      - test-gitlab-runner
+  token: "xxx"
+  # Note: tag_list configuration may have changed - verify current API spec
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 56 - 65, The README example uses the old
registration_config structure; update the v1beta2 example so it uses the new
Runner spec fields: replace spec.registration_config with spec.registration,
rename tag_list to tags, and keep the token under registration.token (ensure
field names match the v1beta2 API for Runner). Update the sample metadata
(apiVersion: gitlab.k8s.alekc.dev/v1beta2, kind: Runner) to reflect those new
field names so the example validates against v1beta2.
api/v1beta2/webhook_suite_test.go (1)

55-58: ⚠️ Potential issue | 🔴 Critical

Undefined reference to printer.NewlineReporter{} - will not compile.

The printer import from sigs.k8s.io/controller-runtime/pkg/envtest was removed, but line 57 still references printer.NewlineReporter{}. This will cause a compilation error.

Suggested fix - use simpler RunSpecs
 func TestAPIs(t *testing.T) {
 	RegisterFailHandler(Fail)
 
-	RunSpecsWithDefaultAndCustomReporters(t,
-		"Webhook Suite",
-		[]Reporter{printer.NewlineReporter{}})
+	RunSpecs(t, "Webhook Suite")
 }

Note: In Ginkgo v2, RunSpecsWithDefaultAndCustomReporters is deprecated in favor of RunSpecs with reporter configuration via ReportConfiguration.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v1beta2/webhook_suite_test.go` around lines 55 - 58, The test still
references the removed printer.NewlineReporter via
RunSpecsWithDefaultAndCustomReporters which is undefined; replace the call to
RunSpecsWithDefaultAndCustomReporters(t, "Webhook Suite",
[]Reporter{printer.NewlineReporter{}}) with a Ginkgo v2 compatible RunSpecs
invocation (e.g., call RunSpecs(t, "Webhook Suite") or configure reporter
behavior via ReportConfiguration) so that the undefined symbol
printer.NewlineReporter is removed and the test compiles; update the test
function that calls RunSpecsWithDefaultAndCustomReporters to use RunSpecs and
adjust any reporter configuration through ReportConfiguration if special
reporting is required.
api/v1beta2/runner_types.go (3)

185-186: ⚠️ Potential issue | 🟡 Minor

Duplicate json struct tags on KubernetesDNSConfigOption fields.

Both Name and Value fields have triplicate json tags.

Suggested fix
-	Name  string  `toml:"name" json:"name" json:"name"`
-	Value *string `toml:"value,omitempty" json:"value,omitempty" json:"value,omitempty"`
+	Name  string  `toml:"name" json:"name"`
+	Value *string `toml:"value,omitempty" json:"value,omitempty"`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v1beta2/runner_types.go` around lines 185 - 186, The struct tags for the
KubernetesDNSConfigOption fields (Name and Value) have duplicate json tags;
update the struct definition (KubernetesDNSConfigOption) to remove the repeated
`json` tags so each field only has one `toml` tag and a single `json` tag (e.g.,
`Name string  `toml:"name" json:"name"` and `Value *string
`toml:"value,omitempty" json:"value,omitempty``), ensuring no duplicate tag keys
remain.

276-277: ⚠️ Potential issue | 🟡 Minor

Duplicate json struct tags in KubernetesNodeAffinity.

Multiple fields have duplicate json tags that should be deduplicated.

Suggested fix
-	RequiredDuringSchedulingIgnoredDuringExecution  *NodeSelector             `toml:"required_during_scheduling_ignored_during_execution,omitempty" json:"required_during_scheduling_ignored_during_execution,omitempty" json:"required_during_scheduling_ignored_during_execution"`
-	PreferredDuringSchedulingIgnoredDuringExecution []PreferredSchedulingTerm `toml:"preferred_during_scheduling_ignored_during_execution,omitempty" json:"preferred_during_scheduling_ignored_during_execution,omitempty" json:"preferred_during_scheduling_ignored_during_execution"`
+	RequiredDuringSchedulingIgnoredDuringExecution  *NodeSelector             `toml:"required_during_scheduling_ignored_during_execution,omitempty" json:"required_during_scheduling_ignored_during_execution,omitempty"`
+	PreferredDuringSchedulingIgnoredDuringExecution []PreferredSchedulingTerm `toml:"preferred_during_scheduling_ignored_during_execution,omitempty" json:"preferred_during_scheduling_ignored_during_execution,omitempty"`

Note: Similar duplicate tags exist in KubernetesPodAffinity (lines 281-282), KubernetesPodAntiAffinity (lines 286-287), NodeSelector (line 330), PreferredSchedulingTerm (lines 334-335), WeightedPodAffinityTerm (lines 339-340), NodeSelectorTerm (lines 344-345), NodeSelectorRequirement (lines 349-351), PodAffinityTerm (lines 355-358), and LabelSelector (lines 362-363).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v1beta2/runner_types.go` around lines 276 - 277, Duplicate json struct
tags are present in KubernetesNodeAffinity (fields
RequiredDuringSchedulingIgnoredDuringExecution and
PreferredDuringSchedulingIgnoredDuringExecution); remove the repeated
`json:"..."` entries so each field tag only contains one json key (and keep the
toml and json tags once each), and apply the same deduplication to the other
affected types: KubernetesPodAffinity, KubernetesPodAntiAffinity, NodeSelector,
PreferredSchedulingTerm, WeightedPodAffinityTerm, NodeSelectorTerm,
NodeSelectorRequirement, PodAffinityTerm, and LabelSelector; locate the structs
by their type names and update their field tags to have unique, single
`json:"..."` tags.

168-168: ⚠️ Potential issue | 🟡 Minor

Duplicate json struct tag will cause unpredictable behavior.

The Volumes field has duplicate json tags which may cause marshaling/unmarshaling issues.

Suggested fix
-	Volumes                                           *KubernetesVolumes                  `toml:"volumes,omitempty" json:"volumes,omitempty" json:"volumes,omitempty"`
+	Volumes                                           *KubernetesVolumes                  `toml:"volumes,omitempty" json:"volumes,omitempty"`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v1beta2/runner_types.go` at line 168, The Volumes struct field in
runner_types.go has a duplicated json struct tag which can break marshaling;
remove the duplicate so the field reads with a single json tag (e.g., keep
`json:"volumes,omitempty"`) and keep the toml tag as-is; locate the Volumes
field declaration and the KubernetesVolumes type to verify no other duplicate
tags exist and run `go vet`/tests afterwards.
api/v1beta2/webhook_test.go (1)

35-41: ⚠️ Potential issue | 🔴 Critical

Test references non-existent types RegistrationConfig and RegisterNewRunnerOptions — will fail to compile.

The v1beta2 RunnerSpec (lines 30, 33 in runner_types.go) uses Token *string and TokenSecret string directly. The wrapper types used in the test no longer exist.

Suggested fix
 			Spec: RunnerSpec{
-				RegistrationConfig: RegisterNewRunnerOptions{
-					Token:   pointer.StringPtr("rYwg6EogqxSuvsFCVvAT"),
-					TagList: []string{"testing-runner-operator"},
-				},
+				Token: pointer.String("rYwg6EogqxSuvsFCVvAT"),
 			},

The TagList field has no equivalent in v1beta2 RunnerSpec (tags are tracked in RunnerStatus.LastRegistrationTags).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v1beta2/webhook_test.go` around lines 35 - 41, The test currently uses
removed wrapper types RegistrationConfig and RegisterNewRunnerOptions and a
nonexistent TagList field; update the test in webhook_test.go to construct
RunnerSpec directly using the v1beta2 fields (e.g., set Token or TokenSecret on
RunnerSpec instead of RegistrationConfig/ RegisterNewRunnerOptions) remove the
TagList usage, and if the test needs to assert tags populate status, set
RunnerStatus.LastRegistrationTags on the test object accordingly so the test
compiles against the v1beta2 RunnerSpec/RunnerStatus shape.
internal/api/gitlab_test.go (1)

10-21: ⚠️ Potential issue | 🟠 Major

Test currently passes even when registration fails.

Line 11 and Line 12 discard errors (cl, _ and _, _ = ...), so this test can silently succeed without validating behavior.

Suggested fix
 func TestGitlabApi_Register(t *testing.T) {
-	cl, _ := NewGitlabClient("9Bo36Uxwx6ay-cR-bCLh", "")
-	_, _ = cl.Register(v1beta2.RegisterNewRunnerOptions{
+	cl, err := NewGitlabClient("9Bo36Uxwx6ay-cR-bCLh", "")
+	if err != nil {
+		t.Fatalf("failed to create gitlab client: %v", err)
+	}
+
+	_, err = cl.Register(v1beta2.RegisterNewRunnerOptions{
 		Token:          pointer.StringPtr("9Bo36Uxwx6ay-cR-bCLh"),
 		Description:    nil,
 		Info:           nil,
 		Active:         nil,
 		Locked:         nil,
 		RunUntagged:    nil,
 		TagList:        []string{"gitlab-testing-operator"},
 		MaximumTimeout: nil,
 	})
+	if err != nil {
+		t.Fatalf("failed to register runner: %v", err)
+	}
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/gitlab_test.go` around lines 10 - 21, The test
TestGitlabApi_Register is ignoring errors from NewGitlabClient and Register;
update it to capture and assert the returned errors instead of discarding them:
check the error from NewGitlabClient("9Bo36Uxwx6ay-cR-bCLh", "") and fail the
test if non-nil, then call cl.Register(...) and assert the returned error/result
(using t.Fatalf/t.Fatalf or your test helper) so the test fails when
registration fails; reference the functions NewGitlabClient and Register in the
TestGitlabApi_Register test.
main.go (1)

53-76: ⚠️ Potential issue | 🟡 Minor

Unused metricsAddr variable after removing MetricsBindAddress option.

The metricsAddr flag is defined at line 57 but is never used since MetricsBindAddress was removed from the manager options. Either remove the flag definition or restore the metrics configuration.

Proposed fix (if metrics should be enabled)
 	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
 		Scheme:                 scheme,
+		MetricsBindAddress:     metricsAddr,
 		HealthProbeBindAddress: probeAddr,
 		LeaderElection:         enableLeaderElection,
 		LeaderElectionID:       "e47991d1.k8s.alekc.dev",
 	})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@main.go` around lines 53 - 76, The flag metricsAddr (set via flag.StringVar)
is defined but never used after removing MetricsBindAddress; either remove the
flag definition (delete the metricsAddr variable and its flag.StringVar call) or
restore metrics binding by passing MetricsBindAddress: metricsAddr into the
ctrl.NewManager options (the ctrl.NewManager call in main.go) so the value is
actually used at startup.
🧹 Nitpick comments (14)
Makefile (2)

122-133: Remove commented-out code block.

This commented alternative implementation of go-install-tool adds noise. If it's not needed, remove it; if it's for reference, add it to documentation instead.

Suggested fix
-#define go-install-tool
-#@[ -f $(1) ] || { \
-#echo "Installing $(2) in $(1)";\
-#set -e ;\
-#TMP_DIR=$$(mktemp -d) ;\
-#cd $$TMP_DIR ;\
-# go mod init tmp ;\
-#echo "Downloading $(2)" ;\
-#GOBIN=$(PROJECT_DIR)/bin go install $(2) ;\
-#rm -rf $$TMP_DIR ;\
-#}
-#endef
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Makefile` around lines 122 - 133, Remove the large commented-out alternative
implementation of the macro identified by "define go-install-tool" from the
Makefile: delete the entire commented block (lines beginning with "#define
go-install-tool" through "#endef") so the file contains only the active recipe;
if preserving the alternate approach is desired, move that content into project
documentation (e.g., CONTRIBUTING.md) rather than leaving it commented in the
Makefile.

31-31: Consider adding .PHONY declarations for standard targets.

Static analysis flagged missing .PHONY declarations for all, test, and clean targets. While not strictly required, this is a Makefile best practice.

Suggested addition after line 31
.PHONY: all build test clean tidy manifests generate fmt vet
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Makefile` at line 31, Add a .PHONY declaration listing the Makefile targets
to avoid conflicts with same-named files: include a line declaring .PHONY for
targets such as all, build, test, clean, tidy, manifests, generate, fmt, and vet
(e.g., add a single ".PHONY: all build test clean tidy manifests generate fmt
vet" entry near the top, adjacent to the existing "all: build" target) so make
treats these as phony targets rather than filenames.
api/v1beta2/multirunner_types.go (1)

23-32: MultiRunner types appear to be scaffolded placeholders.

The MultiRunnerSpec contains only a placeholder Foo field, and MultiRunnerStatus is empty with a TODO comment. This seems like incomplete implementation that may have been scaffolded but not yet developed.

Consider either:

  1. Implementing the actual spec/status fields before merging
  2. Removing this file if not ready for this PR
  3. Adding a clear TODO/FIXME comment explaining the planned implementation

Would you like me to help design the MultiRunnerSpec and MultiRunnerStatus fields based on common multi-runner patterns?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v1beta2/multirunner_types.go` around lines 23 - 32, The MultiRunner types
are scaffolding placeholders: update the MultiRunnerSpec (currently containing
only Foo) and MultiRunnerStatus (currently empty) to either implement real
fields or explicitly mark as intentional; replace or remove Foo in
MultiRunnerSpec and add concrete observed-state fields in MultiRunnerStatus (or
remove the file if not ready), or at minimum add a clear TODO/FIXME comment
explaining the planned fields and next steps so reviewers know this is
intentional; locate and modify the MultiRunnerSpec and MultiRunnerStatus
declarations to apply your chosen fix.
api/v1beta2/webhook_suite_test.go (1)

102-102: Use Metrics: metricsserver.Options{BindAddress: "0"} for metrics configuration.

In controller-runtime v0.16.0, MetricsBindAddress was removed. Update to the newer Metrics field with metricsserver.Options:

import metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"

Metrics: metricsserver.Options{BindAddress: "0"}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v1beta2/webhook_suite_test.go` at line 102, Replace the removed
MetricsBindAddress usage with the new Metrics field: change the struct entry
MetricsBindAddress: "0" to Metrics: metricsserver.Options{BindAddress: "0"} and
add the import alias metricsserver for
"sigs.k8s.io/controller-runtime/pkg/metrics/server"; update any references to
MetricsBindAddress in the manager options (e.g., where MetricsBindAddress is
set) to use Metrics instead so the managerOptions/ctrl.Options object compiles
with controller-runtime v0.16.0.
api/v1beta2/runner_types.go (1)

406-406: Migrate to ptr.To() instead of pointer.BoolPtr.

The entire k8s.io/utils/pointer package is deprecated in favor of k8s.io/utils/ptr. Replace pointer.BoolPtr(true) with ptr.To(true).

Suggested fix
-	"k8s.io/utils/pointer"
+	"k8s.io/utils/ptr"
-		Controller:         pointer.BoolPtr(true),
+		Controller:         ptr.To(true),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v1beta2/runner_types.go` at line 406, Replace the deprecated
pointer.BoolPtr usage: update the Controller field assignment (Controller:
pointer.BoolPtr(true)) to use ptr.To(true) and ensure the import is switched
from "k8s.io/utils/pointer" to "k8s.io/utils/ptr"; locate usages in the same
file (e.g., variable/struct where Controller is set) and update any other
pointer.BoolPtr/Pointer helpers to the corresponding ptr.To calls so imports and
references remain consistent.
config/samples/gitlab_v1beta1_runner.yaml (1)

1-1: Rename sample file to match the new API version.

Line 1 now uses v1beta2, but the filename still says gitlab_v1beta1_runner.yaml, which is misleading for users.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/samples/gitlab_v1beta1_runner.yaml` at line 1, The sample file name
gitlab_v1beta1_runner.yaml is inconsistent with its apiVersion v1beta2; rename
the sample file to reflect the new API version (e.g.,
gitlab_v1beta2_runner.yaml) and update any references to
gitlab_v1beta1_runner.yaml in docs or manifests so the filename matches the
apiVersion declared in the file.
internal/api/gitlab.go (1)

24-45: Large block of commented-out code.

If the Register method is permanently removed in favor of Kubernetes Secrets-based authentication, consider removing this commented code entirely. Keeping extensive commented code hurts readability and can cause confusion during future maintenance.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/gitlab.go` around lines 24 - 45, Remove the large commented-out
Register method block (the commented function named Register and its
convertedConfig logic) from the gitlabApi implementation to improve readability;
if you still need its behavior, restore it as a proper method on gitlabApi
(uncomment and adapt to current kubernetes-secrets auth flow) otherwise delete
the entire commented block to avoid confusion.
controllers/suite_test.go (1)

93-98: Commented-out mock registration logic.

The OnRegister callback is commented out, aligning with the removal of Register from the GitLab API interface. Consider removing this dead code entirely if registration functionality is being permanently removed, or add a TODO comment if it's temporary.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controllers/suite_test.go` around lines 93 - 98, The commented-out OnRegister
mock in suite_test.go (the block referencing OnRegister and the Register-related
logic) is dead code after Register was removed from the GitLab API interface;
either delete that entire commented block to remove noise or replace it with a
short TODO comment explaining why registration was removed and when/if it should
be restored (reference the OnRegister callback and any tests that previously
relied on Register to ensure nothing else expects it).
main.go (1)

96-103: Commented-out MultiRunner controller setup.

The MultiRunner controller is commented out. If this is intentional for a staged rollout, consider adding a brief comment explaining when it will be enabled, or remove the dead code if MultiRunner is not yet ready.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@main.go` around lines 96 - 103, The MultiRunner controller setup block for
MultiRunnerReconciler (the commented-out call to
(&controllers.MultiRunnerReconciler{ Client: mgr.GetClient(), Scheme:
mgr.GetScheme() }).SetupWithManager(mgr)) is left commented; either remove this
dead code or re-enable it with a short inline rationale. Update the file to
either (a) delete the commented block if MultiRunner is not intended to be
added, or (b) uncomment and restore the SetupWithManager(mgr) call and error
handling (using setupLog.Error and os.Exit(1)) if the controller should run, or
(c) keep it commented but add a one-line comment explaining the rollout/feature
flag and when to enable MultiRunner so reviewers understand the intent.
internal/api/mocked_client.go (1)

9-18: Remove commented-out code or document why it's retained.

The OnRegister field and Register method are fully commented out. If the registration flow is permanently removed in v1beta2, delete the commented code to maintain clarity. If it's temporarily disabled for reference, add a TODO comment explaining when it should be removed.

♻️ Suggested cleanup
 type MockedGitlabClient struct {
-	//OnRegister       func(config v1beta2.RegisterNewRunnerOptions) (string, error)
 	OnDeleteByTokens func(token string) (*gitlab.Response, error)
 }

-//func (m *MockedGitlabClient) Register(config v1beta2.RegisterNewRunnerOptions) (string, error) {
-//	if m.OnRegister == nil {
-//		return "", errors.New("call is not defined")
-//	}
-//	return m.OnRegister(config)
-//}
-
 func (m *MockedGitlabClient) DeleteByToken(token string) (*gitlab.Response, error) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/mocked_client.go` around lines 9 - 18, The file contains fully
commented-out symbols OnRegister and the Register method in the
MockedGitlabClient; either delete those commented blocks to clean up dead code
or replace them with a short TODO comment that explains why the registration
flow was disabled (reference v1beta2), who owns the decision, and an intended
removal or re-enable date/condition; update the comment near the
MockedGitlabClient declaration to reflect that choice so reviewers know whether
this is permanent removal or temporary retention.
controllers/multirunner_controller.go (1)

49-55: Stub implementation: consider adding basic resource fetch logic.

The reconciler is currently a no-op stub. At minimum, consider fetching the MultiRunner resource to validate the controller is wired correctly and to prevent reconciliation loops on non-existent resources:

♻️ Suggested minimal implementation
 func (r *MultiRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
-	_ = log.FromContext(ctx)
+	log := log.FromContext(ctx)
 
 	// TODO(user): your logic here
+	var multiRunner gitlabv1beta2.MultiRunner
+	if err := r.Get(ctx, req.NamespacedName, &multiRunner); err != nil {
+		// Ignore not-found errors (resource deleted)
+		return ctrl.Result{}, client.IgnoreNotFound(err)
+	}
+
+	log.Info("Reconciling MultiRunner", "name", multiRunner.Name)
 
 	return ctrl.Result{}, nil
 }

Would you like me to help implement the full reconciliation logic for MultiRunner, or open an issue to track this?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controllers/multirunner_controller.go` around lines 49 - 55, The Reconcile
method is a no-op; fetch the referenced MultiRunner resource at the start of
Reconcile to validate wiring and avoid reconciling deleted objects: call
r.Get(ctx, req.NamespacedName, &multiRunner) (where multiRunner is a
multirunnerv1alpha1.MultiRunner), if apierrors.IsNotFound(err) return
ctrl.Result{}, nil, on other errors return ctrl.Result{}, err and log the error
via the controller logger; this ensures MultiRunnerReconciler.Reconcile properly
handles missing resources and surfaces real failures.
config/crd/bases/gitlab.k8s.alekc.dev_multirunners.yaml (1)

34-39: Consider documenting the stub spec or implementing planned fields.

MultiRunnerSpec currently contains only a placeholder foo string field. If this is intentional for incremental development, add a comment in api/v1beta2/multirunner_types.go explaining the planned spec fields to guide future implementation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/crd/bases/gitlab.k8s.alekc.dev_multirunners.yaml` around lines 34 -
39, The CRD spec currently exposes only a placeholder `foo` field for
`MultiRunnerSpec`; update the `MultiRunnerSpec` declaration in
api/v1beta2/multirunner_types.go to either replace `foo` with the intended
fields or add a clear doc comment above the `MultiRunnerSpec` type (and any
placeholder `foo` field) describing the planned/spec rationale and which fields
will be added later (e.g., runner configuration, image, replicas), so future
implementers know this is intentional and what to implement next.
controllers/runner_controller.go (2)

45-45: Misleading import alias: gitlabv1beta1 imports v1beta2.

The alias name suggests v1beta1 but actually imports v1beta2, which could confuse future maintainers.

♻️ Proposed fix
-	gitlabv1beta1 "gitlab.k8s.alekc.dev/api/v1beta2"
+	gitlabv1beta2 "gitlab.k8s.alekc.dev/api/v1beta2"

This would require updating all references throughout the file from gitlabv1beta1 to gitlabv1beta2.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controllers/runner_controller.go` at line 45, The import alias gitlabv1beta1
is incorrect for the imported package gitlab.k8s.alekc.dev/api/v1beta2; rename
the alias to gitlabv1beta2 in the import declaration and update every reference
in this file that uses gitlabv1beta1 (e.g., types, constructors, methods) to use
gitlabv1beta2 instead so the alias matches the actual package version and avoids
confusion.

147-162: Remove commented-out code blocks.

Multiple large blocks of commented-out code exist throughout this file. This creates maintenance burden and reduces readability. Version control preserves the history if the code needs to be restored.

If this is a transitional state, consider adding a TODO comment explaining when the code will be fully removed, or remove it now and reference the commit/PR if needed later.

Also applies to: 338-363, 368-382

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controllers/runner_controller.go` around lines 147 - 162, Remove the large
commented-out blocks in controllers/runner_controller.go that reference
runnerObj and the registration flow (including the conditional that checks
AuthenticationToken, LastRegistrationToken, LastRegistrationTags and the calls
to RemoveRunnerFromGitlab and RegisterNewRunnerOnGitlab); either delete these
dead code blocks or replace them with a short TODO comment explaining why
they’re retained temporarily, making sure to keep the active logic intact and
not change any identifiers or function calls elsewhere.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@config/manager/kustomization.yaml`:
- Line 11: The Kustomization manifest uses an invalid apiVersion value
"kustomize.config.k8s.io/v1beta2"; update the apiVersion for the Kustomization
resource to the supported value "kustomize.config.k8s.io/v1beta1" so kustomize
build will succeed. Locate the manifest that defines kind: Kustomization and
replace the apiVersion symbol (currently "kustomize.config.k8s.io/v1beta2") with
"kustomize.config.k8s.io/v1beta1", then re-run kustomize build to verify the
change.

In `@config/samples/gitlab_v1beta1_multirunner.yaml`:
- Line 8: Fix the typo in the label key by changing
"app.kuberentes.io/managed-by" to the correct "app.kubernetes.io/managed-by" in
the YAML sample (update the label string used in the config/samples file);
ensure the manifest uses "app.kubernetes.io/managed-by" consistently wherever
"app.kuberentes.io/managed-by" appears.
- Line 1: Update the sample's apiVersion from gitlab.k8s.alekc.dev/v1beta1 to
gitlab.k8s.alekc.dev/v1beta2 so it matches the CRD base and Go types;
specifically change the apiVersion field in the sample (currently
"gitlab.k8s.alekc.dev/v1beta1") to "gitlab.k8s.alekc.dev/v1beta2" to align with
the CRD base named gitlab.k8s.alekc.dev_multirunners.yaml and the v1beta2 Go
types.

In `@config/webhook/manifests.yaml`:
- Around line 7-9: Remove the invalid "v1beta2" entry from the
admissionReviewVersions lists in both the MutatingWebhookConfiguration and
ValidatingWebhookConfiguration and ensure only supported AdmissionReview
versions ("v1" and/or "v1beta1") remain; keep rules.apiVersions as-is for your
custom resource (v1beta2) but update the admissionReviewVersions fields to not
include v1beta2.

In `@controllers/runner_controller_test.go`:
- Around line 227-263: The test table references caseTagsChanged and
caseRegistrationTokenChanged but those functions no longer set tc.CheckRunner,
leaving tc.CheckRunner nil and causing a panic when
tc.CheckRunner(createdRunner) is invoked; fix by either removing the entries for
caseTagsChanged and caseRegistrationTokenChanged from the test table or restore
a no-op CheckRunner inside each function (e.g., set tc.CheckRunner = func(runner
*v1beta2.Runner) {}), ensuring tc.CheckRunner is always non-nil before the
unconditional call in the test harness.

In `@controllers/runner_controller.go`:
- Around line 164-173: The code dereferences runnerObj.Spec.Token before
checking nil, risking a panic; change the logic in the authentication-token
block so you first check if runnerObj.Spec.Token is non-nil and non-empty, and
only then assign *runnerObj.Spec.Token to runnerObj.Status.AuthenticationToken;
otherwise call r.getTokenFromSecret(ctx, runnerObj, logger) (as currently done)
and assign its returned token to runnerObj.Status.AuthenticationToken,
preserving the existing error logging and return of
resultRequeueAfterDefaultTimeout on error.
- Around line 204-226: The function getTokenFromSecret on RunnerReconciler
declares an unused parameter log logr.Logger; remove the unused parameter from
the function signature and update all call sites to stop passing a logger (or
pass only ctx and runnerObject) so the function becomes getTokenFromSecret(ctx
context.Context, runnerObject *gitlabv1beta1.Runner) (string, error); ensure
references to getTokenFromSecret in the reconciler and tests are adjusted to the
new signature.

In `@controllers/suite_test.go`:
- Line 35: The import alias gitlabv1beta1 incorrectly refers to the v1beta2
package; rename the alias to match the actual package version (e.g.,
gitlabv1beta2) in the import declaration and update all usages that reference
the old alias (such as the symbol used around the test helper/struct reference)
to the new alias so types/functions resolve to the correct v1beta2 package.

In `@go.mod`:
- Line 3: go.mod declares "go 1.17" but the Makefile tidy target uses
"-compat=1.21", causing a version mismatch; update the module Go version to
match the Makefile by changing the go directive in go.mod from 1.17 to 1.21,
then run go mod tidy (or the Makefile tidy target) to refresh go.sum and ensure
module resolution aligns with the Makefile's "-compat=1.21" setting.
- Line 115: Update the indirect dependency golang.org/x/crypto from v0.14.0 to a
patched release (preferably v0.49.0 or at least v0.45.0) to address multiple
CVEs; run `go get -u golang.org/x/crypto@v0.49.0` (or `go get -u
golang.org/x/crypto`), then `go mod tidy` to update go.mod/go.sum and re-run
tests/build to ensure nothing breaks—look for the module line
"golang.org/x/crypto" in go.mod to verify the version change.
- Around line 38-43: The listed Docker modules are transitive; run go mod graph
(or inspect go.sum) to find which direct module (e.g., k8s.io/* or
sigs.k8s.io/controller-runtime) is pulling in github.com/docker/docker and
github.com/docker/cli, then update that direct dependency to a version that
vendors/depends on a patched Docker release or remove/replace it if Docker
functionality is not needed; if an upstream update isn't available, add a go.mod
replace for the problematic docker modules to a patched commit/version or swap
the direct dependency for an alternative that doesn't transitively depend on
docker (look for usages in your codebase to ensure no direct imports of docker
packages).
- Line 119: The go.mod entry pins golang.org/x/net at v0.16.0 which is
vulnerable; update the module requirement for golang.org/x/net to v0.52.0 (or
later) and refresh modules: change the version token for golang.org/x/net in
go.mod to v0.52.0, then run the Go tooling (e.g., go get
golang.org/x/net@v0.52.0 and go mod tidy) to update go.sum and module graph, and
finally run tests/builds to verify there are no regressions.
- Line 133: Update the grpc dependency in go.mod from google.golang.org/grpc
v1.55.0 to at least v1.79.3 to address the listed CVEs; after changing the
version string for the module "google.golang.org/grpc" run go get
google.golang.org/grpc@v1.79.3 (or go get ./... with the version) and then go
mod tidy to update go.sum, rebuild and run tests to ensure no regressions;
confirm any code using grpc APIs still compiles against the new version (search
for imports referencing google.golang.org/grpc to locate affected files).

In `@internal/validate/validate.go`:
- Line 7: The import alias is incorrect: change the import alias from
gitlabv1beta1 to gitlabv1beta2 (i.e., import gitlab.k8s.alekc.dev/api/v1beta2 as
gitlabv1beta2) and update all references that use gitlabv1beta1.Runner to
gitlabv1beta2.Runner (ensure occurrences in the validate package where Runner is
referenced are updated accordingly).

In `@PROJECT`:
- Around line 27-28: Update the API version references in the PROJECT file from
v1beta1 to v1beta2 so scaffolding matches the actual CRD types; specifically
change path: gitlab.k8s.alekc.dev/api/v1beta1 to
gitlab.k8s.alekc.dev/api/v1beta2 and version: v1beta1 to v1beta2 so Runner and
MultiRunner types (declared under package v1beta2 in api/v1beta2/) are correctly
referenced by the project metadata.

---

Outside diff comments:
In `@api/v1beta2/runner_types.go`:
- Around line 185-186: The struct tags for the KubernetesDNSConfigOption fields
(Name and Value) have duplicate json tags; update the struct definition
(KubernetesDNSConfigOption) to remove the repeated `json` tags so each field
only has one `toml` tag and a single `json` tag (e.g., `Name string 
`toml:"name" json:"name"` and `Value *string `toml:"value,omitempty"
json:"value,omitempty``), ensuring no duplicate tag keys remain.
- Around line 276-277: Duplicate json struct tags are present in
KubernetesNodeAffinity (fields RequiredDuringSchedulingIgnoredDuringExecution
and PreferredDuringSchedulingIgnoredDuringExecution); remove the repeated
`json:"..."` entries so each field tag only contains one json key (and keep the
toml and json tags once each), and apply the same deduplication to the other
affected types: KubernetesPodAffinity, KubernetesPodAntiAffinity, NodeSelector,
PreferredSchedulingTerm, WeightedPodAffinityTerm, NodeSelectorTerm,
NodeSelectorRequirement, PodAffinityTerm, and LabelSelector; locate the structs
by their type names and update their field tags to have unique, single
`json:"..."` tags.
- Line 168: The Volumes struct field in runner_types.go has a duplicated json
struct tag which can break marshaling; remove the duplicate so the field reads
with a single json tag (e.g., keep `json:"volumes,omitempty"`) and keep the toml
tag as-is; locate the Volumes field declaration and the KubernetesVolumes type
to verify no other duplicate tags exist and run `go vet`/tests afterwards.

In `@api/v1beta2/webhook_suite_test.go`:
- Around line 55-58: The test still references the removed
printer.NewlineReporter via RunSpecsWithDefaultAndCustomReporters which is
undefined; replace the call to RunSpecsWithDefaultAndCustomReporters(t, "Webhook
Suite", []Reporter{printer.NewlineReporter{}}) with a Ginkgo v2 compatible
RunSpecs invocation (e.g., call RunSpecs(t, "Webhook Suite") or configure
reporter behavior via ReportConfiguration) so that the undefined symbol
printer.NewlineReporter is removed and the test compiles; update the test
function that calls RunSpecsWithDefaultAndCustomReporters to use RunSpecs and
adjust any reporter configuration through ReportConfiguration if special
reporting is required.

In `@api/v1beta2/webhook_test.go`:
- Around line 35-41: The test currently uses removed wrapper types
RegistrationConfig and RegisterNewRunnerOptions and a nonexistent TagList field;
update the test in webhook_test.go to construct RunnerSpec directly using the
v1beta2 fields (e.g., set Token or TokenSecret on RunnerSpec instead of
RegistrationConfig/ RegisterNewRunnerOptions) remove the TagList usage, and if
the test needs to assert tags populate status, set
RunnerStatus.LastRegistrationTags on the test object accordingly so the test
compiles against the v1beta2 RunnerSpec/RunnerStatus shape.

In `@internal/api/gitlab_test.go`:
- Around line 10-21: The test TestGitlabApi_Register is ignoring errors from
NewGitlabClient and Register; update it to capture and assert the returned
errors instead of discarding them: check the error from
NewGitlabClient("9Bo36Uxwx6ay-cR-bCLh", "") and fail the test if non-nil, then
call cl.Register(...) and assert the returned error/result (using
t.Fatalf/t.Fatalf or your test helper) so the test fails when registration
fails; reference the functions NewGitlabClient and Register in the
TestGitlabApi_Register test.

In `@main.go`:
- Around line 53-76: The flag metricsAddr (set via flag.StringVar) is defined
but never used after removing MetricsBindAddress; either remove the flag
definition (delete the metricsAddr variable and its flag.StringVar call) or
restore metrics binding by passing MetricsBindAddress: metricsAddr into the
ctrl.NewManager options (the ctrl.NewManager call in main.go) so the value is
actually used at startup.

In `@README.md`:
- Around line 29-40: Update the README examples that target apiVersion v1beta2
to replace the removed registration_config field with the new token/token_secret
fields: locate examples named "minimum configuration", "secret-based token", and
"volumes" (and any snippets containing registration_config) and change them to
specify either token: "<literal-token>" for inline tokens or token_secret: {
name: "<k8s-secret-name>", key: "<key>" } for secret-based tokens; ensure any
explanatory text and example YAML keys mention token/token_secret instead of
registration_config so the examples match the v1beta2 API.
- Around line 56-65: The README example uses the old registration_config
structure; update the v1beta2 example so it uses the new Runner spec fields:
replace spec.registration_config with spec.registration, rename tag_list to
tags, and keep the token under registration.token (ensure field names match the
v1beta2 API for Runner). Update the sample metadata (apiVersion:
gitlab.k8s.alekc.dev/v1beta2, kind: Runner) to reflect those new field names so
the example validates against v1beta2.

---

Nitpick comments:
In `@api/v1beta2/multirunner_types.go`:
- Around line 23-32: The MultiRunner types are scaffolding placeholders: update
the MultiRunnerSpec (currently containing only Foo) and MultiRunnerStatus
(currently empty) to either implement real fields or explicitly mark as
intentional; replace or remove Foo in MultiRunnerSpec and add concrete
observed-state fields in MultiRunnerStatus (or remove the file if not ready), or
at minimum add a clear TODO/FIXME comment explaining the planned fields and next
steps so reviewers know this is intentional; locate and modify the
MultiRunnerSpec and MultiRunnerStatus declarations to apply your chosen fix.

In `@api/v1beta2/runner_types.go`:
- Line 406: Replace the deprecated pointer.BoolPtr usage: update the Controller
field assignment (Controller: pointer.BoolPtr(true)) to use ptr.To(true) and
ensure the import is switched from "k8s.io/utils/pointer" to "k8s.io/utils/ptr";
locate usages in the same file (e.g., variable/struct where Controller is set)
and update any other pointer.BoolPtr/Pointer helpers to the corresponding ptr.To
calls so imports and references remain consistent.

In `@api/v1beta2/webhook_suite_test.go`:
- Line 102: Replace the removed MetricsBindAddress usage with the new Metrics
field: change the struct entry MetricsBindAddress: "0" to Metrics:
metricsserver.Options{BindAddress: "0"} and add the import alias metricsserver
for "sigs.k8s.io/controller-runtime/pkg/metrics/server"; update any references
to MetricsBindAddress in the manager options (e.g., where MetricsBindAddress is
set) to use Metrics instead so the managerOptions/ctrl.Options object compiles
with controller-runtime v0.16.0.

In `@config/crd/bases/gitlab.k8s.alekc.dev_multirunners.yaml`:
- Around line 34-39: The CRD spec currently exposes only a placeholder `foo`
field for `MultiRunnerSpec`; update the `MultiRunnerSpec` declaration in
api/v1beta2/multirunner_types.go to either replace `foo` with the intended
fields or add a clear doc comment above the `MultiRunnerSpec` type (and any
placeholder `foo` field) describing the planned/spec rationale and which fields
will be added later (e.g., runner configuration, image, replicas), so future
implementers know this is intentional and what to implement next.

In `@config/samples/gitlab_v1beta1_runner.yaml`:
- Line 1: The sample file name gitlab_v1beta1_runner.yaml is inconsistent with
its apiVersion v1beta2; rename the sample file to reflect the new API version
(e.g., gitlab_v1beta2_runner.yaml) and update any references to
gitlab_v1beta1_runner.yaml in docs or manifests so the filename matches the
apiVersion declared in the file.

In `@controllers/multirunner_controller.go`:
- Around line 49-55: The Reconcile method is a no-op; fetch the referenced
MultiRunner resource at the start of Reconcile to validate wiring and avoid
reconciling deleted objects: call r.Get(ctx, req.NamespacedName, &multiRunner)
(where multiRunner is a multirunnerv1alpha1.MultiRunner), if
apierrors.IsNotFound(err) return ctrl.Result{}, nil, on other errors return
ctrl.Result{}, err and log the error via the controller logger; this ensures
MultiRunnerReconciler.Reconcile properly handles missing resources and surfaces
real failures.

In `@controllers/runner_controller.go`:
- Line 45: The import alias gitlabv1beta1 is incorrect for the imported package
gitlab.k8s.alekc.dev/api/v1beta2; rename the alias to gitlabv1beta2 in the
import declaration and update every reference in this file that uses
gitlabv1beta1 (e.g., types, constructors, methods) to use gitlabv1beta2 instead
so the alias matches the actual package version and avoids confusion.
- Around line 147-162: Remove the large commented-out blocks in
controllers/runner_controller.go that reference runnerObj and the registration
flow (including the conditional that checks AuthenticationToken,
LastRegistrationToken, LastRegistrationTags and the calls to
RemoveRunnerFromGitlab and RegisterNewRunnerOnGitlab); either delete these dead
code blocks or replace them with a short TODO comment explaining why they’re
retained temporarily, making sure to keep the active logic intact and not change
any identifiers or function calls elsewhere.

In `@controllers/suite_test.go`:
- Around line 93-98: The commented-out OnRegister mock in suite_test.go (the
block referencing OnRegister and the Register-related logic) is dead code after
Register was removed from the GitLab API interface; either delete that entire
commented block to remove noise or replace it with a short TODO comment
explaining why registration was removed and when/if it should be restored
(reference the OnRegister callback and any tests that previously relied on
Register to ensure nothing else expects it).

In `@internal/api/gitlab.go`:
- Around line 24-45: Remove the large commented-out Register method block (the
commented function named Register and its convertedConfig logic) from the
gitlabApi implementation to improve readability; if you still need its behavior,
restore it as a proper method on gitlabApi (uncomment and adapt to current
kubernetes-secrets auth flow) otherwise delete the entire commented block to
avoid confusion.

In `@internal/api/mocked_client.go`:
- Around line 9-18: The file contains fully commented-out symbols OnRegister and
the Register method in the MockedGitlabClient; either delete those commented
blocks to clean up dead code or replace them with a short TODO comment that
explains why the registration flow was disabled (reference v1beta2), who owns
the decision, and an intended removal or re-enable date/condition; update the
comment near the MockedGitlabClient declaration to reflect that choice so
reviewers know whether this is permanent removal or temporary retention.

In `@main.go`:
- Around line 96-103: The MultiRunner controller setup block for
MultiRunnerReconciler (the commented-out call to
(&controllers.MultiRunnerReconciler{ Client: mgr.GetClient(), Scheme:
mgr.GetScheme() }).SetupWithManager(mgr)) is left commented; either remove this
dead code or re-enable it with a short inline rationale. Update the file to
either (a) delete the commented block if MultiRunner is not intended to be
added, or (b) uncomment and restore the SetupWithManager(mgr) call and error
handling (using setupLog.Error and os.Exit(1)) if the controller should run, or
(c) keep it commented but add a one-line comment explaining the rollout/feature
flag and when to enable MultiRunner so reviewers understand the intent.

In `@Makefile`:
- Around line 122-133: Remove the large commented-out alternative implementation
of the macro identified by "define go-install-tool" from the Makefile: delete
the entire commented block (lines beginning with "#define go-install-tool"
through "#endef") so the file contains only the active recipe; if preserving the
alternate approach is desired, move that content into project documentation
(e.g., CONTRIBUTING.md) rather than leaving it commented in the Makefile.
- Line 31: Add a .PHONY declaration listing the Makefile targets to avoid
conflicts with same-named files: include a line declaring .PHONY for targets
such as all, build, test, clean, tidy, manifests, generate, fmt, and vet (e.g.,
add a single ".PHONY: all build test clean tidy manifests generate fmt vet"
entry near the top, adjacent to the existing "all: build" target) so make treats
these as phony targets rather than filenames.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5521a841-939c-425c-babf-2616cf55f5fc

📥 Commits

Reviewing files that changed from the base of the PR and between 8251519 and 438c971.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (34)
  • Makefile
  • PROJECT
  • README.md
  • api/v1beta2/groupversion_info.go
  • api/v1beta2/multirunner_types.go
  • api/v1beta2/runner_types.go
  • api/v1beta2/runner_webhook.go
  • api/v1beta2/webhook_suite_test.go
  • api/v1beta2/webhook_test.go
  • api/v1beta2/zz_generated.deepcopy.go
  • config/config.go
  • config/crd/bases/gitlab.k8s.alekc.dev_multirunners.yaml
  • config/crd/bases/gitlab.k8s.alekc.dev_runners.yaml
  • config/crd/kustomization.yaml
  • config/crd/patches/cainjection_in_multirunners.yaml
  • config/crd/patches/webhook_in_multirunners.yaml
  • config/manager/kustomization.yaml
  • config/rbac/multirunner_editor_role.yaml
  • config/rbac/multirunner_viewer_role.yaml
  • config/rbac/role.yaml
  • config/samples/gitlab_v1beta1_multirunner.yaml
  • config/samples/gitlab_v1beta1_runner.yaml
  • config/webhook/manifests.yaml
  • controllers/multirunner_controller.go
  • controllers/runner_controller.go
  • controllers/runner_controller_test.go
  • controllers/suite_test.go
  • go.mod
  • internal/api/gitlab.go
  • internal/api/gitlab_test.go
  • internal/api/mocked_client.go
  • internal/generate/config.go
  • internal/validate/validate.go
  • main.go

- controller_manager_config.yaml
name: manager-config
apiVersion: kustomize.config.k8s.io/v1beta1
apiVersion: kustomize.config.k8s.io/v1beta2
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

According to official Kustomize documentation, what are valid apiVersion values for kind: Kustomization? Is kustomize.config.k8s.io/v1beta2 valid?

💡 Result:

For a kustomization.yaml with kind: Kustomization, the Kustomize project defines the apiVersion constant as:

  • apiVersion: kustomize.config.k8s.io/v1beta1 [1]

So kustomize.config.k8s.io/v1beta2 is not a valid apiVersion for kind: Kustomization in Kustomize itself (it’s commonly associated with other projects’ CRDs, e.g., Flux), and Kustomize’s own codebase does not define a v1beta2 for Kustomization. [1]

Sources:
[1] kubernetes-sigs/kustomize (api/types/kustomization.go, KustomizationVersion constant) (github.com)

Citations:


Kustomization apiVersion v1beta2 is invalid.

Line 11 uses kustomize.config.k8s.io/v1beta2, which is not a valid apiVersion for kind: Kustomization. According to official Kustomize source code, only v1beta1 is defined. This will break kustomize build.

Suggested fix
-apiVersion: kustomize.config.k8s.io/v1beta2
+apiVersion: kustomize.config.k8s.io/v1beta1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/manager/kustomization.yaml` at line 11, The Kustomization manifest
uses an invalid apiVersion value "kustomize.config.k8s.io/v1beta2"; update the
apiVersion for the Kustomization resource to the supported value
"kustomize.config.k8s.io/v1beta1" so kustomize build will succeed. Locate the
manifest that defines kind: Kustomization and replace the apiVersion symbol
(currently "kustomize.config.k8s.io/v1beta2") with
"kustomize.config.k8s.io/v1beta1", then re-run kustomize build to verify the
change.

@@ -0,0 +1,12 @@
apiVersion: gitlab.k8s.alekc.dev/v1beta1
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

API version inconsistency with rest of PR.

This sample uses apiVersion: gitlab.k8s.alekc.dev/v1beta1, but the PR moves the API to v1beta2. The CRD base at config/crd/bases/gitlab.k8s.alekc.dev_multirunners.yaml and Go types are defined under v1beta2. Consider updating to v1beta2 for consistency.

Proposed fix
-apiVersion: gitlab.k8s.alekc.dev/v1beta1
+apiVersion: gitlab.k8s.alekc.dev/v1beta2
📝 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.

Suggested change
apiVersion: gitlab.k8s.alekc.dev/v1beta1
apiVersion: gitlab.k8s.alekc.dev/v1beta2
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/samples/gitlab_v1beta1_multirunner.yaml` at line 1, Update the
sample's apiVersion from gitlab.k8s.alekc.dev/v1beta1 to
gitlab.k8s.alekc.dev/v1beta2 so it matches the CRD base and Go types;
specifically change the apiVersion field in the sample (currently
"gitlab.k8s.alekc.dev/v1beta1") to "gitlab.k8s.alekc.dev/v1beta2" to align with
the CRD base named gitlab.k8s.alekc.dev_multirunners.yaml and the v1beta2 Go
types.

app.kubernetes.io/name: multirunner
app.kubernetes.io/instance: multirunner-sample
app.kubernetes.io/part-of: gitlab-runner-operator
app.kuberentes.io/managed-by: kustomize
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Typo in label key: "kuberentes" should be "kubernetes".

Proposed fix
-    app.kuberentes.io/managed-by: kustomize
+    app.kubernetes.io/managed-by: kustomize
📝 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.

Suggested change
app.kuberentes.io/managed-by: kustomize
app.kubernetes.io/managed-by: kustomize
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/samples/gitlab_v1beta1_multirunner.yaml` at line 8, Fix the typo in
the label key by changing "app.kuberentes.io/managed-by" to the correct
"app.kubernetes.io/managed-by" in the YAML sample (update the label string used
in the config/samples file); ensure the manifest uses
"app.kubernetes.io/managed-by" consistently wherever
"app.kuberentes.io/managed-by" appears.

Comment on lines 7 to +9
- admissionReviewVersions:
- v1
- v1beta1
- v1beta2
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

What are valid admissionReviewVersions for Kubernetes webhooks?

💡 Result:

Valid values for webhooks[*].admissionReviewVersions (in MutatingWebhookConfiguration / ValidatingWebhookConfiguration) are:

  • v1
  • v1beta1

These correspond to the supported AdmissionReview versions in the admission.k8s.io API group. [1], [2]


Remove invalid v1beta2 from admissionReviewVersions—only v1 and v1beta1 are valid Kubernetes AdmissionReview versions.

The admissionReviewVersions field specifies which versions of the AdmissionReview object (from the admission.k8s.io API group) the webhook can handle. Valid values are v1 and v1beta1. v1beta2 does not exist in the AdmissionReview API.

It appears v1beta2 from your custom resource API version was confused with the Kubernetes AdmissionReview API version. The rules.apiVersions field correctly uses v1beta2 for the custom resource, but admissionReviewVersions must only include v1 and/or v1beta1.

Proposed fix
 webhooks:
 - admissionReviewVersions:
   - v1
-  - v1beta2

Apply to both MutatingWebhookConfiguration (line 9) and ValidatingWebhookConfiguration (line 36).

📝 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.

Suggested change
- admissionReviewVersions:
- v1
- v1beta1
- v1beta2
- admissionReviewVersions:
- v1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/webhook/manifests.yaml` around lines 7 - 9, Remove the invalid
"v1beta2" entry from the admissionReviewVersions lists in both the
MutatingWebhookConfiguration and ValidatingWebhookConfiguration and ensure only
supported AdmissionReview versions ("v1" and/or "v1beta1") remain; keep
rules.apiVersions as-is for your custom resource (v1beta2) but update the
admissionReviewVersions fields to not include v1beta2.

Comment on lines 227 to 263
func caseTagsChanged(tc *testCase) {
ctx := context.Background()
tc.CheckRunner = func(runner *v1beta1.Runner) {
oldAuth := runner.Status.AuthenticationToken

// update tags
runner.Spec.RegistrationConfig.TagList = []string{"new", "tag", "list"}
Expect(k8sClient.Update(ctx, runner)).To(Succeed())

// runner should get a new hash version
newRunner := &v1beta1.Runner{}
Eventually(func() bool {
err := k8sClient.Get(ctx, nameSpacedRunnerName(runner), newRunner)
return err == nil && newRunner.Status.AuthenticationToken != oldAuth
}, timeout, interval).Should(BeTrue())
}
//ctx := context.Background()
//tc.CheckRunner = func(runner *v1beta2.Runner) {
// oldAuth := runner.Status.AuthenticationToken
//
// // update tags
// runner.Spec.RegistrationConfig.TagList = &[]string{"new", "tag", "list"}
// Expect(k8sClient.Update(ctx, runner)).To(Succeed())
//
// // runner should get a new hash version
// newRunner := &v1beta2.Runner{}
// Eventually(func() bool {
// err := k8sClient.Get(ctx, nameSpacedRunnerName(runner), newRunner)
// return err == nil && newRunner.Status.AuthenticationToken != oldAuth
// }, timeout, interval).Should(BeTrue())
//}
}

// caseRegistrationTokenChanged deals with scenario where we change our registration token
func caseRegistrationTokenChanged(tc *testCase) {
ctx := context.Background()
tc.CheckRunner = func(runner *v1beta1.Runner) {
oldAuth := runner.Status.AuthenticationToken

// update tags
runner.Spec.RegistrationConfig.Token = pointer.StringPtr("new reg token")
Expect(k8sClient.Update(ctx, runner)).To(Succeed())

// runner should get a new hash version
newRunner := &v1beta1.Runner{}
Eventually(func() bool {
err := k8sClient.Get(ctx, nameSpacedRunnerName(runner), newRunner)
return err == nil && newRunner.Status.AuthenticationToken != oldAuth
}, timeout, interval).Should(BeTrue())
Expect(newRunner.Status.LastRegistrationToken).To(Equal(*runner.Spec.RegistrationConfig.Token))
}
//ctx := context.Background()
//tc.CheckRunner = func(runner *v1beta2.Runner) {
// oldAuth := runner.Status.AuthenticationToken
//
// // update tags
// runner.Spec.RegistrationConfig.Token = pointer.StringPtr("new reg token")
// Expect(k8sClient.Update(ctx, runner)).To(Succeed())
//
// // runner should get a new hash version
// newRunner := &v1beta2.Runner{}
// Eventually(func() bool {
// err := k8sClient.Get(ctx, nameSpacedRunnerName(runner), newRunner)
// return err == nil && newRunner.Status.AuthenticationToken != oldAuth
// }, timeout, interval).Should(BeTrue())
// Expect(newRunner.Status.LastRegistrationToken).To(Equal(*runner.Spec.RegistrationConfig.Token))
//}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Test cases will panic: CheckRunner is nil but invoked unconditionally.

The test functions caseTagsChanged and caseRegistrationTokenChanged are entirely commented out, but they're still registered in the test table at lines 138-139. Since these functions no longer set tc.CheckRunner, it remains nil, causing a nil pointer dereference when tc.CheckRunner(createdRunner) is called at line 135.

Either remove the table entries or provide a no-op implementation:

🐛 Option 1: Remove table entries
 		table.Entry("Should support setting of env var for build env", caseEnvironmentIsSpecified),
-		table.Entry("Should have created a different registration on tag update", caseTagsChanged),
-		table.Entry("Should have created a different registration on registration token update", caseRegistrationTokenChanged),
 		table.Entry("Should have updated runner status with auth token", caseTestAuthToken),
🐛 Option 2: Add no-op CheckRunner
 func caseTagsChanged(tc *testCase) {
+	tc.CheckRunner = func(runner *v1beta2.Runner) {
+		// TODO: Re-enable when tag change detection is implemented in v1beta2
+	}
 	//ctx := context.Background()
 	//...
 }

 func caseRegistrationTokenChanged(tc *testCase) {
+	tc.CheckRunner = func(runner *v1beta2.Runner) {
+		// TODO: Re-enable when registration token change detection is implemented in v1beta2
+	}
 	//ctx := context.Background()
 	//...
 }
📝 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.

Suggested change
func caseTagsChanged(tc *testCase) {
ctx := context.Background()
tc.CheckRunner = func(runner *v1beta1.Runner) {
oldAuth := runner.Status.AuthenticationToken
// update tags
runner.Spec.RegistrationConfig.TagList = []string{"new", "tag", "list"}
Expect(k8sClient.Update(ctx, runner)).To(Succeed())
// runner should get a new hash version
newRunner := &v1beta1.Runner{}
Eventually(func() bool {
err := k8sClient.Get(ctx, nameSpacedRunnerName(runner), newRunner)
return err == nil && newRunner.Status.AuthenticationToken != oldAuth
}, timeout, interval).Should(BeTrue())
}
//ctx := context.Background()
//tc.CheckRunner = func(runner *v1beta2.Runner) {
// oldAuth := runner.Status.AuthenticationToken
//
// // update tags
// runner.Spec.RegistrationConfig.TagList = &[]string{"new", "tag", "list"}
// Expect(k8sClient.Update(ctx, runner)).To(Succeed())
//
// // runner should get a new hash version
// newRunner := &v1beta2.Runner{}
// Eventually(func() bool {
// err := k8sClient.Get(ctx, nameSpacedRunnerName(runner), newRunner)
// return err == nil && newRunner.Status.AuthenticationToken != oldAuth
// }, timeout, interval).Should(BeTrue())
//}
}
// caseRegistrationTokenChanged deals with scenario where we change our registration token
func caseRegistrationTokenChanged(tc *testCase) {
ctx := context.Background()
tc.CheckRunner = func(runner *v1beta1.Runner) {
oldAuth := runner.Status.AuthenticationToken
// update tags
runner.Spec.RegistrationConfig.Token = pointer.StringPtr("new reg token")
Expect(k8sClient.Update(ctx, runner)).To(Succeed())
// runner should get a new hash version
newRunner := &v1beta1.Runner{}
Eventually(func() bool {
err := k8sClient.Get(ctx, nameSpacedRunnerName(runner), newRunner)
return err == nil && newRunner.Status.AuthenticationToken != oldAuth
}, timeout, interval).Should(BeTrue())
Expect(newRunner.Status.LastRegistrationToken).To(Equal(*runner.Spec.RegistrationConfig.Token))
}
//ctx := context.Background()
//tc.CheckRunner = func(runner *v1beta2.Runner) {
// oldAuth := runner.Status.AuthenticationToken
//
// // update tags
// runner.Spec.RegistrationConfig.Token = pointer.StringPtr("new reg token")
// Expect(k8sClient.Update(ctx, runner)).To(Succeed())
//
// // runner should get a new hash version
// newRunner := &v1beta2.Runner{}
// Eventually(func() bool {
// err := k8sClient.Get(ctx, nameSpacedRunnerName(runner), newRunner)
// return err == nil && newRunner.Status.AuthenticationToken != oldAuth
// }, timeout, interval).Should(BeTrue())
// Expect(newRunner.Status.LastRegistrationToken).To(Equal(*runner.Spec.RegistrationConfig.Token))
//}
}
func caseTagsChanged(tc *testCase) {
tc.CheckRunner = func(runner *v1beta2.Runner) {
// TODO: Re-enable when tag change detection is implemented in v1beta2
}
//ctx := context.Background()
//tc.CheckRunner = func(runner *v1beta2.Runner) {
// oldAuth := runner.Status.AuthenticationToken
//
// // update tags
// runner.Spec.RegistrationConfig.TagList = &[]string{"new", "tag", "list"}
// Expect(k8sClient.Update(ctx, runner)).To(Succeed())
//
// // runner should get a new hash version
// newRunner := &v1beta2.Runner{}
// Eventually(func() bool {
// err := k8sClient.Get(ctx, nameSpacedRunnerName(runner), newRunner)
// return err == nil && newRunner.Status.AuthenticationToken != oldAuth
// }, timeout, interval).Should(BeTrue())
//}
}
// caseRegistrationTokenChanged deals with scenario where we change our registration token
func caseRegistrationTokenChanged(tc *testCase) {
tc.CheckRunner = func(runner *v1beta2.Runner) {
// TODO: Re-enable when registration token change detection is implemented in v1beta2
}
//ctx := context.Background()
//tc.CheckRunner = func(runner *v1beta2.Runner) {
// oldAuth := runner.Status.AuthenticationToken
//
// // update tags
// runner.Spec.RegistrationConfig.Token = pointer.StringPtr("new reg token")
// Expect(k8sClient.Update(ctx, runner)).To(Succeed())
//
// // runner should get a new hash version
// newRunner := &v1beta2.Runner{}
// Eventually(func() bool {
// err := k8sClient.Get(ctx, nameSpacedRunnerName(runner), newRunner)
// return err == nil && newRunner.Status.AuthenticationToken != oldAuth
// }, timeout, interval).Should(BeTrue())
// Expect(newRunner.Status.LastRegistrationToken).To(Equal(*runner.Spec.RegistrationConfig.Token))
//}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controllers/runner_controller_test.go` around lines 227 - 263, The test table
references caseTagsChanged and caseRegistrationTokenChanged but those functions
no longer set tc.CheckRunner, leaving tc.CheckRunner nil and causing a panic
when tc.CheckRunner(createdRunner) is invoked; fix by either removing the
entries for caseTagsChanged and caseRegistrationTokenChanged from the test table
or restore a no-op CheckRunner inside each function (e.g., set tc.CheckRunner =
func(runner *v1beta2.Runner) {}), ensuring tc.CheckRunner is always non-nil
before the unconditional call in the test harness.

go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

What is the latest version of golang.org/x/crypto and what CVEs were fixed after 0.14.0?

💡 Result:

Latest version

  • golang.org/x/crypto v0.49.0 (published Mar 11, 2026) [1]

CVEs fixed after v0.14.0 (Oct 5, 2023)

Sources: [1] https://pkg.go.dev/golang.org/x/crypto (versions) • [2] https://pkg.go.dev/vuln/GO-2024-3321 • [3] https://pkg.go.dev/vuln/GO-2025-3487 • [4] https://pkg.go.dev/vuln/GO-2025-4116 • [5] https://pkg.go.dev/vuln/GO-2025-4135 • [6] https://pkg.go.dev/vuln/GO-2025-4134


Update golang.org/x/crypto to v0.49.0 (or minimum v0.45.0) to fix multiple CVE vulnerabilities.

This indirect dependency has multiple security issues that have been fixed in later versions:

  • Authorization bypass (GO-2024-3321) – fixed in v0.31.0
  • SSH agent DoS vulnerabilities (GO-2025-4116, GO-2025-4134, GO-2025-4135) – fixed in v0.43.0–v0.45.0

Run go get -u golang.org/x/crypto to update to the latest patched version (v0.49.0, currently available).

🧰 Tools
🪛 OSV Scanner (2.3.3)

[CRITICAL] 115-115: golang.org/x/crypto 0.14.0: Man-in-the-middle attacker can compromise integrity of secure channel in golang.org/x/crypto

(GO-2023-2402)


[CRITICAL] 115-115: golang.org/x/crypto 0.14.0: Misuse of connection.serverAuthenticate may cause authorization bypass in golang.org/x/crypto

(GO-2024-3321)


[CRITICAL] 115-115: golang.org/x/crypto 0.14.0: Potential denial of service in golang.org/x/crypto

(GO-2025-3487)


[CRITICAL] 115-115: golang.org/x/crypto 0.14.0: Potential denial of service in golang.org/x/crypto/ssh/agent

(GO-2025-4116)


[CRITICAL] 115-115: golang.org/x/crypto 0.14.0: Unbounded memory consumption in golang.org/x/crypto/ssh

(GO-2025-4134)


[CRITICAL] 115-115: golang.org/x/crypto 0.14.0: Malformed constraint may cause denial of service in golang.org/x/crypto/ssh/agent

(GO-2025-4135)


[CRITICAL] 115-115: golang.org/x/crypto 0.14.0: Prefix Truncation Attack against ChaCha20-Poly1305 and Encrypt-then-MAC aka Terrapin

(GHSA-45x7-px36-x8w8)


[CRITICAL] 115-115: golang.org/x/crypto 0.14.0: golang.org/x/crypto/ssh/agent vulnerable to panic if message is malformed due to out of bounds read

(GHSA-f6x5-jh6r-wrfv)


[CRITICAL] 115-115: golang.org/x/crypto 0.14.0: golang.org/x/crypto Vulnerable to Denial of Service (DoS) via Slow or Incomplete Key Exchange

(GHSA-hcg3-q754-cr77)


[CRITICAL] 115-115: golang.org/x/crypto 0.14.0: golang.org/x/crypto/ssh allows an attacker to cause unbounded memory consumption

(GHSA-j5w8-q4qc-rx2x)


[CRITICAL] 115-115: golang.org/x/crypto 0.14.0: Misuse of ServerConfig.PublicKeyCallback may cause authorization bypass in golang.org/x/crypto

(GHSA-v778-237x-gjrc)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@go.mod` at line 115, Update the indirect dependency golang.org/x/crypto from
v0.14.0 to a patched release (preferably v0.49.0 or at least v0.45.0) to address
multiple CVEs; run `go get -u golang.org/x/crypto@v0.49.0` (or `go get -u
golang.org/x/crypto`), then `go mod tidy` to update go.mod/go.sum and re-run
tests/build to ensure nothing breaks—look for the module line
"golang.org/x/crypto" in go.mod to verify the version change.

golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect
golang.org/x/mod v0.13.0 // indirect
golang.org/x/net v0.16.0 // indirect
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

golang.org/x/net latest version security fixes

💡 Result:

Latest golang.org/x/net (as of March 19, 2026): v0.52.0 (published Mar 12, 2026). [1] (pkg.go.dev)

Security fixes covered by updating to latest:

  • CVE-2025-22872 (XSS / tokenizer/HTML foreign-content parsing issue): fixed in golang.org/x/net v0.38.0 (so v0.52.0 includes the fix). [2] (github.com)
  • CVE-2025-47911 (DoS via quadratic complexity in golang.org/x/net/html parsing): affects versions before v0.45.0; fixed in v0.45.0 (so v0.52.0 includes the fix). [3] (pkg.go.dev)

Update command:

go get golang.org/x/net@latest

Citations:


🌐 Web query:

GO-2023-2102 HTTP/2 rapid reset golang.org/x/net

💡 Result:

GO-2023-2102 is a Go HTTP/2 server DoS issue (alias CVE-2023-39325) where a malicious client rapidly opens streams and immediately sends RST_STREAM, causing the server to do excessive work because new requests can start while prior handlers are still running; the fix makes handler goroutines obey the MaxConcurrentStreams limit (queueing new requests and eventually closing the connection if the queue grows too large). [1]

Affected / fixed versions

  • Go stdlib net/http: affected before go1.20.10, and go1.21.0–go1.21.2; fixed in go1.20.10 and go1.21.3. [1]
  • golang.org/x/net/http2 (for apps manually configuring HTTP/2): affected before v0.17.0; fixed in v0.17.0. [1]

What to do

  • Upgrade to Go ≥ 1.20.10 (or ≥ 1.21.3) and/or golang.org/x/net ≥ 0.17.0. [1]
  • If you can’t upgrade immediately, consider tightening HTTP/2 concurrency via http2.Server.MaxConcurrentStreams / http2.ConfigureServer (trade-off: can reduce per-connection parallelism). [1]

Sources: Go Vulnerability Database report for GO-2023-2102. [1]


🌐 Web query:

GO-2024-2687 HTTP/2 CONTINUATION flood golang.org/x/net

💡 Result:

GO-2024-2687 (CVE-2023-45288 / GHSA-4v7x-pqxf-cx7m) is an HTTP/2 “CONTINUATION frame flood” issue affecting Go’s HTTP/2 implementations in net/http and golang.org/x/net/http2. An attacker can send an excessive number of CONTINUATION frames so the endpoint keeps parsing/decoding header blocks (including potentially expensive HPACK Huffman decoding) even though the request will be rejected once headers exceed limits, leading to resource exhaustion / DoS. [1]

Affected / fixed versions

  • Go standard library (net/http): affected before go1.21.9, and go1.22.0 up to (but not including) go1.22.2. Fixed in go1.21.9 and go1.22.2. [1]
  • golang.org/x/net/http2: affected before v0.23.0. Fixed in v0.23.0. [1][2]

What to do

  • Upgrade Go to go1.21.9+ (or go1.22.2+ if on 1.22.x). [1]
  • If you use the external module, upgrade golang.org/x/net to v0.23.0+. [1][2]

Sources: [1] [2]


🌐 Web query:

GO-2025-3503 HTTP proxy bypass IPv6 golang.org/x/net

💡 Result:

GO-2025-3503 is the Go vulnerability entry for CVE-2025-22870 in golang.org/x/net: proxy-bypass logic can mis-handle an IPv6 zone identifier (the % / percent-encoded %25) as if it were part of the hostname when matching proxy patterns (e.g., NO_PROXY). This can cause requests that should be proxied to be sent directly (proxy bypass). Example: with NO_PROXY=*.example.com, the host "[::1%25.example.com]:80" may incorrectly match and not be proxied. [1][2][3]

  • Affected: golang.org/x/net before v0.36.0, notably golang.org/x/net/http/httpproxy and golang.org/x/net/proxy (e.g., FromEnvironment, FromEnvironmentUsing, PerHost.*). [1][2]
  • Fixed: upgrade to golang.org/x/net v0.36.0 or later. [1][2]

Sources:
[1] Go Vulnerability Database (GO-2025-3503) — pkg.go.dev
[2] GitLab Advisory Database (CVE-2025-22870)
[3] Go issue tracker (golang/go #71984)


Upgrade golang.org/x/net to v0.52.0 or later.

Version v0.16.0 is affected by multiple security vulnerabilities:

  • GO-2023-2102 (HTTP/2 rapid reset DoS) — fixed in v0.17.0
  • GO-2024-2687 (HTTP/2 CONTINUATION frame flood DoS) — fixed in v0.23.0
  • GO-2025-3503 (HTTP proxy bypass via IPv6 zone ID mishandling) — fixed in v0.36.0

Update to the latest version (v0.52.0, released March 2026) to address all known vulnerabilities in this module.

🧰 Tools
🪛 OSV Scanner (2.3.3)

[HIGH] 119-119: golang.org/x/net 0.16.0: HTTP/2 rapid reset can cause excessive work in net/http

(GO-2023-2102)


[HIGH] 119-119: golang.org/x/net 0.16.0: HTTP/2 CONTINUATION flood in net/http

(GO-2024-2687)


[HIGH] 119-119: golang.org/x/net 0.16.0: Non-linear parsing of case-insensitive content in golang.org/x/net/html

(GO-2024-3333)


[HIGH] 119-119: golang.org/x/net 0.16.0: HTTP Proxy bypass using IPv6 Zone IDs in golang.org/x/net

(GO-2025-3503)


[HIGH] 119-119: golang.org/x/net 0.16.0: Incorrect Neutralization of Input During Web Page Generation in x/net in golang.org/x/net

(GO-2025-3595)


[HIGH] 119-119: golang.org/x/net 0.16.0: Quadratic parsing complexity in golang.org/x/net/html

(GO-2026-4440)


[HIGH] 119-119: golang.org/x/net 0.16.0: Infinite parsing loop in golang.org/x/net

(GO-2026-4441)


[HIGH] 119-119: golang.org/x/net 0.16.0: HTTP/2 rapid reset can cause excessive work in net/http

(GHSA-4374-p667-p6c8)


[HIGH] 119-119: golang.org/x/net 0.16.0: net/http, x/net/http2: close connections when receiving too many headers

(GHSA-4v7x-pqxf-cx7m)


[HIGH] 119-119: golang.org/x/net 0.16.0: HTTP/2 Stream Cancellation Attack

(GHSA-qppj-fm5r-hxr3)


[HIGH] 119-119: golang.org/x/net 0.16.0: HTTP Proxy bypass using IPv6 Zone IDs in golang.org/x/net

(GHSA-qxp5-gwg8-xv66)


[HIGH] 119-119: golang.org/x/net 0.16.0: golang.org/x/net vulnerable to Cross-site Scripting

(GHSA-vvgc-356p-c3xw)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@go.mod` at line 119, The go.mod entry pins golang.org/x/net at v0.16.0 which
is vulnerable; update the module requirement for golang.org/x/net to v0.52.0 (or
later) and refresh modules: change the version token for golang.org/x/net in
go.mod to v0.52.0, then run the Go tooling (e.g., go get
golang.org/x/net@v0.52.0 and go mod tidy) to update go.sum and module graph, and
finally run tests/builds to verify there are no regressions.

google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/grpc v1.55.0 // indirect
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

google.golang.org/grpc minimum version to fix CVE-2023-44487

💡 Result:

To fix CVE-2023-44487 in google.golang.org/grpc (gRPC-Go), upgrade to one of the patched versions: v1.56.3, v1.57.1, or v1.58.3 (and all later versions, e.g. v1.59.0+, also include the fix). The minimum safe version overall is v1.56.3. [1][2]


🌐 Web query:

GHSA-p77j-4mvh-x3m3 gRPC authorization bypass CVE

💡 Result:

GHSA-p77j-4mvh-x3m3 maps to CVE-2026-33186: gRPC-Go authorization bypass via missing leading slash in the HTTP/2 :path pseudo-header. Affected: google.golang.org/grpc < 1.79.3. Fix: upgrade to v1.79.3+. The bypass occurs when a client sends a non-canonical :path like Service/Method (no leading /), which can cause path-based authorization (including grpc/authz) to evaluate a different string than the router, letting “deny” rules miss if there’s a fallback “allow”. Published Mar 17, 2026 (updated Mar 18, 2026). [1]


🌐 Web query:

google.golang.org/grpc v1.55.0 CVE vulnerabilities list

💡 Result:

google.golang.org/grpc v1.55.0 is affected by:

  • CVE-2023-44487 (GHSA-m425-mq94-257g / GO-2023-2153) — HTTP/2 Rapid Reset DoS; affects google.golang.org/grpc before v1.56.3 (so v1.55.0 is affected). Fixed in v1.56.3 (and also in the later maintained lines v1.57.1, v1.58.3). [1]
  • CVE-2023-33953 — gRPC HPACK parser DoS; affects grpc versions 1.55.0 <= v < 1.55.2 (so v1.55.0 is affected). Fixed in v1.55.2. [2]

Sources: [1] [2]


Upgrade gRPC to v1.79.3 or later to fix critical vulnerabilities.

google.golang.org/grpc v1.55.0 is affected by:

Additionally, CVE-2023-33953 (HPACK parser DoS) affects this version. Upgrade to v1.79.3 to fix all three vulnerabilities.

🧰 Tools
🪛 OSV Scanner (2.3.3)

[CRITICAL] 133-133: google.golang.org/grpc 1.55.0: Denial of service from HTTP/2 Rapid Reset in google.golang.org/grpc

(GO-2023-2153)


[CRITICAL] 133-133: google.golang.org/grpc 1.55.0: gRPC-Go HTTP/2 Rapid Reset vulnerability

(GHSA-m425-mq94-257g)


[CRITICAL] 133-133: google.golang.org/grpc 1.55.0: gRPC-Go has an authorization bypass via missing leading slash in :path

(GHSA-p77j-4mvh-x3m3)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@go.mod` at line 133, Update the grpc dependency in go.mod from
google.golang.org/grpc v1.55.0 to at least v1.79.3 to address the listed CVEs;
after changing the version string for the module "google.golang.org/grpc" run go
get google.golang.org/grpc@v1.79.3 (or go get ./... with the version) and then
go mod tidy to update go.sum, rebuild and run tests to ensure no regressions;
confirm any code using grpc APIs still compiles against the new version (search
for imports referencing google.golang.org/grpc to locate affected files).


"github.com/go-logr/logr"
gitlabv1beta1 "gitlab.k8s.alekc.dev/api/v1beta1"
gitlabv1beta1 "gitlab.k8s.alekc.dev/api/v1beta2"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Misleading import alias: rename gitlabv1beta1 to gitlabv1beta2.

The import path points to v1beta2 but the alias still uses v1beta1. This creates confusion and could lead to maintenance issues.

🔧 Suggested fix
-	gitlabv1beta1 "gitlab.k8s.alekc.dev/api/v1beta2"
+	gitlabv1beta2 "gitlab.k8s.alekc.dev/api/v1beta2"

Then update all usages in lines 20 and 102 to use gitlabv1beta2.Runner.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/validate/validate.go` at line 7, The import alias is incorrect:
change the import alias from gitlabv1beta1 to gitlabv1beta2 (i.e., import
gitlab.k8s.alekc.dev/api/v1beta2 as gitlabv1beta2) and update all references
that use gitlabv1beta1.Runner to gitlabv1beta2.Runner (ensure occurrences in the
validate package where Runner is referenced are updated accordingly).

Comment on lines +27 to +28
path: gitlab.k8s.alekc.dev/api/v1beta1
version: v1beta1
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== MultiRunner type files =="
fd -t f 'multirunner_types.go'

echo
echo "== Package/version declaration in MultiRunner type files =="
for f in $(fd -t f 'multirunner_types.go'); do
  echo "--- $f ---"
  sed -n '1,60p' "$f"
done

echo
echo "== PROJECT entry for MultiRunner =="
rg -n -C2 'kind:\s*MultiRunner|path:\s*gitlab\.k8s\.alekc\.dev/api/|version:\s*v1beta' PROJECT

Repository: alekc/gitlab-runner-operator

Length of output: 2215


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Runner type files =="
fd -t f 'runner_types.go'

echo
echo "== Package declarations in Runner type files =="
for f in $(fd -t f 'runner_types.go'); do
  echo "--- $f ---"
  head -30 "$f" | grep -E '^(package|type Runner)' || true
done

Repository: alekc/gitlab-runner-operator

Length of output: 339


Both Runner and MultiRunner API versions in PROJECT are out of sync with v1beta2 migration.

Lines 14-15 and lines 27-28 reference api/v1beta1 and v1beta1, but the type files are located in api/v1beta2/ and declare package v1beta2. This mismatch will cause incorrect scaffolding output.

Suggested fix
  domain: k8s.alekc.dev
  group: gitlab
  kind: Runner
-  path: gitlab.k8s.alekc.dev/api/v1beta1
-  version: v1beta1
+  path: gitlab.k8s.alekc.dev/api/v1beta2
+  version: v1beta2
  webhooks:
    defaulting: true
---
  domain: k8s.alekc.dev
  group: gitlab
  kind: MultiRunner
-  path: gitlab.k8s.alekc.dev/api/v1beta1
-  version: v1beta1
+  path: gitlab.k8s.alekc.dev/api/v1beta2
+  version: v1beta2
📝 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.

Suggested change
path: gitlab.k8s.alekc.dev/api/v1beta1
version: v1beta1
path: gitlab.k8s.alekc.dev/api/v1beta2
version: v1beta2
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@PROJECT` around lines 27 - 28, Update the API version references in the
PROJECT file from v1beta1 to v1beta2 so scaffolding matches the actual CRD
types; specifically change path: gitlab.k8s.alekc.dev/api/v1beta1 to
gitlab.k8s.alekc.dev/api/v1beta2 and version: v1beta1 to v1beta2 so Runner and
MultiRunner types (declared under package v1beta2 in api/v1beta2/) are correctly
referenced by the project metadata.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant