Skip to content

Commit ec1edef

Browse files
authored
Merge pull request #20 from github/gm/integrate-with-teams
Add support to sync cost centers with teams
2 parents 47fe24f + add2ec3 commit ec1edef

File tree

10 files changed

+2192
-349
lines changed

10 files changed

+2192
-349
lines changed

ORPHANED_USERS_FEATURE.md

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
# Orphaned User Detection and Removal Feature
2+
3+
## Overview
4+
5+
This feature automatically detects and optionally removes "orphaned users" from cost centers. Orphaned users are those who are assigned to a cost center but are no longer members of the corresponding GitHub team.
6+
7+
## Why This Feature?
8+
9+
When teams change over time (members leave, are removed, or switch teams), their cost center assignments can become stale. This feature keeps cost centers synchronized with actual team membership by:
10+
11+
1. **Detecting** users in cost centers who are no longer in the corresponding team
12+
2. **Reporting** these orphaned users with warnings
13+
3. **Optionally removing** them based on configuration
14+
15+
## How It Works
16+
17+
### Detection Logic
18+
19+
For each cost center being managed:
20+
1. Fetch the **expected members** from the GitHub team
21+
2. Fetch the **current members** from the cost center API
22+
3. Calculate orphaned users: `current_members - expected_members`
23+
4. Log warnings for any orphaned users found
24+
25+
### Removal Logic (when enabled)
26+
27+
If `teams.remove_orphaned_users: true`:
28+
- Automatically remove orphaned users from their cost centers
29+
- Log success/failure for each removal
30+
- Provide summary statistics
31+
32+
## Configuration
33+
34+
### Enable/Disable
35+
36+
Add to `config/config.yaml`:
37+
38+
```yaml
39+
teams:
40+
enabled: true
41+
scope: "enterprise" # or "organization"
42+
mode: "auto"
43+
44+
# Orphaned user handling
45+
remove_orphaned_users: false # Set to true to enable automatic removal
46+
```
47+
48+
### Default Behavior
49+
50+
- **Default**: `false` (disabled)
51+
- **When disabled**: Orphaned users are detected and logged but NOT removed
52+
- **When enabled**: Orphaned users are detected and automatically removed
53+
54+
## Usage Examples
55+
56+
### Plan Mode (Preview)
57+
58+
```bash
59+
# See what would happen (with removal disabled)
60+
python main.py --teams-mode --assign-cost-centers --mode plan
61+
62+
# Output shows:
63+
# MODE=plan: Orphaned user detection is DISABLED
64+
# Users in cost centers but not in teams will remain assigned
65+
```
66+
67+
```bash
68+
# With removal enabled in config
69+
python main.py --teams-mode --assign-cost-centers --mode plan
70+
71+
# Output shows:
72+
# MODE=plan: Orphaned user detection is ENABLED
73+
# In apply mode, users in cost centers but not in teams will be removed
74+
```
75+
76+
### Apply Mode (Execution)
77+
78+
```bash
79+
# Apply with removal disabled (default)
80+
python main.py --teams-mode --assign-cost-centers --mode apply --yes
81+
82+
# Adds users to cost centers but leaves orphaned users alone
83+
```
84+
85+
```bash
86+
# Apply with removal enabled
87+
python main.py --teams-mode --assign-cost-centers --mode apply --yes
88+
89+
# Output includes:
90+
# [INFO] Checking for orphaned users...
91+
# [WARNING] ⚠️ Found 3 orphaned users in cost center 'Team: Frontend'
92+
# [WARNING] ⚠️ alice is in cost center but not in team
93+
# [WARNING] ⚠️ bob is in cost center but not in team
94+
# [INFO] Removing 3 orphaned users from 'Team: Frontend'...
95+
# [INFO] ✅ Successfully removed 3 users from cost center
96+
# [INFO] 📊 Orphaned users summary: Found 3 orphaned users, successfully removed 3
97+
```
98+
99+
## API Methods Added
100+
101+
### 1. `get_cost_center_members(cost_center_id)`
102+
103+
**Purpose**: Fetch current members of a cost center
104+
105+
**Endpoint**: `GET /enterprises/{enterprise}/settings/billing/cost-centers/{cost_center_id}`
106+
107+
**Returns**: List of usernames currently assigned to the cost center
108+
109+
**Example**:
110+
```python
111+
members = github_manager.get_cost_center_members("abc-123-def")
112+
# Returns: ['alice', 'bob', 'charlie']
113+
```
114+
115+
### 2. `remove_users_from_cost_center(cost_center_id, usernames)`
116+
117+
**Purpose**: Remove multiple users from a cost center
118+
119+
**Endpoint**: `DELETE /enterprises/{enterprise}/settings/billing/cost-centers/{cost_center_id}/resource`
120+
121+
**Parameters**:
122+
- `cost_center_id`: ID of the cost center
123+
- `usernames`: List of usernames to remove
124+
125+
**Returns**: Dict mapping username → success status (True/False)
126+
127+
**Example**:
128+
```python
129+
results = github_manager.remove_users_from_cost_center(
130+
"abc-123-def",
131+
["alice", "bob"]
132+
)
133+
# Returns: {'alice': True, 'bob': True}
134+
```
135+
136+
## Implementation Details
137+
138+
### Files Modified
139+
140+
1. **`src/github_api.py`**
141+
- Added `get_cost_center_members()` method
142+
- Added `remove_users_from_cost_center()` method
143+
144+
2. **`src/config_manager.py`**
145+
- Added `teams_remove_orphaned_users` configuration property
146+
147+
3. **`src/teams_cost_center_manager.py`**
148+
- Added `_remove_orphaned_users()` private method
149+
- Modified `sync_team_assignments()` to call orphaned user detection
150+
- Added orphaned user handling in apply mode
151+
152+
4. **`config/config.yaml` & `config/config.example.yaml`**
153+
- Added `remove_orphaned_users` configuration option with documentation
154+
155+
5. **`main.py`**
156+
- Display `remove_orphaned_users` status in configuration output
157+
158+
### Logging
159+
160+
The feature provides comprehensive logging:
161+
162+
- **INFO**: General operation status
163+
- **WARNING**: Orphaned users detected
164+
- **ERROR**: API failures or removal failures
165+
- **DEBUG**: Detailed member counts
166+
167+
### Error Handling
168+
169+
- API failures are logged but don't stop execution
170+
- Individual user removal failures are tracked separately
171+
- Summary statistics show success/failure counts
172+
173+
## Use Cases
174+
175+
### Use Case 1: Team Restructuring
176+
177+
**Scenario**: Your engineering team is split into "Frontend" and "Backend" teams. Some engineers move from one team to another.
178+
179+
**Without this feature**:
180+
- Users remain in their old cost center
181+
- Cost reporting is inaccurate
182+
- Manual cleanup required
183+
184+
**With this feature**:
185+
```yaml
186+
teams:
187+
remove_orphaned_users: true
188+
```
189+
- Users automatically removed from old cost center
190+
- Added to new cost center
191+
- Cost reporting stays accurate
192+
193+
### Use Case 2: Employee Departures
194+
195+
**Scenario**: Team members leave the company and are removed from GitHub teams.
196+
197+
**Without this feature**:
198+
- Departed users remain in cost centers
199+
- Inflated cost center counts
200+
- Security/audit concerns
201+
202+
**With this feature**:
203+
- Departed users automatically removed from cost centers
204+
- Accurate headcount per cost center
205+
- Clean audit trail
206+
207+
### Use Case 3: Temporary Team Assignments
208+
209+
**Scenario**: Users temporarily join teams for projects, then return to their main team.
210+
211+
**With this feature enabled**:
212+
- Users are automatically moved back when they leave the temporary team
213+
- No manual cleanup needed
214+
215+
## Best Practices
216+
217+
### 1. Test in Plan Mode First
218+
219+
Always run with `--mode plan` to see what changes would be made:
220+
221+
```bash
222+
python main.py --teams-mode --assign-cost-centers --mode plan
223+
```
224+
225+
### 2. Enable Gradually
226+
227+
Start with `remove_orphaned_users: false` to see how many orphaned users exist:
228+
229+
```bash
230+
# Step 1: Run once to see orphaned users (they'll be logged as warnings)
231+
python main.py --teams-mode --assign-cost-centers --mode apply --yes
232+
233+
# Step 2: Review logs for orphaned users
234+
# Step 3: If comfortable, enable removal
235+
# Step 4: Run again with removal enabled
236+
```
237+
238+
### 3. Regular Sync Schedule
239+
240+
Run teams sync regularly to keep cost centers up-to-date:
241+
242+
```bash
243+
# Daily cron job
244+
0 2 * * * cd /path/to/repo && python main.py --teams-mode --assign-cost-centers --mode apply --yes
245+
```
246+
247+
### 4. Monitor Logs
248+
249+
Review execution logs for:
250+
- Number of orphaned users found
251+
- Removal success rates
252+
- Any API errors
253+
254+
### 5. Consider Impact
255+
256+
Before enabling `remove_orphaned_users: true`, consider:
257+
- Do you have users manually added to cost centers outside of team membership?
258+
- Are there legitimate reasons for users to be in cost centers but not teams?
259+
- Do you have adequate logging/monitoring?
260+
261+
## Limitations
262+
263+
1. **Plan Mode**: Cannot show specific orphaned users in plan mode because cost centers may not exist yet. Orphaned user detection only runs in apply mode after cost centers are created/resolved.
264+
265+
2. **Manual Assignments**: If you manually add users to cost centers outside of this tool, they will be detected as orphaned and removed if they're not in the corresponding team.
266+
267+
3. **API Rate Limits**: Checking cost center membership adds API calls. Large numbers of cost centers may hit rate limits.
268+
269+
4. **Single Cost Center**: Remember, users can only belong to ONE cost center at a time (GitHub API constraint).
270+
271+
## Troubleshooting
272+
273+
### Orphaned users not being removed
274+
275+
**Check**:
276+
1. Is `remove_orphaned_users: true` in config?
277+
2. Running in `--mode apply` (not plan)?
278+
3. Check logs for API errors
279+
280+
### False positives (users incorrectly identified as orphaned)
281+
282+
**Cause**: User is not in the team being synced
283+
284+
**Solutions**:
285+
- Verify team membership in GitHub
286+
- Check that correct teams are configured
287+
- Review team mappings in manual mode
288+
289+
### API 404 errors when checking cost center members
290+
291+
**Cause**: Cost center doesn't exist yet (plan mode issue)
292+
293+
**Solution**: This is expected in plan mode. Orphaned detection only runs in apply mode.
294+
295+
## Future Enhancements
296+
297+
Potential improvements:
298+
1. **Dry-run for orphaned users**: Show what would be removed without actually removing
299+
2. **Whitelist**: Configure specific users to never be removed
300+
3. **Notification**: Send alerts when orphaned users are found/removed
301+
4. **Audit log export**: Export orphaned user reports to CSV
302+
303+
## Summary
304+
305+
The orphaned user detection and removal feature helps maintain clean, accurate cost center assignments by:
306+
307+
- ✅ **Detecting** users who shouldn't be in cost centers
308+
- ✅ **Reporting** discrepancies with clear warnings
309+
- ✅ **Removing** orphaned users automatically (when enabled)
310+
- ✅ **Working** with both organization and enterprise team scopes
311+
- ✅ **Configurable** - enable/disable as needed
312+
- ✅ **Safe** - disabled by default, clear logging, error handling
313+
314+
This keeps your cost center data synchronized with actual team membership over time with minimal manual intervention.

0 commit comments

Comments
 (0)