Skip to content

Enable workspace resolver to find nested workspaces#54

Open
Perseus985 wants to merge 3 commits intomainfrom
feature/workspace-resolver
Open

Enable workspace resolver to find nested workspaces#54
Perseus985 wants to merge 3 commits intomainfrom
feature/workspace-resolver

Conversation

@Perseus985
Copy link
Copy Markdown
Contributor

@Perseus985 Perseus985 commented May 7, 2026

Summary

  • Previously, the workspace resolver hardcoded a client pointed at the root workspace and fetched workspaces by name directly, this only worked for direct children of root (e.g. root:my-workspace).
  • Replaced rootCfg with baseCfg (the bare front-proxy URL) and derive the parent workspace path dynamically by stripping the last segment of the requested path.

Motivation

The controller was failing to resolve workspace paths for anything not at depth 1 under root. This change makes the resolver work for any depth of the kcp workspace tree.

Changes

  • dependencyrule_controller.go: rename rootCfg → baseCfg on workspaceResolver, update ensureInitialized to pass the base config unchanged, and rewrite ensureResolved to walk the parent path per missing entry and list workspaces rather than fetching a single one by name.

Closes #26

Summary by CodeRabbit

  • Refactor

    • Improved workspace resolution behavior for dependency handling, including multi-parent resolution, caching, and more tolerant handling of missing cluster names.
  • Style

    • Tightened linter/security checks and added YAML linting rules.
  • Tests

    • Added unit tests for workspace resolution and caching behavior.
    • Minor adjustment to an end-to-end test helper for port-forwarding.

Signed-off-by: Kevin Stellmacher <dev@stellmacher.xyz>
@Perseus985 Perseus985 self-assigned this May 7, 2026
@Perseus985 Perseus985 linked an issue May 7, 2026 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

The workspace resolver mechanism is refactored to use Reconciler.BaseConfig directly, store a front-proxy baseCfg, and resolve workspace paths by deriving parent logicalcluster paths, creating per-parent REST clients, listing Workspace objects under each parent, validating ws.Spec.Cluster, and caching parentPath:workspaceName → cluster mappings.

Changes

Workspace Resolver Parent-Based Discovery

Layer / File(s) Summary
Config Structure Definition
internal/controller/dependencyrule_controller.go
workspaceResolver struct field rootCfg replaced with baseCfg, adds scheme and an injectable newClient factory.
Resolver Initialization
internal/controller/dependencyrule_controller.go
ensureInitialized constructs workspaceResolver directly from BaseConfig and the manager scheme, removing the intermediate creation of a root-scoped REST config with appended logicalcluster root path.
Parent-Based Workspace Discovery & Caching
internal/controller/dependencyrule_controller.go
ensureResolved derives parent paths from unresolved workspace paths, creates per-parent REST clients, lists Workspace objects under each parent, validates ws.Spec.Cluster, and caches parentPath:ws.Name -> ws.Spec.Cluster with log entries.
Unit Tests
internal/controller/dependencyrule_controller_test.go
Adds tests and a helper for resolver: successful resolve and cache population, cache short-circuit, list error propagation, per-parent client routing, and no-op on empty input.
Linting Configs
.golangci.yaml, .yamllint.yaml
Remove specific gosec excludes from .golangci.yaml; add .yamllint.yaml with custom rules (120 char line length warning, 2-space indent, truthy disabled for on:, relaxed comment spacing, EOF newline warning, ignore globs).
E2E Test Minor
test/e2e/suite_test.go
Add inline // #nosec G204 annotation to a dynamic kubectl port-forward argument node.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hop from root to branch and see,
Parents list the work for me,
Caches stitch the path by name,
No single-root confines remain,
Logs sing each resolved workspace claim.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Enable workspace resolver to find nested workspaces' directly and clearly describes the main change, which is to make the resolver work for nested workspace paths at any depth, not just direct children of root.
Linked Issues check ✅ Passed The pull request fully addresses issue #26 objectives: it removes the single-root assumption by replacing rootCfg with baseCfg, implements segment-by-segment path walking, lists workspaces at parent paths dynamically, and caches full workspace paths with their cluster names.
Out of Scope Changes check ✅ Passed The changes are appropriately scoped: core logic is in dependencyrule_controller.go (resolver refactoring), comprehensive tests are added, linting configuration is tightened (gosec excludes removed), and yamllint configuration is added for consistency.

✏️ 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 feature/workspace-resolver

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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: 2

🧹 Nitpick comments (2)
internal/controller/dependencyrule_controller.go (2)

193-196: ⚡ Quick win

Remove commented-out dead code.

Lines 193–196 still contain the old client-construction snippet. Dead commented-out code should not be included in a merged PR.

🧹 Proposed cleanup
-	//	c, err := client.New(w.rootCfg, client.Options{Scheme: w.scheme})
-	//	if err != nil {
-	//		return fmt.Errorf("creating root workspace client: %w", err)
-	//	}
 	for _, path := range missing {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/controller/dependencyrule_controller.go` around lines 193 - 196,
Remove the dead commented-out client construction snippet (the block containing
client.New, client.Options, w.rootCfg and w.scheme) from
dependencyrule_controller.go; locate the commented lines that begin with "//	c,
err := client.New(...)" and delete that entire commented block so no
commented-out client creation code remains in the PR.

197-228: ⚡ Quick win

Multiple List API calls issued for the same parent when several sibling paths are missing.

The outer loop iterates every entry in missing individually. If root:org:ws1, root:org:ws2, and root:org:ws3 are all absent from the cache, three separate clients are built and three List calls are sent to the same root:org parent endpoint. The inner cache check on line 198 only short-circuits if an exact path match was already cached (which it never is for a freshly listed sibling), so it does not prevent the redundant calls.

Group missing paths by parentPath first, then issue one List per distinct parent:

♻️ Proposed refactor
-	for _, path := range missing {
-		if _, ok := w.cache[path]; ok {
-			continue
-		}
-
-		var parentPath string
-		if i := strings.LastIndex(path, ":"); i >= 0 {
-			parentPath = path[:i]
-		}
-
-		parentCfg := rest.CopyConfig(w.baseCfg)
-		parentCfg.Host += logicalcluster.NewPath(parentPath).RequestPath()
-
-		c, err := client.New(parentCfg, client.Options{Scheme: w.scheme})
-		if err != nil {
-			return fmt.Errorf("creating %s workspace client: %w", parentPath, err)
-		}
-
-		var wsList tenancyv1alpha1.WorkspaceList
-		if err := c.List(ctx, &wsList); err != nil {
-			return fmt.Errorf("list workspaces in %s: %w", parentPath, err)
-		}
-
-		for _, ws := range wsList.Items {
-			if ws.Spec.Cluster == "" {
-				return fmt.Errorf("workspace %s has no logical cluster name", ws.Name)
-			}
-
-			wsPath := parentPath + ":" + ws.Name
-			w.cache[wsPath] = ws.Spec.Cluster
-			log.FromContext(ctx).Info("resolved workspace path", "path", wsPath, "cluster", ws.Spec.Cluster)
-		}
-	}
+	// Group missing paths by their parent to avoid redundant List calls.
+	byParent := make(map[string]struct{})
+	for _, path := range missing {
+		if _, ok := w.cache[path]; ok {
+			continue
+		}
+		i := strings.LastIndex(path, ":")
+		if i < 0 {
+			return fmt.Errorf("workspace path %q has no parent segment", path)
+		}
+		byParent[path[:i]] = struct{}{}
+	}
+
+	for parentPath := range byParent {
+		parentCfg := rest.CopyConfig(w.baseCfg)
+		parentCfg.Host += logicalcluster.NewPath(parentPath).RequestPath()
+
+		c, err := client.New(parentCfg, client.Options{Scheme: w.scheme})
+		if err != nil {
+			return fmt.Errorf("creating %s workspace client: %w", parentPath, err)
+		}
+
+		var wsList tenancyv1alpha1.WorkspaceList
+		if err := c.List(ctx, &wsList); err != nil {
+			return fmt.Errorf("list workspaces in %s: %w", parentPath, err)
+		}
+
+		for _, ws := range wsList.Items {
+			if ws.Spec.Cluster == "" {
+				log.FromContext(ctx).Info("skipping workspace with no cluster (still provisioning?)", "workspace", ws.Name)
+				continue
+			}
+			wsPath := parentPath + ":" + ws.Name
+			w.cache[wsPath] = ws.Spec.Cluster
+			log.FromContext(ctx).Info("resolved workspace path", "path", wsPath, "cluster", ws.Spec.Cluster)
+		}
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/controller/dependencyrule_controller.go` around lines 197 - 228, The
loop over missing issues redundant List calls for the same parentPath; change
the logic to first group missing paths by their parentPath (compute parentPath
via strings.LastIndex like current code), then iterate each distinct parentPath
once: build parentCfg (rest.CopyConfig +
logicalcluster.NewPath(parentPath).RequestPath()), create client.New(parentCfg,
...), call c.List(ctx, &wsList) once per parent, and populate w.cache for each
child wsPath (parentPath + ":" + ws.Name) from wsList.Items; keep the existing
checks/logging (w.cache lookup, ws.Spec.Cluster emptiness, and log.FromContext)
but remove per-missing-path client creation and List calls so only one List
happens per unique parentPath.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/controller/dependencyrule_controller.go`:
- Around line 221-223: The early return in ensureResolved when ws.Spec.Cluster
== "" should be changed to skip the not-yet-provisioned workspace instead of
failing the whole reconciliation: replace the hard error return in the block
that checks ws.Spec.Cluster (inside ensureResolved / the workspace iteration)
with a processLogger or logger.Warnf message noting the workspace is not ready
and continue to the next workspace, ensuring the function does not abort
resolution for other paths; keep the check but make it non-fatal so other
caching/resolution work proceeds.
- Around line 202-205: The code builds parentPath using strings.LastIndex(path,
":") which yields -1 for single-segment workspace paths (e.g., "root"), leaving
parentPath empty and causing cache keys like ":child". Update the parentPath
logic in the block that sets parentPath (the variable using strings.LastIndex)
so that when LastIndex returns -1 you assign parentPath = path (instead of
leaving it empty); this ensures cache entries use "root:child" and resolve(path)
can find single-segment workspace entries correctly.

---

Nitpick comments:
In `@internal/controller/dependencyrule_controller.go`:
- Around line 193-196: Remove the dead commented-out client construction snippet
(the block containing client.New, client.Options, w.rootCfg and w.scheme) from
dependencyrule_controller.go; locate the commented lines that begin with "//	c,
err := client.New(...)" and delete that entire commented block so no
commented-out client creation code remains in the PR.
- Around line 197-228: The loop over missing issues redundant List calls for the
same parentPath; change the logic to first group missing paths by their
parentPath (compute parentPath via strings.LastIndex like current code), then
iterate each distinct parentPath once: build parentCfg (rest.CopyConfig +
logicalcluster.NewPath(parentPath).RequestPath()), create client.New(parentCfg,
...), call c.List(ctx, &wsList) once per parent, and populate w.cache for each
child wsPath (parentPath + ":" + ws.Name) from wsList.Items; keep the existing
checks/logging (w.cache lookup, ws.Spec.Cluster emptiness, and log.FromContext)
but remove per-missing-path client creation and List calls so only one List
happens per unique parentPath.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7a531908-919b-4987-ba22-9d0c386c46d3

📥 Commits

Reviewing files that changed from the base of the PR and between 1fb2920 and 4b2b8e8.

📒 Files selected for processing (1)
  • internal/controller/dependencyrule_controller.go

Comment thread internal/controller/dependencyrule_controller.go
Comment thread internal/controller/dependencyrule_controller.go
…nit testing

Signed-off-by: Cyrill Berg <cyrill.berg@opendefense.cloud>
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: 1

🧹 Nitpick comments (2)
internal/controller/dependencyrule_controller_test.go (2)

159-168: ⚡ Quick win

Consider also covering an empty (non-nil) slice — nil and []string{} may exercise different code paths.

The production code likely has if len(paths) == 0 { return nil }, which handles both. But if the guard is if paths == nil, an empty slice would still trigger client creation. A one-liner addition eliminates the ambiguity:

💡 Suggested addition
 if err := r.ensureResolved(context.Background(), nil); err != nil {
     t.Fatalf("ensureResolved: %v", err)
 }
+if err := r.ensureResolved(context.Background(), []string{}); err != nil {
+    t.Fatalf("ensureResolved with empty slice: %v", err)
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/controller/dependencyrule_controller_test.go` around lines 159 -
168, Add a second assertion to
TestWorkspaceResolver_EnsureResolved_EmptyInputIsNoop that calls
r.ensureResolved with an empty non-nil slice (e.g., []string{}) to ensure the
code treats []string{} the same as nil; use the same newTestResolver callback
that fails the test if a client is created and assert that ensureResolved
returns nil (no error) for the empty slice as well, referencing
TestWorkspaceResolver_EnsureResolved_EmptyInputIsNoop, newTestResolver, and
ensureResolved.

154-156: ⚡ Quick win

len(calls) only checks distinct host count, not per-host call count — double-listing would go unnoticed.

If ensureResolved mistakenly calls newClient twice for the same parent (e.g., once per child path), calls["root:org-a"] would be 2 but len(calls) would still be 2, passing the assertion. Consider asserting the per-host count:

💡 Suggested assertion addition
 if len(calls) != 2 {
     t.Errorf("expected exactly 2 distinct hosts called, got %v", calls)
 }
+for host, n := range calls {
+    if n != 1 {
+        t.Errorf("host %q called %d times, want 1 (parent should be listed once)", host, n)
+    }
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/controller/dependencyrule_controller_test.go` around lines 154 -
156, The test currently only asserts len(calls) == 2 which misses duplicate
calls to the same host; update the test around ensureResolved/newClient to also
assert each host was called exactly once by checking calls["root:org-a"] == 1
and calls["root:org-b"] == 1 (with clear error messages), so the test fails if
ensureResolved invokes newClient multiple times for the same parent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/controller/dependencyrule_controller_test.go`:
- Line 15: The test is using scheme.Scheme which lacks KCP tenancy types
(tenancyv1alpha1.Workspace/WorkspaceList), causing
fake.NewClientBuilder().WithScheme(...).WithLists(...) to fail; create a
dedicated test scheme (e.g., call runtime.NewScheme()), register core Kubernetes
types and KCP tenancy types by calling corev1.AddToScheme or
clientgoscheme.AddToScheme and tenancyv1alpha1.AddToScheme (reference
tenancyv1alpha1.Workspace and WorkspaceList), then replace scheme.Scheme in
fake.NewClientBuilder().WithScheme(...) calls with this new scheme and import
the tenancyv1alpha1 package and runtime/client-go scheme helpers as needed so
TestWorkspaceResolver_EnsureResolved_ResolvesPath and the related tests can
build and run.

---

Nitpick comments:
In `@internal/controller/dependencyrule_controller_test.go`:
- Around line 159-168: Add a second assertion to
TestWorkspaceResolver_EnsureResolved_EmptyInputIsNoop that calls
r.ensureResolved with an empty non-nil slice (e.g., []string{}) to ensure the
code treats []string{} the same as nil; use the same newTestResolver callback
that fails the test if a client is created and assert that ensureResolved
returns nil (no error) for the empty slice as well, referencing
TestWorkspaceResolver_EnsureResolved_EmptyInputIsNoop, newTestResolver, and
ensureResolved.
- Around line 154-156: The test currently only asserts len(calls) == 2 which
misses duplicate calls to the same host; update the test around
ensureResolved/newClient to also assert each host was called exactly once by
checking calls["root:org-a"] == 1 and calls["root:org-b"] == 1 (with clear error
messages), so the test fails if ensureResolved invokes newClient multiple times
for the same parent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0d67154e-c535-4dbe-8ad8-00cff31bb2d9

📥 Commits

Reviewing files that changed from the base of the PR and between 4b2b8e8 and e9915f2.

📒 Files selected for processing (5)
  • .golangci.yaml
  • .yamllint.yaml
  • internal/controller/dependencyrule_controller.go
  • internal/controller/dependencyrule_controller_test.go
  • test/e2e/suite_test.go
💤 Files with no reviewable changes (1)
  • .golangci.yaml
✅ Files skipped from review due to trivial changes (1)
  • .yamllint.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/controller/dependencyrule_controller.go

Comment thread internal/controller/dependencyrule_controller_test.go Outdated
… fail hard on unready workspaces

Signed-off-by: Cyrill Berg <cyrill.berg@opendefense.cloud>
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.

🧹 Nitpick comments (2)
internal/controller/dependencyrule_controller_test.go (2)

163-165: ⚡ Quick win

Assert per-host call counts, not only distinct hosts.

Line 163 currently checks only len(calls) == 2, which still passes if each host is called multiple times. Add exact count assertions per expected host to lock in the intended one-list-per-parent behavior.

Suggested test hardening
-	if len(calls) != 2 {
-		t.Errorf("expected exactly 2 distinct hosts called, got %v", calls)
-	}
+	if len(calls) != 2 {
+		t.Errorf("expected exactly 2 distinct hosts called, got %v", calls)
+	}
+	if calls[baseHost+logicalcluster.NewPath("root:org-a").RequestPath()] != 1 {
+		t.Errorf("expected exactly 1 call for root:org-a host, got %d", calls[baseHost+logicalcluster.NewPath("root:org-a").RequestPath()])
+	}
+	if calls[baseHost+logicalcluster.NewPath("root:org-b").RequestPath()] != 1 {
+		t.Errorf("expected exactly 1 call for root:org-b host, got %d", calls[baseHost+logicalcluster.NewPath("root:org-b").RequestPath()])
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/controller/dependencyrule_controller_test.go` around lines 163 -
165, The current test only asserts len(calls) == 2 which allows multiple hits
per host; update the assertion to verify per-host call counts by building a
frequency map from the calls slice and asserting that each expected host (the
specific host strings used in this test) has count == 1; modify the assertion
near the len(calls) check in dependencyrule_controller_test.go to create a
map[string]int of counts for the calls variable and assert exact counts for each
host instead of only checking distinct host count.

168-176: ⚡ Quick win

Cover empty slice explicitly in no-op test.

Line 174 validates nil, but not []string{}. Since behavior is documented as nil/empty no-op, add the empty-slice assertion too.

Suggested test extension
 	if err := r.ensureResolved(context.Background(), nil); err != nil {
 		t.Fatalf("ensureResolved: %v", err)
 	}
+	if err := r.ensureResolved(context.Background(), []string{}); err != nil {
+		t.Fatalf("ensureResolved(empty): %v", err)
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/controller/dependencyrule_controller_test.go` around lines 168 -
176, Update the TestWorkspaceResolver_EnsureResolved_EmptyInputIsNoop test to
also assert that an empty slice is a no-op: add a second call to
r.ensureResolved(context.Background(), []string{}) and check it returns no error
(just like the existing nil case) while still ensuring newTestResolver's client
factory is not invoked; modify only the
TestWorkspaceResolver_EnsureResolved_EmptyInputIsNoop test (referencing
r.ensureResolved, newTestResolver) to include this extra assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/controller/dependencyrule_controller_test.go`:
- Around line 163-165: The current test only asserts len(calls) == 2 which
allows multiple hits per host; update the assertion to verify per-host call
counts by building a frequency map from the calls slice and asserting that each
expected host (the specific host strings used in this test) has count == 1;
modify the assertion near the len(calls) check in
dependencyrule_controller_test.go to create a map[string]int of counts for the
calls variable and assert exact counts for each host instead of only checking
distinct host count.
- Around line 168-176: Update the
TestWorkspaceResolver_EnsureResolved_EmptyInputIsNoop test to also assert that
an empty slice is a no-op: add a second call to
r.ensureResolved(context.Background(), []string{}) and check it returns no error
(just like the existing nil case) while still ensuring newTestResolver's client
factory is not invoked; modify only the
TestWorkspaceResolver_EnsureResolved_EmptyInputIsNoop test (referencing
r.ensureResolved, newTestResolver) to include this extra assertion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7a43a3ba-035f-40c9-9989-8bd9c695ec72

📥 Commits

Reviewing files that changed from the base of the PR and between e9915f2 and 4b99525.

📒 Files selected for processing (2)
  • internal/controller/dependencyrule_controller.go
  • internal/controller/dependencyrule_controller_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/controller/dependencyrule_controller.go

Copy link
Copy Markdown
Contributor

@BergCyrill BergCyrill left a comment

Choose a reason for hiding this comment

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

The logic itself seems legit to me and I have added some unit tests to the new workspace resolver additionally to the already existent and working e2e tests. The controller needs to get more testing in the future to prevent regression on functionality to be automatically discovered during CI.

@BergCyrill BergCyrill requested a review from trevex May 8, 2026 08:40
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.

Workspace resolver

2 participants