Skip to content

feat: add admin apis (CM-1235)#4211

Open
ulemons wants to merge 8 commits into
mainfrom
feat/steward-admin-actions-api
Open

feat: add admin apis (CM-1235)#4211
ulemons wants to merge 8 commits into
mainfrom
feat/steward-admin-actions-api

Conversation

@ulemons

@ulemons ulemons commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Expose four admin-facing endpoints to support stewardship lifecycle management in the OSSPREY Program dashboard. Admins can now open a package for stewardship, assign individual stewards, escalate with a structured resolution path, and update stewardship status — all with audit logging to stewardship_activity.

Changes

  • POST /api/public/v1/stewardships — opens a package for stewardship (upserts status → open); body takes a PURL, normalised before DB lookup
  • PUT /api/public/v1/stewardships/:id/steward — assigns a steward (lead or co_steward) via soft-delete + insert pattern; entire operation is wrapped in a transaction to keep the audit log consistent
  • PUT /api/public/v1/stewardships/:id/escalate — sets status → escalated and records one of 6 resolution paths in stewardship_activity metadata
  • PUT /api/public/v1/stewardships/:id/status — updates stewardship status (assessing, active, needs_attention, blocked, inactive); inactiveReason is required when setting inactive and is preserved on other transitions (not overwritten to null)
  • DAL (stewardships.ts) — added getStewardshipById, openStewardshipByPurl, assignSteward, escalateStewardship, updateStewardshipStatus; exported ESCALATION_RESOLUTION_PATHS, INACTIVE_REASONS, and STEWARDSHIP_UPDATABLE_STATUSES as shared constants
  • Auth0 scope checks commented out with TODO following the same pattern as existing packages endpoints (restore once write:stewardships is provisioned on the Auth0 staging tenant)

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Performance improvement
  • Chore / dependency update
  • Documentation

JIRA ticket

ticket


Note

High Risk
New write endpoints mutate stewardship state and assignments with scope enforcement disabled until Auth0 provisions write:stewardships, widening who can change production-like data if tokens leak.

Overview
Adds OAuth-protected write APIs under /api/v1/stewardships for OSSPREY admin workflows: open by PURL, assign stewards (optional moveToAssessing), escalate with a resolution path, and update status (with required inactiveReason when inactive). Handlers delegate to new DAL functions that upsert/update stewardships, manage stewardship_stewards, and append stewardship_activity audit rows.

Read-side changes expose stewardshipId on package list/detail and populate package detail stewardship with real stewards and lastActivityAt via getStewardshipSummary. Package OpenAPI documents the new IDs; a separate stewardships OpenAPI describes the mutations.

write:stewardships scope checks are commented out (same pattern as existing package stewardship reads) until Auth0 staging is provisioned.

Reviewed by Cursor Bugbot for commit 01f5fee. Bugbot is set up for automated code reviews on this repo. Configure here.

@ulemons ulemons self-assigned this Jun 15, 2026
Copilot AI review requested due to automatic review settings June 15, 2026 10:41
@ulemons ulemons added the Feature Created by Linear-GitHub Sync label Jun 15, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new set of Auth0-protected public v1 API endpoints plus supporting DAL methods to manage OSSPCKGS “stewardship” lifecycle actions (open, assign steward, escalate, update status) while writing audit entries to stewardship_activity.

Changes:

  • Added DAL helpers for stewardship CRUD-ish workflows and exported shared constants for request validation.
  • Added four new /api/public/v1/stewardships/* handlers with Zod validation and wired them into the v1 router.
  • Added routing for the new stewardship endpoints under the existing Auth0 oauth2Middleware.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
services/libs/data-access-layer/src/osspckgs/stewardships.ts Adds DAL APIs for opening, assigning, escalating, and status updates + shared enum constants.
backend/src/api/public/v1/stewardships/openStewardship.ts New POST handler to open a package for stewardship via normalized PURL.
backend/src/api/public/v1/stewardships/assignSteward.ts New PUT handler to soft-delete + insert a steward assignment.
backend/src/api/public/v1/stewardships/escalate.ts New PUT handler to escalate a stewardship with a resolution path.
backend/src/api/public/v1/stewardships/updateStatus.ts New PUT handler to update stewardship status with conditional inactiveReason validation.
backend/src/api/public/v1/stewardships/schemas.ts Adds shared param schema for numeric stewardship id.
backend/src/api/public/v1/stewardships/index.ts Adds stewardships router + rate limiting (scope checks currently commented out).
backend/src/api/public/v1/index.ts Mounts the new /stewardships router under v1 with Auth0 middleware.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread services/libs/data-access-layer/src/osspckgs/stewardships.ts
Comment thread services/libs/data-access-layer/src/osspckgs/stewardships.ts Outdated
Comment thread services/libs/data-access-layer/src/osspckgs/stewardships.ts
Comment thread services/libs/data-access-layer/src/osspckgs/stewardships.ts
Comment thread backend/src/api/public/v1/stewardships/index.ts
@ulemons ulemons force-pushed the feat/steward-admin-actions-api branch from 8af239c to 3f87f89 Compare June 15, 2026 10:51
Copilot AI review requested due to automatic review settings June 15, 2026 11:13
ulemons added 4 commits June 15, 2026 13:29
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
@ulemons ulemons force-pushed the feat/steward-admin-actions-api branch from e1b707e to 03abe99 Compare June 15, 2026 11:29
Comment thread services/libs/data-access-layer/src/osspckgs/stewardships.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Comment thread backend/src/api/public/v1/packages/getPackage.ts
Comment thread services/libs/data-access-layer/src/osspckgs/stewardships.ts
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Copilot AI review requested due to automatic review settings June 15, 2026 14:17
Comment thread services/libs/data-access-layer/src/osspckgs/stewardships.ts
Comment thread services/libs/data-access-layer/src/osspckgs/stewardships.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Comment thread services/libs/data-access-layer/src/osspckgs/stewardships.ts
Comment thread services/libs/data-access-layer/src/osspckgs/stewardships.ts
Comment thread backend/src/api/public/v1/stewardships/openapi.yaml
Comment thread backend/src/api/public/v1/stewardships/index.ts
ulemons added 2 commits June 15, 2026 16:52
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Copilot AI review requested due to automatic review settings June 15, 2026 16:35

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 01f5fee. Configure here.

WHERE id = $(stewardshipId)
AND status IN ('unassigned', 'open')
RETURNING id, package_id, status, origin, version, opened_at,
last_status_at, inactive_reason, resolution_path, status_note, created_at, updated_at

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid stewardship columns in SQL

High Severity

When moveToAssessing is true, assignSteward runs an UPDATE that sets and returns resolution_path and status_note on stewardships, but those columns are not defined in the stewardship migration schema, so PostgreSQL rejects the query and the assign endpoint fails for that flow.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 01f5fee. Configure here.

`,
{ stewardshipId, actorUserId: data.assignedBy, metadata: JSON.stringify({ status: 'assessing' }) },
)
if (updated) finalStewardship = mapStewardshipRow(updated)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moveToAssessing succeeds without status change

Medium Severity

With moveToAssessing true, the status UPDATE only applies when status is unassigned or open. If the stewardship is already past that (e.g. active), the handler still returns 200 with stewards updated but the prior status unchanged, so clients believe an atomic move to assessing occurred when it did not.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 01f5fee. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (1)

backend/src/api/public/v1/packages/openapi.yaml:443

  • The field-level description for stewards still says "Null in v1", but GET /packages/detail can now return an array (possibly empty) when a stewardship exists.
            stewards:
              description: Assigned stewards or null. Null in v1.
              oneOf:
                - type: array
                  items:
                    $ref: '#/components/schemas/Steward'
                - type: 'null'

Comment on lines +223 to +232
SET status = 'assessing',
last_status_at = NOW(),
resolution_path = NULL,
status_note = NULL,
updated_at = NOW()
WHERE id = $(stewardshipId)
AND status IN ('unassigned', 'open')
RETURNING id, package_id, status, origin, version, opened_at,
last_status_at, inactive_reason, resolution_path, status_note, created_at, updated_at
),
Comment on lines +385 to +388
SET status = $(status),
last_status_at = NOW(),
inactive_reason = CASE WHEN $(status) = 'inactive' THEN $(inactiveReason) ELSE NULL END,
updated_at = NOW()
Comment on lines +1 to +19
import { Router } from 'express'

import { createRateLimiter } from '@/api/apiRateLimiter'
// TODO: restore once write:stewardships is added to Auth0 staging tenant
// import { requireScopes } from '@/api/public/middlewares/requireScopes'
import { safeWrap } from '@/middlewares/errorMiddleware'

// import { SCOPES } from '@/security/scopes'
import { assignStewardHandler } from './assignSteward'
import { escalateHandler } from './escalate'
import { openStewardship } from './openStewardship'
import { updateStatusHandler } from './updateStatus'

const rateLimiter = createRateLimiter({ max: 60, windowMs: 60 * 1000 })

export function stewardshipsRouter(): Router {
const router = Router()

router.use(rateLimiter)
Comment on lines +88 to +96
inactiveReason:
type:
- string
- 'null'
enum:
- quarterly_cadence_missed
- stepped_down
- no_longer_critical
- 'null'
Comment on lines 425 to 428
stewardship:
type: object
description: Stewardship state. In v1 always unassigned with no stewards or activity.
properties:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature Created by Linear-GitHub Sync

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants