mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(cli): allow site admins to use coder create --org for any organization (#21528)
## Problem Site-wide admins (e.g., Owners) could not use `coder create --org <org>` to create workspaces in organizations they are not members of. The error was: ``` $ coder create my-workspace -t docker --org data-science error: organization "data-science" not found, are you sure you are a member of this organization? ``` This was inconsistent with the web UI, where Owners can create workspaces in any organization. ## Root Cause The CLI's `OrganizationContext.Selected()` function only checked the user's membership list, ignoring site-wide RBAC permissions that grant Owners access to all organizations. ## Solution Added a fallback in `OrganizationContext.Selected()` that fetches the org directly via the API when not found in the membership list. This works because the API endpoint applies RBAC filtering, allowing Owners to read any org. ## Impact This fixes `coder create --org` and all other CLI commands that use `OrganizationContext.Selected()` (29+ commands), including: - `coder templates push --org <any-org>` - `coder organizations members add --org <any-org>` - `coder provisioner list --org <any-org>` ## Testing Added `TestEnterpriseCreate/OwnerCanCreateInNonMemberOrg` which: - Creates an Owner user who is NOT a member of a second org - Verifies they can create a workspace there using `--org` - Properly fails without the code fix, passes with it --- *This PR was generated by [mux](https://mux.coder.com) but reviewed by a human.*
This commit is contained in:
+15
-4
@@ -884,16 +884,27 @@ func (o *OrganizationContext) Selected(inv *serpent.Invocation, client *codersdk
|
||||
index := slices.IndexFunc(orgs, func(org codersdk.Organization) bool {
|
||||
return org.Name == o.FlagSelect || org.ID.String() == o.FlagSelect
|
||||
})
|
||||
if index >= 0 {
|
||||
return orgs[index], nil
|
||||
}
|
||||
|
||||
if index < 0 {
|
||||
// Not in membership list - try direct fetch.
|
||||
// This allows site-wide admins (e.g., Owners) to use orgs they aren't
|
||||
// members of.
|
||||
org, err := client.OrganizationByName(inv.Context(), o.FlagSelect)
|
||||
if err != nil {
|
||||
var names []string
|
||||
for _, org := range orgs {
|
||||
names = append(names, org.Name)
|
||||
}
|
||||
return codersdk.Organization{}, xerrors.Errorf("organization %q not found, are you sure you are a member of this organization? "+
|
||||
"Valid options for '--org=' are [%s].", o.FlagSelect, strings.Join(names, ", "))
|
||||
var sdkErr *codersdk.Error
|
||||
if errors.As(err, &sdkErr) && sdkErr.StatusCode() == http.StatusNotFound {
|
||||
return codersdk.Organization{}, xerrors.Errorf("organization %q not found, are you sure you are a member of this organization? "+
|
||||
"Valid options for '--org=' are [%s].", o.FlagSelect, strings.Join(names, ", "))
|
||||
}
|
||||
return codersdk.Organization{}, xerrors.Errorf("get organization %q: %w", o.FlagSelect, err)
|
||||
}
|
||||
return orgs[index], nil
|
||||
return org, nil
|
||||
}
|
||||
|
||||
if len(orgs) == 1 {
|
||||
|
||||
Reference in New Issue
Block a user