Skip to content

refactor(cli): various cleanups and bug fixes#6262

Open
geovannewashington wants to merge 6 commits intomasterfrom
fix/cli-cleanups-and-bug-fixes
Open

refactor(cli): various cleanups and bug fixes#6262
geovannewashington wants to merge 6 commits intomasterfrom
fix/cli-cleanups-and-bug-fixes

Conversation

@geovannewashington
Copy link
Copy Markdown
Member

What changed?

A series of small correctness fixes and cleanups across the CLI service
and command layers.

Why

UserList was returning raw store errors directly, unlike every other
service method which wraps them in sentinel values from errors.go.
This leaked implementation details to the cmd layer.

NamespaceDelete.Namespace had no validation tag. Cobra's ExactArgs
only enforces argument count - invalid names like My.Namespace were
reaching the store instead of being rejected early with a clear error.

namespaceInspect was making N+1 DB round trips - one UserResolve
call per member plus a separate one for the owner. Replaced with a
single UserList call upfront and an in-memory map for lookups,
bringing it down to 2 queries regardless of member count.

Deprecated commands had been marked for removal since v0.16.0, over
two years and eight minor versions ago. Removed with team approval.

getMaxDevices() lived in its own utils.go file despite being a
single function called only by NamespaceCreate. Moved to
namespaces.go and deleted the file.

Added the missing doc comment to UserList in the UserStore
interface, which was the only method without one.

How to test

  1. Start the environment with ./bin/docker-compose up -d
  2. Run the following and verify expected behavior:
# invalid namespace name must be rejected early
./bin/cli namespace delete My.Namespace  # must error: namespace is invalid

# inspect must show all members correctly
./bin/cli user create user1 Secret123! user1@test.com
./bin/cli user create user2 Secret123! user2@test.com
./bin/cli namespace create testns user1
./bin/cli namespace member add user2 testns observer
./bin/cli namespace inspect testns

# deprecated commands must no longer exist
./bin/cli add-user testuser2 Secret123! test2@test.com  # must error

@geovannewashington geovannewashington self-assigned this Apr 29, 2026
@geovannewashington geovannewashington requested review from a team as code owners April 29, 2026 19:26
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 29, 2026

Claude finished @geovannewashington's task in 6m 56s —— View job


Code Review Complete

Reviewed 10 files across code quality, security, testing, Go patterns, and architecture — 1 issue found.

Test assertion not updated for UserList error wrapping

Severity: high  ·  File: cli/services/users_test.go:563

UserList was updated to return ErrFailedListUsers instead of the raw store error (users.go:155-157), but TestUserList still asserts the raw storeErr:

// line 563 — current (will fail)
expectedErr: storeErr,

// fix
expectedErr: ErrFailedListUsers,

The parallel NamespaceList change had its test correctly updated to expect ErrFailedListNamespaces (namespaces_test.go:773), but this one was missed. The storeErr variable is still needed for the mock's .Return(nil, 0, storeErr) call — only the assertion needs to change.

Fix this →


If you've addressed the feedback and want a new review, tag @shellhub-io/admin and a team member can trigger it.

UserList was returning the raw store error directly, unlike every other
service method which translates store errors into sentinel values from
errors.go. This leaks implementation details to the cmd layer and breaks
the consistency of the error handling pattern.
NamespaceDelete.Namespace had no validate tag, unlike every other input
struct. Cobra's ExactArgs(1) only enforces argument count, not content,
so invalid namespace names like "My.Namespace" or "UPPERCASE" would pass
through to the store instead of being rejected early with a clear error.
namespaceInspect was calling UserResolve once per namespace member inside
a loop, plus a separate call for the owner. For a namespace with N members
this resulted in N+1 DB round trips. Replace with a single UserList call
upfront, building an in-memory map for O(1) lookups of both the owner and
all members.
UserList was the only method in UserStore without a doc comment,
inconsistent with the rest of the interface.
These commands were marked for removal in v0.16.0, over two years and
eight minor versions ago. All functionality has been available through
the current command structure (cli user *, cli namespace *) since then.
Removed with team approval.
getMaxDevices() is only called by NamespaceCreate, so it has no reason
to live in its own file. Moved it to namespaces.go where it is used and
deleted utils.go.
@geovannewashington geovannewashington force-pushed the fix/cli-cleanups-and-bug-fixes branch from 93899c7 to c1238f2 Compare April 29, 2026 19:36
@otavio
Copy link
Copy Markdown
Member

otavio commented Apr 29, 2026

/review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 29, 2026

Claude finished @otavio's task in 6m 12s —— View job


Code Review Complete

Reviewed 10 files across code quality, security, testing, Go patterns, and architecture — no issues found. The code looks good as-is.

The issue from the previous review (users_test.go:563 asserting storeErr instead of ErrFailedListUsers) has been correctly addressed.


If you push additional changes and want a new review, tag @shellhub-io/admin and a team member can trigger it.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants