Skip to main content

Automated remediation PR (npm)

Where the remediation dry-run only previews the package.json edit, the automated remediation PR actually opens a pull request on your project's GitHub repository that applies the bump — branch, commit, and PR — using a short-lived GitHub App installation token.

This is a privileged write to an external repository, so it is opt-in and team-admin only.

Opt-in is the only authority over the target repository

The portal will never open a PR on a repository you have not explicitly linked to the project. The target repo is derived only from the project's opted-in GitHub App installation — there is no request field that lets a caller name a repository. If the project is not opted in, the request is refused with 409.

Prerequisites​

  1. A team admin has registered a GitHub App credential for the team.
  2. That credential's installation is linked to the project with a repository_full_name (the opt-in). The linked installation's credential must not be revoked.

Endpoint​

POST /v1/projects/{project_id}/remediation/npm/pull-request

Authentication is required (JWT or API key). The caller must be a team admin of the project's team. A project you cannot see returns 404 (existence-hide).

Request body (optional)​

{
"manifest": "{\n \"dependencies\": { \"lodash\": \"^4.17.20\" }\n}\n"
}
FieldTypeNotes
manifeststring | nullRaw package.json to edit. When omitted, the manifest is best-effort read from the project's latest preserved scan source. The target repository is not part of this body — it is derived from the opt-in.

Responses​

StatusMeaning
201 CreatedA new remediation PR was opened. The body is the PR record.
200 OKAn existing open PR with the same set of bumps was returned (idempotent — no duplicate PR).
204 No ContentNothing to remediate (the manifest already satisfies the fixes).
{
"id": "…",
"project_id": "…",
"ecosystem": "npm",
"repository_full_name": "acme/widget",
"head_branch": "trustedoss/remediation-1a2b3c4d",
"base_branch": "main",
"pr_number": 42,
"pr_url": "https://github.com/acme/widget/pull/42",
"status": "open",
"package_changes": [
{ "package": "lodash", "from": "4.17.20", "to": "4.17.21" }
],
"created_at": "2026-05-25T12:00:00Z",
"updated_at": "2026-05-25T12:00:01Z"
}

Idempotency​

Each attempt is fingerprinted by its set of bumps (package → target version). If an open PR with the same fingerprint already exists for the project, that PR is returned instead of opening a second one. A failed or superseded record does not block a fresh attempt.

What the PR contains​

  • A new branch trustedoss/remediation-<short-fingerprint> off the repo's default branch.
  • A single commit editing only package.json.
  • A pull request describing the bumps.

The lockfile is not edited — run npm install to regenerate package-lock.json before merging. The PR body carries this reminder.

Listing remediation PRs​

GET /v1/projects/{project_id}/remediation/pull-requests

Any team member can read the project's remediation-PR records (newest first), paginated with page / page_size.

Using the portal UI​

The same flow is available without the API, from the project's Remediation tab (/projects/:id?tab=remediation):

  1. Preview — click Run preview to compute the dry-run. The proposed bumps are shown as a package → current → recommended table, alongside the manifest source (uploaded / preserved scan source / not available) and any warnings — most importantly "run npm install to regenerate package-lock.json". A no-change result and a no-manifest result are shown as explicit empty states.
  2. Open remediation PR — visible only to team admins. Clicking it opens (or idempotently returns) the PR and surfaces the result as a link that opens GitHub in a new tab.
    • If the project is not opted in (no linked GitHub App installation), the button is replaced with inline guidance instead of failing — a team admin must link a repository first.
    • A non-team-admin sees read-only guidance, not the button.
  3. Remediation pull requests — the list below shows every PR opened for the project with a status badge (creating / open / failed / superseded), the target repository, and the creation time. Each row links out to the PR on GitHub.

Status lifecycle​

StatusMeaning
creatingthe record was persisted before the GitHub writes started (a crash mid-flight leaves a visible trail)
openGitHub returned a created PR; pr_number / pr_url are set
faileda GitHub write failed; the attempt is recorded
supersededreserved for a future "a newer PR replaces this one" flow

Errors​

All errors are RFC 7807 application/problem+json:

  • 401 — authentication required.
  • 403 — the caller is a project member but not a team admin.
  • 404 — project not found / not accessible.
  • 409 — the project is not opted in to automated remediation PRs (link a GitHub App installation with a repository first).
  • 422 — the manifest could not be edited, or the stored repository identifier is unusable.
  • 502 — a GitHub write (branch / commit / PR) failed. The error reports the GitHub HTTP status only — never a token or response body.