Repository navigation
Conversation
…spec and SDKs The spec gains x-primitive-permission on every declared operation, the grant_forbidden and step-up error codes, the whoami grant fields, the CLI user login shapes, the org list, and the keys, credential inventory, audit event, credential policy and role read operations. Node, Python and Go get a typed GrantForbiddenError that still matches their existing API error type. Node also gets the generated Permission union and OPERATION_PERMISSIONS, a GrantSpec builder, and keys, credentials and roles resources.
…es commands primitive login asks for a login as the person (login_kind user) and falls back to today's org-bound login when the server refuses the field. Such a login lists organizations with primitive orgs, switches with primitive org use, and takes --org on every command. Per-org tokens are exchanged when missing or expired and once more on a 401; a refused exchange reports its reason. Saved org-bound logins, API keys and connected agent profiles keep working as before and refuse a different organization. Also primitive keys create, list, rotate and revoke (with --expires, --permission and --step-up), login --permission, whoami showing the grant and answering --check, and read-only roles commands.
…hed workers, nullable grant details - Wait briefly for the credentials lock during exchanges instead of failing, and use another process's fresh token after a 401. - Take the 401 retry token from the request header. - Resolve organization names only through the full list, so a shared name is refused instead of matching a cached organization. - Rename the selection variable to PRIMITIVE_CLI_ORG, apply --org after the receiver and signal workers start, and keep memories:<cmd> --org intact. - payloads push and pull use the per-org token for user logins and --org. - doctor and the root sign-in line recognize user logins. - whoami --check refuses a connected profile; the grant lines appear only when the server reports a grant, and --json without --grant makes no extra request. - login checks a saved user login without an organization against the server before calling it valid. - grant_forbidden detail fields are nullable, so the Go SDK decodes errors that carry null details. - Neutral wording in docs and help text. - Raise the agent network smoke script's output buffer for list-operations.
|
@greptileai review |
[Medium impact] The PR appears safe to merge; no new blocking issues were found. Reviews (7) · Last reviewed commit: "Keep the public built-in role list to ow..." · Reviewed by Greptile |
…g for profile-bound agent commands, accept empty revoke responses
|
@greptileai review |
|
@greptileai review |
…ckground child never inherits it
|
Summary finding (listener child inherits the organization selection) addressed in ea08619: |
… organization selection
|
Summary finding (enrollment leaves receiving stopped) addressed in 66ab747: agent setup starts the profile's background listener with the organization selection removed from its environment ( |
…n operator role The CLI keeps keys list, which shows key metadata and never a secret, and says keys are created, rotated and revoked in the dashboard. The generated create, rotate, update and revoke commands are left out as well. The SDK client methods stay. The spec gains BuiltinRoleKey (owner, admin, operator, member, restricted). Node exports BUILTIN_ROLE_KEYS and BuiltinRoleKey, Python generates the enum and Go adds BuiltinRoleKey constants.
|
@greptileai review |
Role keys stay plain strings, so a key outside the list still parses.
|
@greptileai review |
Client side of fine-grained keys, grants and CLI organization switching. Draft until the matching server-side handlers are available. Every new path is feature-detected, so released servers keep working with this build.
Spec and SDKs
x-primitive-permissionon every operation the server declares, plusgrant_forbidden, the step-up codes andgrant_forbiddendetail fields in the error schema.listCliOrgs,createKey,rotateKey,updateKey,getKeyBuilder,listCredentials,revokeCredential,listCredentialEvents,getCredentialPolicy,listRoles,listGroups,listMailboxAccess,getAccessMode.StartCliLoginInputgainslogin_kindandrequested_grant. The user login poll shape is a separateCliUserLoginPollResultschema, so the generated poll result type is unchanged.whoamigains optionalgrantandcheckfields. Thegrant_forbiddendetail fields are nullable, so Go decodes error bodies that carry null details. Itsinclude,checkandresourcequery parameters are described in the operation, not declared, because declaring the first parameter would change the generated GoWhoamisignature.GrantForbiddenError(aPrimitiveApiErrorsubclass, so existing checks still match),isGrantForbiddenError, andPERMISSIONS,PermissionandOPERATION_PERMISSIONS, generated from the spec intopermissions.generated.ts. Also aGrantSpecbuilder,client.keys,client.credentials,client.roles,client.account.whoami({ grant: true })andclient.account.checkPermission(). The operation manifest gainspermissions.GrantForbiddenError(PrimitiveAPIError)with the detail fields.GrantForbiddenError, which embeds*APIError.errors.Asmatches both types.CLI
primitive loginsendslogin_kind: "user"and retries without it on400 validation_error, so servers without user logins get today's org-bound login. The saved file for an org-bound login is byte-compatible with today's. A user login is saved asauth_method: "user_grant": the standard fields hold the current organization's token, anduser_grantholds the identity token and a small per-org token cache.primitive orgslists your organizations, with the refusal reason for each one you cannot use.primitive org use <org>switches by id or name.--org <org>(orPRIMITIVE_CLI_ORG) works on every command.bin/run.jsstrips it just before oclif parses the command, after the detached receiver and signal workers start, so they never inherit it.primitive memorieskeeps its own boolean--org. Organization names resolve against the full list, so a name two organizations share is refused. Parallel commands wait briefly for the credentials lock rather than failing.not_a_member,cli_access_disabled_by_org,role_insufficient,cli_access_revoked). The identity token is refreshed when needed, andinvalid_grantremoves the saved login.primitive logouton a user login revokes the refresh token, which signs out of every organization.primitive login --permission <p>sendsrequested_grant. If the server refuses it (grant_not_available, or an older server'svalidation_error), the login stops. It is never retried with a wider grant.primitive keys listshows API key metadata (id, prefix, name, grant, expiry, last use) and never a secret. The CLI has no command that creates, rotates, updates or revokes a key or other credential: API keys are created, rotated and revoked in the dashboard, and the help and README say so. The generatedkeys:create-key,keys:rotate-key,keys:update-keyandcredentials:revoke-credentialcommands are left out too, along with their entries inlist-operations,describeand fish completion (DASHBOARD_ONLY_OPERATION_IDSincli-operations.ts). The SDK client methods for keys stay.primitive whoamishows organization, role and grant when the server reports them.--check <permission>prints the decision and exits 1 when the permission is not allowed.--grantadds the grant to--json.primitive roles list|groups|mailbox-access|access-modeare read-only.roles listhelp names the built-in roles,operatorincluded.Built-in operator role
BuiltinRoleKey:owner,admin,operator,member.operatorhas every permissionadminhas except managing members, changing roles, sending invitations and billing.Role.key,CliOrg.roleandCliOrgAccessToken.rolepoint to it and stay plain strings, so template, custom and unlisted keys still decode.CredentialPolicy.cli_accesssaysowners_and_adminsadmitsowner,adminandoperator.BUILTIN_ROLE_KEYS(generated from the spec intopermissions.generated.ts) and theBuiltinRoleKeytype. Python: the generatedBuiltinRoleKeyenum. Go:BuiltinRoleKey,RoleOwnerthroughRoleMember,BuiltinRoleKeys()andIsBuiltinRoleKey, with a test that pins them to the spec enum.grant_forbiddenerrors print a hint naming the missing permission.Unchanged: connected agent profiles,
pconn_detection, and API keys. With--orgnaming a different organization, an org-bound login, an API key or a connected profile refuses the command rather than act elsewhere.Notes for review
keys listand the inventory and audit operations only for an owner or admin in a dashboard session. From a CLI login (an OAuth token) they show the server's 403.--permissionvalues are sent as space-separated permissions inrequested_grant. The server accepts onlyprimitive:apithere, so narrowed logins are refused.Tests
sdk-node/tests/api/grants.test.ts:GrantForbiddenErrorparsing (typed details, other refusals stayPrimitiveApiError, malformed details), the generated permissions,GrantSpec, and the keys, credentials, roles and whoami calls.cli-node/tests/oclif/user-grant.test.tsruns against a mock HTTP server:--permissionrefusals;loginwith--org, and the org-bound save from an old server;--orgby name with caching;invalid_grant;unsupported_grant_typeandfeature_disabled;--orgrefused for them and for API keys;orgs,org use,whoamiand--checkcommands;cli-node/tests/oclif/keys-roles.test.ts:--orgargv handling,keys list, that no create, rotate, update or revoke command or generated operation is offered, and the roles commands with an operator row.cli-node/tests/oclif/user-grant.test.tsalso lists and switches to an organization where the role isoperator.cli-node/tests/oclif/commands-manifest-coverage.test.ts: every manifest operation has a command except exactly the dashboard-only ones.sdk-node/tests/api/grants.test.ts,sdk-python/tests/test_grant_forbidden.pyandsdk-go/roles_test.go: the built-in role keys includeoperator, and a key outside the list still parses.sdk-go/grant_forbidden_test.goandsdk-python/tests/test_grant_forbidden.py.make node-check-generated,go-check,python-checkandshared-checkall pass. sdk-node: 1277 tests. cli-node: lint and typecheck are clean, and the suite passes in a clean environment. A few notification, receipt and pending-mail tests time out under full-suite load on a busy machine; they are untouched here and the set that times out changes between runs.make cli-buildsucceeds.Nothing was run against a deployed environment.