Skip to content

Commit 930daac

Browse files
author
Baton Admin
committed
chore: update connector skills via baton-admin
1 parent 4b7dfd7 commit 930daac

File tree

1 file changed

+285
-0
lines changed

1 file changed

+285
-0
lines changed
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
# ref-traits
2+
3+
Trait selection guide for resource types.
4+
5+
---
6+
7+
## Available Traits
8+
9+
| Trait | Purpose | Typical Resources |
10+
|-------|---------|-------------------|
11+
| User | Human identity | Users, accounts, members |
12+
| Group | Collection of users | Groups, teams, departments |
13+
| Role | Named permission set | Roles, permission groups |
14+
| App | Non-human identity | Service accounts, API keys, apps |
15+
16+
---
17+
18+
## CRITICAL: User vs App (Caused Production Revert)
19+
20+
**The Rule:**
21+
- **User** = Human being who logs in
22+
- **App** = Everything else (systems, accounts, services, machines)
23+
24+
**Common Mistake**: Using User trait for "accounts" that aren't humans.
25+
26+
| Resource | WRONG | CORRECT | Why |
27+
|----------|-------|---------|-----|
28+
| AWS Account | User | **App** | AWS account is a container, not a person |
29+
| Service Account | User | **App** | Machine identity, not human |
30+
| API Key | User | **App** | Credential, not person |
31+
| Bot User | User | **App** | Automated, not human |
32+
| OAuth Client | User | **App** | Application identity |
33+
| IAM Role | User | **App** | Assumed by services |
34+
35+
**The Revert (baton-aws #84)**: AWS Account IAM was modeled as User. Had to revert to App. The word "account" is ambiguous - AWS accounts are not user accounts.
36+
37+
**Ask**: "Can this entity log into a web browser and click things?" If no, it's probably an App.
38+
39+
---
40+
41+
## User Trait
42+
43+
For human identities that can authenticate.
44+
45+
```go
46+
rs.NewUserResource(
47+
displayName,
48+
userResourceType,
49+
userID,
50+
[]rs.UserTraitOption{
51+
rs.WithEmail(email, isPrimary), // Email address
52+
rs.WithUserLogin(login), // Login/username
53+
rs.WithStatus(v2.UserTrait_Status_STATUS_ENABLED),
54+
rs.WithUserProfile(map[string]interface{}{
55+
"first_name": firstName,
56+
"last_name": lastName,
57+
}),
58+
},
59+
)
60+
```
61+
62+
**Required:** At least one of `WithEmail` or `WithUserLogin`
63+
64+
**Status values:**
65+
- `STATUS_ENABLED` - Active user
66+
- `STATUS_DISABLED` - Suspended/inactive
67+
- `STATUS_DELETED` - Soft deleted
68+
69+
---
70+
71+
## Group Trait
72+
73+
For collections of users. Groups are grantable (users can be members).
74+
75+
```go
76+
rs.NewGroupResource(
77+
displayName,
78+
groupResourceType,
79+
groupID,
80+
[]rs.GroupTraitOption{
81+
rs.WithGroupProfile(map[string]interface{}{
82+
"description": description,
83+
}),
84+
},
85+
rs.WithParentResourceID(parentID), // Optional hierarchy
86+
)
87+
```
88+
89+
**Entitlement pattern for groups:**
90+
```go
91+
func (g *groupBuilder) Entitlements(ctx context.Context, resource *v2.Resource,
92+
token *pagination.Token) ([]*v2.Entitlement, string, annotations.Annotations, error) {
93+
94+
// Groups typically have a "member" entitlement
95+
return []*v2.Entitlement{
96+
sdkEntitlement.NewAssignmentEntitlement(
97+
resource,
98+
"member",
99+
sdkEntitlement.WithGrantableTo(userResourceType),
100+
sdkEntitlement.WithDisplayName("Member"),
101+
sdkEntitlement.WithDescription("Member of the group"),
102+
),
103+
}, "", nil, nil
104+
}
105+
```
106+
107+
---
108+
109+
## Role Trait
110+
111+
For named permission sets. Roles define what actions are allowed.
112+
113+
```go
114+
rs.NewRoleResource(
115+
displayName,
116+
roleResourceType,
117+
roleID,
118+
[]rs.RoleTraitOption{
119+
rs.WithRoleProfile(map[string]interface{}{
120+
"permissions": permissions,
121+
}),
122+
},
123+
)
124+
```
125+
126+
**Entitlement pattern for roles:**
127+
```go
128+
func (r *roleBuilder) Entitlements(ctx context.Context, resource *v2.Resource,
129+
token *pagination.Token) ([]*v2.Entitlement, string, annotations.Annotations, error) {
130+
131+
// Roles typically have an "assigned" entitlement
132+
return []*v2.Entitlement{
133+
sdkEntitlement.NewAssignmentEntitlement(
134+
resource,
135+
"assigned",
136+
sdkEntitlement.WithGrantableTo(userResourceType),
137+
sdkEntitlement.WithDisplayName("Assigned"),
138+
sdkEntitlement.WithDescription("Has this role assigned"),
139+
),
140+
}, "", nil, nil
141+
}
142+
```
143+
144+
---
145+
146+
## App Trait
147+
148+
For non-human identities: service accounts, API keys, applications.
149+
150+
```go
151+
rs.NewAppResource(
152+
displayName,
153+
appResourceType,
154+
appID,
155+
[]rs.AppTraitOption{
156+
rs.WithAppProfile(map[string]interface{}{
157+
"client_id": clientID,
158+
}),
159+
},
160+
)
161+
```
162+
163+
**When to use App vs User:**
164+
- **App:** API keys, service accounts, OAuth clients, integrations
165+
- **User:** Human accounts, even if they authenticate via API key
166+
167+
---
168+
169+
## Trait Selection Decision Tree
170+
171+
```
172+
Is it a human identity?
173+
├─ Yes → User trait
174+
│ └─ Can it be disabled/suspended? → WithStatus
175+
└─ No
176+
├─ Is it a collection of users? → Group trait
177+
├─ Is it a permission set? → Role trait
178+
└─ Is it a service/app identity? → App trait
179+
```
180+
181+
---
182+
183+
## Parent Resources
184+
185+
Use `WithParentResourceID` for hierarchy:
186+
187+
```go
188+
// User belongs to an organization
189+
rs.NewUserResource(name, userType, id, opts,
190+
rs.WithParentResourceID(&v2.ResourceId{
191+
ResourceType: "organization",
192+
Resource: orgID,
193+
}),
194+
)
195+
196+
// Group belongs to a workspace
197+
rs.NewGroupResource(name, groupType, id, opts,
198+
rs.WithParentResourceID(&v2.ResourceId{
199+
ResourceType: "workspace",
200+
Resource: wsID,
201+
}),
202+
)
203+
```
204+
205+
**When to use parents:**
206+
- Multi-tenant systems (user belongs to org)
207+
- Nested structures (group in workspace in org)
208+
- Scoped permissions (role within project)
209+
210+
---
211+
212+
## Common Patterns
213+
214+
### SaaS with Organizations
215+
216+
```
217+
Organization (no trait, or custom)
218+
├── User (User trait, parent=org)
219+
├── Group (Group trait, parent=org)
220+
└── Role (Role trait, parent=org)
221+
```
222+
223+
### DevOps Tool (GitHub-like)
224+
225+
```
226+
Organization (no trait)
227+
├── Team (Group trait, parent=org)
228+
├── Repository (no trait, parent=org)
229+
│ └── Collaborator role (Role trait, parent=repo)
230+
└── Member (User trait, parent=org)
231+
```
232+
233+
### Cloud Provider (AWS-like)
234+
235+
```
236+
Account (no trait)
237+
├── IAM User (User trait, parent=account)
238+
├── IAM Group (Group trait, parent=account)
239+
├── IAM Role (Role trait, parent=account)
240+
└── Service Account (App trait, parent=account)
241+
```
242+
243+
---
244+
245+
## Trait Options Reference
246+
247+
### User Trait Options
248+
249+
| Option | Purpose | C1 Usage |
250+
|--------|---------|----------|
251+
| `WithEmail(email, isPrimary)` | Email address | Identity matching |
252+
| `WithUserLogin(login)` | Username/login | Identity matching |
253+
| `WithStatus(status)` | Account status | Lifecycle management |
254+
| `WithUserProfile(map)` | Additional fields | Display in UI |
255+
256+
### Group Trait Options
257+
258+
| Option | Purpose | C1 Usage |
259+
|--------|---------|----------|
260+
| `WithGroupProfile(map)` | Additional fields | Display in UI |
261+
262+
### Role Trait Options
263+
264+
| Option | Purpose | C1 Usage |
265+
|--------|---------|----------|
266+
| `WithRoleProfile(map)` | Additional fields | Display in UI |
267+
268+
### App Trait Options
269+
270+
| Option | Purpose | C1 Usage |
271+
|--------|---------|----------|
272+
| `WithAppProfile(map)` | Additional fields | Display in UI |
273+
274+
---
275+
276+
## What NOT to Sync
277+
278+
Not everything needs to be a resource:
279+
280+
- **Settings/preferences** - Not access-related
281+
- **Audit logs** - Read-only, not grantable
282+
- **Temporary tokens** - Ephemeral, not managed
283+
- **System accounts** - Built-in, can't be modified
284+
285+
Ask: "Can C1 grant or revoke access to this?" If no, don't sync it.

0 commit comments

Comments
 (0)