PMM-15294 Submit ServiceNow inputs to SEP settings - #5758
Conversation
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]>
There was a problem hiding this comment.
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]>
|
@coderabbitai full review |
✅ Action performedFull review finished. |
WalkthroughThis 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. ChangesServiceNow settings integration
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
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
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
📒 Files selected for processing (13)
ui/apps/pmm/src/pages/settings/Settings.messages.tsui/apps/pmm/src/pages/settings/Settings.test.tsxui/apps/pmm/src/pages/settings/Settings.tsxui/apps/pmm/src/pages/settings/Settings.types.tsui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.constants.tsui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.types.tsui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.utils.test.tsui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnection.utils.tsui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionForm.schema.tsui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionForm.test.tsxui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionForm.tsxui/apps/pmm/src/pages/settings/components/servicenow/ServiceNowConnectionTab.tsxui/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)
Signed-off-by: Ignacio Durand <[email protected]>
…into PMM-15294-sep-diagnostics-settings Signed-off-by: yyyyyyy <[email protected]>
Signed-off-by: Ignacio Durand <[email protected]>
Ticket number: PMM-15294
Feature Build: Percona-Lab/pmm-submodules#4523
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:not_overridableDIAGNOSTICS_DELIVERY_INPUTS. There is no partial-write path anywhere.SEPSettings→DIAGNOSTICS_DELIVERY→value.secrets), never hardcoded. One field is rendered per declared name, so an image that renames one is followed rather than 422'd.""before sending, because a mask with nothing behind it is a 422.Requests go through
usePatchSetting()/useSettingsList()/useResetSetting()inui/packages/sep/api/src/hooks/useSettings.ts, which already ship the single-key atomic body.How
Where it lives
Settingsgains 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.secretsis astring[]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 backundefined, 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), ordrifted(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_INPUTSat 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, andvitest run— 434 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
Related work
Depends on PMM-15293 Mint the SEP bearer from the PMM session #5739 (PMM-15293, SEP session exchange), which is this PR's base — the admin-gated write is unreachable without it.
Which in turn depends on PMM-15216 Migrate the SEP UI into PMM #5653 (PMM-15216) and PMM-15288 Migrate UI toolchain to pnpm + oxlint/oxfmt #5728 (PMM-15288).
SEP side: SEP-1698.
API Docs updated