Skip to content

PMM-15294 Submit ServiceNow inputs to SEP settings - #5758

Open
nachodd wants to merge 6 commits into
PMM-15293-sep-session-exchangefrom
PMM-15294-sep-diagnostics-settings
Open

PMM-15294 Submit ServiceNow inputs to SEP settings#5758
nachodd wants to merge 6 commits into
PMM-15293-sep-session-exchangefrom
PMM-15294-sep-diagnostics-settings

Conversation

@nachodd

@nachodd nachodd commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Ticket number: PMM-15294

Feature Build: Percona-Lab/pmm-submodules#4523

Stacked PR — base is PMM-15293-sep-session-exchange, not v3. Review the diff against the base, not the full branch. Merge order: #5728 (PMM-15288) → #5653 (PMM-15216) → #5739 (PMM-15293) → this one.

What

A ServiceNow connection tab in PMM Settings where an admin enters the receiver endpoint and the delivery plan's named secrets, and PMM writes them to SEP's settings API.

This is the direct-entry path: the operator obtains a ServiceNow token out of band and types it in. PMM-15218 replaces this entry surface with a guided ServiceNow round trip (currently blocked on the ServiceNow side) — it replaces the surface, not the write path below, which is why the two are separated the way they are.

Why

SEP bakes the delivery-plan skeleton into its embedded profile and exposes only the per-deployment inputs — the receiver endpoint and the plan's named secrets — as one structured, overridable settings key. Without a UI for it, diagnostics delivery can only be configured by hand-editing SEP's configuration. See SEP-1698.

The contract this codes against

Shipped and verified against SEP main; not a proposal. The whole design of the diff follows from four properties of it:

Property Consequence in the UI
The key's leaves are sealed — a per-leaf write is 422 not_overridable One whole-object PATCH of DIAGNOSTICS_DELIVERY_INPUTS. There is no partial-write path anywhere.
The submitted secret map must match the declared names exactly — an extra or missing name is a 422 Names are read at runtime from the baked plan (SEPSettingsDIAGNOSTICS_DELIVERYvalue.secrets), never hardcoded. One field is rendered per declared name, so an image that renames one is followed rather than 422'd.
A resubmitted mask restores the stored secret, but only once something is stored Masks round-trip verbatim; where no override exists to restore from, the mask is downgraded to "" before sending, because a mask with nothing behind it is a 422.
Empty is a valid save — SEP then reports delivery unavailable An empty secret reads as "not configured", never as an error.

Requests go through usePatchSetting() / useSettingsList() / useResetSetting() in ui/packages/sep/api/src/hooks/useSettings.ts, which already ship the single-key atomic body.

How

Where it lives

Settings gains a fourth tab, matching the design at Figma (although, the functionality is not implemented the same way as in Figma, since the integration is blocked by ServiceNow at the moment). PMM-15218 can then swap the tab body from this form to the OAuth button without moving anything.

The tab wraps its content in SepAuthGate, so the calls carry the bearer minted from the PMM session (#5739) rather than a cookie — SEP's settings router is admin-gated on reads as well as writes, and refuses a cookie-only mutation with a 401 before it validates anything.

Secrets are addressed by position, not by name

ServiceNowFormValues.secrets is a string[] aligned with the declared names, and the names are zipped back on only when building the PATCH.

react-hook-form reads a field name as a path. A declared name carrying a . — and these names are runtime data from SEP — would register as a nested field, read back undefined, and silently submit "" over a stored secret. Positional addressing removes that class entirely. Covered by a unit test (sn.api.key, client[token]) and a rendering test that types into a dotted field and asserts the payload key survives.

Failure reporting

Validation is all-or-nothing server-side, so nothing here is optimistic: a rejected save refetches nothing and the previous configuration stands, with the typed-in values still on screen.

The per-field 422 message is surfaced verbatim — it names the offending secret keys, which is more useful than anything the UI could synthesise. Below that, 401, 403 and an unreachable SEP each get their own message, and a raw HTTP status is never shown. The 403 case matters: the ACs call out never leaving the user with an unexplained 403.

Status

Derived from the stored inputs rather than a second round trip: configured, not-configured (nothing saved, or a declared secret saved empty), or drifted (the plan declares a name the stored inputs lack — an image renamed one after the values were supplied).

Two states short-circuit the form: a deployment whose settings list carries no DIAGNOSTICS_DELIVERY_INPUTS at all says so instead of offering a form whose every write would 422, and a plan declaring no secrets still offers the endpoint, since the two are independent.

Testing

tsc --noEmit, oxlint (0 errors), oxfmt --check, vite build, and vitest run434 tests pass, 48 of them new.

  • ServiceNowConnection.utils.test.ts — declared-name resolution and its fallback, the mask/empty/omitted-endpoint rules in the patch builder, exact-name submission, every status transition, and the error mapping.
  • ServiceNowConnectionForm.test.tsx — one field per declared name, a rename followed across a reload, the single atomic PATCH, masks preserved on an untouched resubmit, clearing a secret as an explicit unconfigured save, the 422 surfaced, the form intact after a rejected save, and disconnect behind its confirmation.

Verified against a live SEP

Not only unit tests: run against a local SEP on the Grafana auth provider, with the bearer minted from the PMM session by #5739. The exchange returns an admin-capable identity (isAdmin: true) and the admin-gated settings list returns 200, so the tab loads and writes as a real PMM admin.

Out of scope

  • SEP-side validation, merge semantics, and the baked plan skeleton — already shipped.
  • The guided ServiceNow round trip (PMM-15218), blocked on the ServiceNow side.

Related work

Add a "ServiceNow connection" tab to PMM Settings so an admin can enter
the receiver endpoint and the delivery plan's named secrets, and have
PMM write them to SEP's settings API. The operator obtains the token out
of band; PMM-15218 replaces this entry surface with a guided round trip
and leaves the write path below untouched.

The write is one whole-object PATCH of DIAGNOSTICS_DELIVERY_INPUTS. SEP
seals the key's leaves, so a per-leaf write is not a shape the UI may
improvise, and the submitted secret map must match the declared names
exactly. Those names are read at runtime from the baked plan
(SEPSettings -> DIAGNOSTICS_DELIVERY -> value.secrets) rather than
hardcoded, so an image that renames one is followed rather than 422'd.

Secrets are addressed by position, not by name: react-hook-form reads a
field name as a path, and a declared name carrying a "." would register
as a nested field, read back undefined, and silently overwrite a stored
secret with an empty string.

Stored secrets come back masked and are resubmitted verbatim so SEP
restores them, except where no override exists to restore from - that
case is sent empty, since a mask with nothing behind it is a 422. An
empty secret is a valid save and reads as "not configured", never as an
error. A rejected save leaves the previous configuration standing and
reports the per-field 422 verbatim; 401, 403 and an unreachable SEP each
get their own message, and a raw HTTP status is never shown.

The tab sits behind SepAuthGate, so the settings calls carry the bearer
minted from the PMM session (PMM-15293) rather than a cookie, which the
admin-gated settings router refuses.

Signed-off-by: Ignacio Durand <[email protected]>
Copilot AI lite review requested due to automatic review settings August 10, 2026 22:23
@nachodd
nachodd requested a review from a team as a code owner August 10, 2026 22:23
@nachodd
nachodd requested review from matejkubinec and mattiasimonato and removed request for a team August 10, 2026 22:23

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 ServiceNow connection tab under PMM Settings that lets admins enter the SEP diagnostics delivery receiver endpoint and any delivery-plan-declared secret values, then persists them via SEP’s settings API using a single atomic PATCH of DIAGNOSTICS_DELIVERY_INPUTS.

Changes:

  • Adds a new Settings tab/route (/settings/servicenow-connection) and label text for “ServiceNow connection”.
  • Introduces a SEP-auth-gated ServiceNow connection form that loads declared secret names from SEP’s baked delivery plan, supports masked secret round-trips, and provides disconnect (reset) behavior.
  • Adds unit and component tests for rendering, submission payload shape, validation, and error surfacing.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
ui/apps/pmm/src/pages/settings/Settings.types.ts Extends TabValue union to include the new ServiceNow tab route value.
ui/apps/pmm/src/pages/settings/Settings.tsx Adds a new MUI Tab and renders ServiceNowConnectionTab when selected.
ui/apps/pmm/src/pages/settings/Settings.test.tsx Verifies the ServiceNow tab activates for /settings/servicenow-connection.
ui/apps/pmm/src/pages/settings/Settings.messages.ts Adds UI copy for the ServiceNow connection tab, status text, validation, and error messages.
ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionTab.tsx Wraps the ServiceNow form in SepAuthGate so requests use the SEP bearer flow.
ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionForm.tsx Implements the direct-entry form, status banner, submit (PATCH), and disconnect (reset) flows.
ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionForm.test.tsx Component tests for field rendering, payload correctness, masks, validation, and disconnect confirmation.
ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionForm.schema.ts Zod schema for minimal client-side validation (absolute URL / empty allowed).
ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.utils.ts Utilities for extracting declared names/stored values, building PATCH payload, status derivation, and error mapping.
ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.utils.test.ts Unit tests covering secret-name resolution, patch builder rules, status transitions, and error mapping.
ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.types.ts Types for SEP delivery inputs, stored inputs, and form values (positional secrets).
ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.constants.ts Constants for SEP settings class and key names (DIAGNOSTICS_DELIVERY, DIAGNOSTICS_DELIVERY_INPUTS).
ui/apps/pmm/src/pages/settings/components/servicenow/index.ts Re-exports the ServiceNow tab/form components for Settings integration.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

`connectionStatus` collapsed "no declared secrets" into `not-configured`
unconditionally, so a deployment whose plan declares no credentials could
save an endpoint and still be told its connection was not configured -
with no way for the banner to ever say otherwise. The form offers the
endpoint field in that case and accepts the save, so the status
contradicted what the surface had just done.

With no declared secrets there is no credential left for the deployment
to supply, so a stored override is as configured as this form can make
it. Absent an override it still reads as not configured.

Signed-off-by: Ignacio Durand <[email protected]>
@theTibi

theTibi commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This change adds a ServiceNow settings tab and authenticated connection form. It defines SEP data handling, validation, status and error mapping, save and disconnect actions, localized messages, and comprehensive tests.

Changes

ServiceNow settings integration

Layer / File(s) Summary
Settings navigation and contracts
ui/apps/pmm/src/pages/settings/Settings.types.ts, ui/apps/pmm/src/pages/settings/Settings.messages.ts, ui/apps/pmm/src/pages/settings/Settings.tsx, ui/apps/pmm/src/pages/settings/Settings.test.tsx
The settings page adds the servicenow-connection route, localized messages, tab rendering, and route coverage.
SEP data handling and validation
ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.constants.ts, ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.types.ts, ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.utils.ts, ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionForm.schema.ts, ui/apps/pmm/src/pages/settings/components/servicenow/*utils.test.ts
The implementation normalizes SEP settings, preserves masked secrets, builds complete patches, classifies connection status, formats errors and secret labels, and validates HTTP(S) endpoints.
Authenticated form flow
ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionTab.tsx, ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionForm.tsx, ui/apps/pmm/src/pages/settings/components/servicenow/index.ts, ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionForm.test.tsx
The authenticated form loads SEP settings, renders dynamic credentials and status, saves and disconnects through SEP mutations, handles errors, and validates loading, save, and reset flows.

Sequence Diagram(s)

sequenceDiagram
  participant Settings
  participant ServiceNowConnectionTab
  participant SepAuthGate
  participant ServiceNowConnectionForm
  participant SEPSettingsAPI
  Settings->>ServiceNowConnectionTab: select servicenow-connection route
  ServiceNowConnectionTab->>SepAuthGate: render authenticated tab
  SepAuthGate->>ServiceNowConnectionForm: render form
  ServiceNowConnectionForm->>SEPSettingsAPI: list SEP settings
  SEPSettingsAPI-->>ServiceNowConnectionForm: return delivery inputs and plan
  ServiceNowConnectionForm->>SEPSettingsAPI: patch delivery inputs on save
  SEPSettingsAPI-->>ServiceNowConnectionForm: return save result
  ServiceNowConnectionForm->>SEPSettingsAPI: reset delivery inputs on disconnect
  SEPSettingsAPI-->>ServiceNowConnectionForm: return reset result
Loading
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the ServiceNow settings submission, which is the primary change in the pull request.
Description check ✅ Passed The description includes the ticket, feature build, implementation details, testing, related work, scope, and API documentation checkbox.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/apps/pmm/src/pages/settings/Settings.messages.ts`:
- Line 113: Move the support URL from the subscriptionLink definition into a
shared constant in constants.ts, then update subscriptionLink to reference that
constant instead of embedding the URL string. Export and import the constant
using the existing project conventions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8dd2b122-6d92-4f6a-990c-705a8e555448

📥 Commits

Reviewing files that changed from the base of the PR and between ec3d246 and 0443024.

📒 Files selected for processing (13)
  • ui/apps/pmm/src/pages/settings/Settings.messages.ts
  • ui/apps/pmm/src/pages/settings/Settings.test.tsx
  • ui/apps/pmm/src/pages/settings/Settings.tsx
  • ui/apps/pmm/src/pages/settings/Settings.types.ts
  • ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.constants.ts
  • ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.types.ts
  • ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.utils.test.ts
  • ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.utils.ts
  • ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionForm.schema.ts
  • ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionForm.test.tsx
  • ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionForm.tsx
  • ui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionTab.tsx
  • ui/apps/pmm/src/pages/settings/components/servicenow/index.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • percona/pmm-qa (manual)
  • percona/pmm (manual)

Comment thread ui/apps/pmm/src/pages/settings/Settings.messages.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants