[GH-ISSUE #70] Add Users & Access Management (users + invitations) #17

Closed
opened 2026-02-26 21:32:48 +03:00 by kerem · 2 comments
Owner

Originally created by @rudrankriyam on GitHub (Jan 24, 2026).
Original GitHub issue: https://github.com/rudrankriyam/App-Store-Connect-CLI/issues/70

Summary

Add Users & Access Management commands (users, invitations, visible apps). ASC currently has no user/admin tooling.

Current State (verified)

Repo search for user/admin/access endpoints returns no matches. There are no users or userInvitations commands or client methods.

API Endpoints (App Store Connect OpenAPI)

  • GET /v1/users
  • GET /v1/users/{id}
  • PATCH /v1/users/{id}
  • DELETE /v1/users/{id}
  • GET /v1/users/{id}/visibleApps
  • GET|POST|PATCH|DELETE /v1/users/{id}/relationships/visibleApps
  • GET /v1/userInvitations
  • POST /v1/userInvitations
  • GET /v1/userInvitations/{id}
  • DELETE /v1/userInvitations/{id}
  • GET /v1/userInvitations/{id}/visibleApps
  • GET /v1/userInvitations/{id}/relationships/visibleApps

Proposed CLI

asc users list [--filter email] [--limit] [--paginate]
asc users get --id USER_ID
asc users update --id USER_ID --roles ROLE_ID[,ROLE_ID...] [--visible-app APP_ID[,APP_ID...]]
asc users delete --id USER_ID --confirm

asc users invite --email user@example.com --roles ROLE_ID[,ROLE_ID...] [--all-apps | --visible-app APP_ID[,APP_ID...]]
asc users invites list [--limit] [--paginate]
asc users invites get --id INVITE_ID
asc users invites revoke --id INVITE_ID --confirm

Implementation Plan

  1. internal/asc/users.go
  • Types for User, UserInvitation, relationships, filters.
  • Client methods: list/get/update/delete users; list/create/get/delete invitations; manage visible apps relationships.
  1. cmd/users.go
  • New users command group with list/get/update/delete/invite/invites subcommands.
  • Validation: required IDs/emails, explicit confirmation for deletes.
  1. Output helpers
  • Add table/markdown formatting for users and invitations in internal/asc output helpers.
  1. Tests
  • CLI validation tests in cmd/commands_test.go or new cmd/users_test.go.
  • HTTP client tests in internal/asc/client_http_test.go.

Acceptance Criteria

  • Can list, fetch, update, and delete users.
  • Can create, list, fetch, and revoke user invitations.
  • Visible apps relationship management works (add/remove/set).
  • JSON output by default; table/markdown supported.
Originally created by @rudrankriyam on GitHub (Jan 24, 2026). Original GitHub issue: https://github.com/rudrankriyam/App-Store-Connect-CLI/issues/70 ## Summary Add Users & Access Management commands (users, invitations, visible apps). ASC currently has no user/admin tooling. ## Current State (verified) Repo search for user/admin/access endpoints returns no matches. There are no `users` or `userInvitations` commands or client methods. ## API Endpoints (App Store Connect OpenAPI) - `GET /v1/users` - `GET /v1/users/{id}` - `PATCH /v1/users/{id}` - `DELETE /v1/users/{id}` - `GET /v1/users/{id}/visibleApps` - `GET|POST|PATCH|DELETE /v1/users/{id}/relationships/visibleApps` - `GET /v1/userInvitations` - `POST /v1/userInvitations` - `GET /v1/userInvitations/{id}` - `DELETE /v1/userInvitations/{id}` - `GET /v1/userInvitations/{id}/visibleApps` - `GET /v1/userInvitations/{id}/relationships/visibleApps` ## Proposed CLI ``` asc users list [--filter email] [--limit] [--paginate] asc users get --id USER_ID asc users update --id USER_ID --roles ROLE_ID[,ROLE_ID...] [--visible-app APP_ID[,APP_ID...]] asc users delete --id USER_ID --confirm asc users invite --email user@example.com --roles ROLE_ID[,ROLE_ID...] [--all-apps | --visible-app APP_ID[,APP_ID...]] asc users invites list [--limit] [--paginate] asc users invites get --id INVITE_ID asc users invites revoke --id INVITE_ID --confirm ``` ## Implementation Plan 1) `internal/asc/users.go` - Types for User, UserInvitation, relationships, filters. - Client methods: list/get/update/delete users; list/create/get/delete invitations; manage visible apps relationships. 2) `cmd/users.go` - New `users` command group with `list/get/update/delete/invite/invites` subcommands. - Validation: required IDs/emails, explicit confirmation for deletes. 3) Output helpers - Add table/markdown formatting for users and invitations in `internal/asc` output helpers. 4) Tests - CLI validation tests in `cmd/commands_test.go` or new `cmd/users_test.go`. - HTTP client tests in `internal/asc/client_http_test.go`. ## Acceptance Criteria - Can list, fetch, update, and delete users. - Can create, list, fetch, and revoke user invitations. - Visible apps relationship management works (add/remove/set). - JSON output by default; table/markdown supported.
kerem closed this issue 2026-02-26 21:32:48 +03:00
Author
Owner

@rudrankriyam commented on GitHub (Jan 24, 2026):

@cursor

Implementation Guide

Codebase Context

The CLI follows these patterns (see docs/GO_STANDARDS.md, docs/CONTRIBUTING.md):

  • Commands use ffcli with factory functions returning *ffcli.Command
  • All commands use UsageFunc: DefaultUsageFunc for consistent help formatting
  • Client methods live in internal/asc/client*.go, split by domain
  • Types use generics: Resource[T], Response[T], SingleResponse[T] (see internal/asc/client_types.go)
  • Output formatting uses switch statements in internal/asc/output_core.go

File Structure

Create these files:

1. internal/asc/users.go (~200-300 lines)

// Types needed:
type UserAttributes struct {
    Username        string   `json:"username"`
    FirstName       string   `json:"firstName"`
    LastName        string   `json:"lastName"`
    Email           string   `json:"email,omitempty"`
    Roles           []string `json:"roles"`
    AllAppsVisible  bool     `json:"allAppsVisible"`
    ProvisioningAllowed bool `json:"provisioningAllowed"`
}

type UserInvitationAttributes struct {
    Email           string   `json:"email"`
    FirstName       string   `json:"firstName"`
    LastName        string   `json:"lastName"`
    Roles           []string `json:"roles"`
    AllAppsVisible  bool     `json:"allAppsVisible"`
    ProvisioningAllowed bool `json:"provisioningAllowed"`
    ExpirationDate  string   `json:"expirationDate,omitempty"`
}

// Response types using existing generics:
type UsersResponse = Response[UserAttributes]
type UserResponse = SingleResponse[UserAttributes]
type UserInvitationsResponse = Response[UserInvitationAttributes]
type UserInvitationResponse = SingleResponse[UserInvitationAttributes]

// Add ResourceType constants to client_types.go:
// ResourceTypeUsers ResourceType = "users"
// ResourceTypeUserInvitations ResourceType = "userInvitations"

2. internal/asc/client_users.go (~150-200 lines)

// Client methods pattern (see client_apps.go for examples):
func (c *Client) GetUsers(ctx context.Context, opts ...UsersOption) (*UsersResponse, error)
func (c *Client) GetUser(ctx context.Context, userID string) (*UserResponse, error)
func (c *Client) UpdateUser(ctx context.Context, userID string, attrs UserUpdateAttributes) (*UserResponse, error)
func (c *Client) DeleteUser(ctx context.Context, userID string) error

func (c *Client) GetUserInvitations(ctx context.Context, opts ...UserInvitationsOption) (*UserInvitationsResponse, error)
func (c *Client) CreateUserInvitation(ctx context.Context, attrs UserInvitationCreateAttributes) (*UserInvitationResponse, error)
func (c *Client) GetUserInvitation(ctx context.Context, inviteID string) (*UserInvitationResponse, error)
func (c *Client) DeleteUserInvitation(ctx context.Context, inviteID string) error

// Visible apps relationship methods:
func (c *Client) GetUserVisibleApps(ctx context.Context, userID string) (*AppsResponse, error)
func (c *Client) AddUserVisibleApps(ctx context.Context, userID string, appIDs []string) error
func (c *Client) RemoveUserVisibleApps(ctx context.Context, userID string, appIDs []string) error

3. internal/asc/users_output.go (~100-150 lines)

// Table/markdown formatters following output_apps.go pattern:
func printUsersTable(resp *UsersResponse) error
func printUsersMarkdown(resp *UsersResponse) error
func printUserInvitationsTable(resp *UserInvitationsResponse) error
func printUserInvitationsMarkdown(resp *UserInvitationsResponse) error

4. cmd/users.go (~350-400 lines)

// Command structure:
func UsersCommand() *ffcli.Command  // Parent with subcommands
func UsersListCommand() *ffcli.Command
func UsersGetCommand() *ffcli.Command
func UsersUpdateCommand() *ffcli.Command
func UsersDeleteCommand() *ffcli.Command
func UsersInviteCommand() *ffcli.Command
func UsersInvitesListCommand() *ffcli.Command
func UsersInvitesGetCommand() *ffcli.Command
func UsersInvitesRevokeCommand() *ffcli.Command

// Standard flags for list commands:
// --limit, --paginate, --next, --output, --pretty
// Filter flags: --email

// Delete/Revoke require --confirm flag

5. Register in cmd/commands.go
Add UsersCommand() to RootCommand().Subcommands

6. Update internal/asc/output_core.go
Add cases for *UsersResponse, *UserResponse, *UserInvitationsResponse, *UserInvitationResponse in both PrintMarkdown and PrintTable switches.

API Endpoints Reference

GET    /v1/users                                    → GetUsers
GET    /v1/users/{id}                               → GetUser  
PATCH  /v1/users/{id}                               → UpdateUser
DELETE /v1/users/{id}                               → DeleteUser
GET    /v1/users/{id}/visibleApps                   → GetUserVisibleApps
POST   /v1/users/{id}/relationships/visibleApps     → AddUserVisibleApps
DELETE /v1/users/{id}/relationships/visibleApps     → RemoveUserVisibleApps

GET    /v1/userInvitations                          → GetUserInvitations
POST   /v1/userInvitations                          → CreateUserInvitation
GET    /v1/userInvitations/{id}                     → GetUserInvitation
DELETE /v1/userInvitations/{id}                     → DeleteUserInvitation

Testing

  • Add CLI validation tests in cmd/commands_test.go or new cmd/users_test.go
  • Add HTTP client tests in internal/asc/client_http_test.go following existing patterns
  • Run make test && make lint before committing

Commands to verify

make build
./asc users --help
./asc users list --help
./asc users invites --help
<!-- gh-comment-id:3795326318 --> @rudrankriyam commented on GitHub (Jan 24, 2026): @cursor ## Implementation Guide ### Codebase Context The CLI follows these patterns (see `docs/GO_STANDARDS.md`, `docs/CONTRIBUTING.md`): - Commands use `ffcli` with factory functions returning `*ffcli.Command` - All commands use `UsageFunc: DefaultUsageFunc` for consistent help formatting - Client methods live in `internal/asc/client*.go`, split by domain - Types use generics: `Resource[T]`, `Response[T]`, `SingleResponse[T]` (see `internal/asc/client_types.go`) - Output formatting uses switch statements in `internal/asc/output_core.go` ### File Structure Create these files: **1. `internal/asc/users.go`** (~200-300 lines) ```go // Types needed: type UserAttributes struct { Username string `json:"username"` FirstName string `json:"firstName"` LastName string `json:"lastName"` Email string `json:"email,omitempty"` Roles []string `json:"roles"` AllAppsVisible bool `json:"allAppsVisible"` ProvisioningAllowed bool `json:"provisioningAllowed"` } type UserInvitationAttributes struct { Email string `json:"email"` FirstName string `json:"firstName"` LastName string `json:"lastName"` Roles []string `json:"roles"` AllAppsVisible bool `json:"allAppsVisible"` ProvisioningAllowed bool `json:"provisioningAllowed"` ExpirationDate string `json:"expirationDate,omitempty"` } // Response types using existing generics: type UsersResponse = Response[UserAttributes] type UserResponse = SingleResponse[UserAttributes] type UserInvitationsResponse = Response[UserInvitationAttributes] type UserInvitationResponse = SingleResponse[UserInvitationAttributes] // Add ResourceType constants to client_types.go: // ResourceTypeUsers ResourceType = "users" // ResourceTypeUserInvitations ResourceType = "userInvitations" ``` **2. `internal/asc/client_users.go`** (~150-200 lines) ```go // Client methods pattern (see client_apps.go for examples): func (c *Client) GetUsers(ctx context.Context, opts ...UsersOption) (*UsersResponse, error) func (c *Client) GetUser(ctx context.Context, userID string) (*UserResponse, error) func (c *Client) UpdateUser(ctx context.Context, userID string, attrs UserUpdateAttributes) (*UserResponse, error) func (c *Client) DeleteUser(ctx context.Context, userID string) error func (c *Client) GetUserInvitations(ctx context.Context, opts ...UserInvitationsOption) (*UserInvitationsResponse, error) func (c *Client) CreateUserInvitation(ctx context.Context, attrs UserInvitationCreateAttributes) (*UserInvitationResponse, error) func (c *Client) GetUserInvitation(ctx context.Context, inviteID string) (*UserInvitationResponse, error) func (c *Client) DeleteUserInvitation(ctx context.Context, inviteID string) error // Visible apps relationship methods: func (c *Client) GetUserVisibleApps(ctx context.Context, userID string) (*AppsResponse, error) func (c *Client) AddUserVisibleApps(ctx context.Context, userID string, appIDs []string) error func (c *Client) RemoveUserVisibleApps(ctx context.Context, userID string, appIDs []string) error ``` **3. `internal/asc/users_output.go`** (~100-150 lines) ```go // Table/markdown formatters following output_apps.go pattern: func printUsersTable(resp *UsersResponse) error func printUsersMarkdown(resp *UsersResponse) error func printUserInvitationsTable(resp *UserInvitationsResponse) error func printUserInvitationsMarkdown(resp *UserInvitationsResponse) error ``` **4. `cmd/users.go`** (~350-400 lines) ```go // Command structure: func UsersCommand() *ffcli.Command // Parent with subcommands func UsersListCommand() *ffcli.Command func UsersGetCommand() *ffcli.Command func UsersUpdateCommand() *ffcli.Command func UsersDeleteCommand() *ffcli.Command func UsersInviteCommand() *ffcli.Command func UsersInvitesListCommand() *ffcli.Command func UsersInvitesGetCommand() *ffcli.Command func UsersInvitesRevokeCommand() *ffcli.Command // Standard flags for list commands: // --limit, --paginate, --next, --output, --pretty // Filter flags: --email // Delete/Revoke require --confirm flag ``` **5. Register in `cmd/commands.go`** Add `UsersCommand()` to `RootCommand().Subcommands` **6. Update `internal/asc/output_core.go`** Add cases for `*UsersResponse`, `*UserResponse`, `*UserInvitationsResponse`, `*UserInvitationResponse` in both `PrintMarkdown` and `PrintTable` switches. ### API Endpoints Reference ``` GET /v1/users → GetUsers GET /v1/users/{id} → GetUser PATCH /v1/users/{id} → UpdateUser DELETE /v1/users/{id} → DeleteUser GET /v1/users/{id}/visibleApps → GetUserVisibleApps POST /v1/users/{id}/relationships/visibleApps → AddUserVisibleApps DELETE /v1/users/{id}/relationships/visibleApps → RemoveUserVisibleApps GET /v1/userInvitations → GetUserInvitations POST /v1/userInvitations → CreateUserInvitation GET /v1/userInvitations/{id} → GetUserInvitation DELETE /v1/userInvitations/{id} → DeleteUserInvitation ``` ### Testing - Add CLI validation tests in `cmd/commands_test.go` or new `cmd/users_test.go` - Add HTTP client tests in `internal/asc/client_http_test.go` following existing patterns - Run `make test && make lint` before committing ### Commands to verify ```bash make build ./asc users --help ./asc users list --help ./asc users invites --help ```
Author
Owner

@cursor[bot] commented on GitHub (Jan 24, 2026):

Summary:

  • Added Users & Invitations models, client methods (including visible-apps relationship add/remove/set), and CLI commands with JSON/table/markdown output support.
  • Wired users/invitations into pagination and output core, plus new tabular/markdown formatters and delete/revoke result outputs.
  • Added CLI validation tests and HTTP client request tests for users/invitations endpoints.

Tests/verification:

  • make test && make lint
  • make build
  • ./asc users --help
  • ./asc users list --help
  • ./asc users invites --help

Note: Per environment rules I committed/pushed before running make test && make lint (those ran successfully afterward).

View PR
Open in Cursor Open in Web

<!-- gh-comment-id:3795326402 --> @cursor[bot] commented on GitHub (Jan 24, 2026): Summary: - Added Users & Invitations models, client methods (including visible-apps relationship add/remove/set), and CLI commands with JSON/table/markdown output support. - Wired users/invitations into pagination and output core, plus new tabular/markdown formatters and delete/revoke result outputs. - Added CLI validation tests and HTTP client request tests for users/invitations endpoints. Tests/verification: - `make test && make lint` - `make build` - `./asc users --help` - `./asc users list --help` - `./asc users invites --help` Note: Per environment rules I committed/pushed before running `make test && make lint` (those ran successfully afterward). <a href="https://github.com/rudrankriyam/App-Store-Connect-CLI/pull/101"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/view-pr-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/view-pr-light.svg"><img alt="View PR" src="https://cursor.com/view-pr-light.svg"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-f1254a4f-2b23-4150-b329-72c1bd74c1ac"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/open-in-cursor-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/open-in-cursor-light.svg"><img alt="Open in Cursor" src="https://cursor.com/open-in-cursor.svg"></picture></a>&nbsp;<a href="https://cursor.com/agents?id=bc-f1254a4f-2b23-4150-b329-72c1bd74c1ac"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/open-in-web-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/open-in-web-light.svg"><img alt="Open in Web" src="https://cursor.com/open-in-web.svg"></picture></a>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/App-Store-Connect-CLI#17
No description provided.