@acarmisc/backstage-plugin-litellm-backend 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config.d.ts +9 -0
- package/dist/index.cjs.js +21 -14
- package/dist/index.cjs.js.map +2 -2
- package/dist/routes/teamUsage.js +21 -11
- package/dist/teamMemberUsage.d.ts +2 -0
- package/dist/teamMemberUsage.js +1 -0
- package/package.json +1 -1
package/config.d.ts
CHANGED
|
@@ -463,6 +463,8 @@ export interface Config {
|
|
|
463
463
|
* reaches:
|
|
464
464
|
* - managers of the team (members of its metadata.owning_group, with
|
|
465
465
|
* team management enabled);
|
|
466
|
+
* - team leads (members of the catalog group `<team_alias><leadGroupSuffix>`,
|
|
467
|
+
* when leadGroupSuffix is set);
|
|
466
468
|
* - members of the team holding one of `viewerRoles` in it;
|
|
467
469
|
* - members of the team granted `litellm.team.usage.read` (only
|
|
468
470
|
* consulted when permission.enabled is true).
|
|
@@ -480,6 +482,13 @@ export interface Config {
|
|
|
480
482
|
* @default []
|
|
481
483
|
*/
|
|
482
484
|
viewerRoles?: string[];
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Suffix of a catalog group named `<team_alias><suffix>` whose members
|
|
488
|
+
* are team leads (e.g. "-leads" -> group:default/abstrid-leads). For
|
|
489
|
+
* teams synced without metadata.owning_group. Unset: no lead access.
|
|
490
|
+
*/
|
|
491
|
+
leadGroupSuffix?: string;
|
|
483
492
|
};
|
|
484
493
|
};
|
|
485
494
|
|
package/dist/index.cjs.js
CHANGED
|
@@ -9449,7 +9449,8 @@ function readMemberBreakdownConfig(config) {
|
|
|
9449
9449
|
return {
|
|
9450
9450
|
enabled: config.getOptionalBoolean("litellm.teamUsage.memberBreakdown.enabled") ?? false,
|
|
9451
9451
|
viewerRoles: config.getOptionalStringArray("litellm.teamUsage.memberBreakdown.viewerRoles") ?? [],
|
|
9452
|
-
permissionEnabled: config.getOptionalBoolean("permission.enabled") ?? false
|
|
9452
|
+
permissionEnabled: config.getOptionalBoolean("permission.enabled") ?? false,
|
|
9453
|
+
leadGroupSuffix: config.getOptionalString("litellm.teamUsage.memberBreakdown.leadGroupSuffix") || void 0
|
|
9453
9454
|
};
|
|
9454
9455
|
}
|
|
9455
9456
|
function memberEmails(team, keys) {
|
|
@@ -11521,6 +11522,22 @@ function registerTeamUsageRoutes(router, ctx) {
|
|
|
11521
11522
|
teamBudgetVisibility
|
|
11522
11523
|
} = ctx;
|
|
11523
11524
|
const requireUser = createRequireUser(ctx);
|
|
11525
|
+
async function isTeamManager(team, tokenEntityRef) {
|
|
11526
|
+
const owningGroup = typeof team.metadata?.owning_group === "string" ? team.metadata.owning_group : void 0;
|
|
11527
|
+
if (ctx.teamMgmtEnabled && owningGroup && await isUserMemberOfGroup(tokenEntityRef, owningGroup, catalogClient, auth, logger)) {
|
|
11528
|
+
return true;
|
|
11529
|
+
}
|
|
11530
|
+
const suffix = ctx.memberBreakdownCfg.leadGroupSuffix;
|
|
11531
|
+
if (!suffix || !team.team_alias) return false;
|
|
11532
|
+
const slug = team.team_alias.toLowerCase().replace(/[^a-z0-9\-_.]/g, "-");
|
|
11533
|
+
return isUserMemberOfGroup(
|
|
11534
|
+
tokenEntityRef,
|
|
11535
|
+
`group:default/${slug}${suffix}`,
|
|
11536
|
+
catalogClient,
|
|
11537
|
+
auth,
|
|
11538
|
+
logger
|
|
11539
|
+
);
|
|
11540
|
+
}
|
|
11524
11541
|
router.get("/teams/:teamId/usage", requireUser, async (req, res) => {
|
|
11525
11542
|
try {
|
|
11526
11543
|
const { teamId } = req.params;
|
|
@@ -11533,20 +11550,11 @@ function registerTeamUsageRoutes(router, ctx) {
|
|
|
11533
11550
|
const userInfo = await getProvisionedUser(ctx, res);
|
|
11534
11551
|
const isMember = userInfo?.teams?.includes(teamId) ?? false;
|
|
11535
11552
|
let isManager = false;
|
|
11536
|
-
const managerCheckNeeded = ctx.teamMgmtEnabled && (!isMember || teamBudgetVisibility.hideTeamBudgetForMembers !== teamBudgetVisibility.hideTeamBudgetForManagers);
|
|
11553
|
+
const managerCheckNeeded = (ctx.teamMgmtEnabled || !!ctx.memberBreakdownCfg.leadGroupSuffix) && (!isMember || teamBudgetVisibility.hideTeamBudgetForMembers !== teamBudgetVisibility.hideTeamBudgetForManagers);
|
|
11537
11554
|
if (managerCheckNeeded) {
|
|
11538
11555
|
try {
|
|
11539
11556
|
const team = await withTeamFetchRetry(() => client.getTeamInfo(teamId));
|
|
11540
|
-
|
|
11541
|
-
if (owningGroup) {
|
|
11542
|
-
isManager = await isUserMemberOfGroup(
|
|
11543
|
-
tokenEntityRef,
|
|
11544
|
-
owningGroup,
|
|
11545
|
-
catalogClient,
|
|
11546
|
-
auth,
|
|
11547
|
-
logger
|
|
11548
|
-
);
|
|
11549
|
-
}
|
|
11557
|
+
isManager = await isTeamManager(team, tokenEntityRef);
|
|
11550
11558
|
} catch (err) {
|
|
11551
11559
|
const message2 = err instanceof Error ? err.message : String(err);
|
|
11552
11560
|
logger.warn(`Team-manager check failed: ${message2}`);
|
|
@@ -11600,8 +11608,7 @@ function registerTeamUsageRoutes(router, ctx) {
|
|
|
11600
11608
|
}
|
|
11601
11609
|
throw err;
|
|
11602
11610
|
}
|
|
11603
|
-
const
|
|
11604
|
-
const isManager = ctx.teamMgmtEnabled && !!owningGroup && await isUserMemberOfGroup(tokenEntityRef, owningGroup, catalogClient, auth, logger);
|
|
11611
|
+
const isManager = await isTeamManager(team, tokenEntityRef);
|
|
11605
11612
|
if (!isMember && !isManager) {
|
|
11606
11613
|
res.status(404).json({ error: "Team not found" });
|
|
11607
11614
|
return null;
|