Fall back to top-level keyData when resolving previous premium value

Premium fields like policies are echoed at the top level of the
/key/update response, not necessarily mirrored into metadata. Read
metadata first then fall back to the top-level property so an
intentional clear is preserved in either shape.
This commit is contained in:
Yuneng Jiang 2026-04-18 12:23:58 -07:00
parent 2c41f3c291
commit cae8b74b0b
No known key found for this signature in database
2 changed files with 22 additions and 1 deletions

View File

@ -757,5 +757,24 @@ describe("KeyInfoView", () => {
expect.objectContaining({ policies: [] }),
);
});
it("should keep an empty policies field when the previous value lives only at the top level of keyData", async () => {
// Defensive: some premium fields may be present at the top level but not
// mirrored into metadata. A genuine clear must still be forwarded.
const keyData: KeyResponse = {
...MOCK_KEY_DATA,
user_id: "proxy-admin-user",
metadata: {},
policies: ["existing-policy"],
} as KeyResponse;
await enterEditMode(keyData);
await editViewMocks.onSubmit!({ key: keyData.token, token: keyData.token, policies: [] });
expect(keyUpdateCall).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({ policies: [] }),
);
});
});
});

View File

@ -166,7 +166,9 @@ export default function KeyInfoView({
// state; without this, the next save resends `[]` and trips the premium
// gate in prepare_metadata_fields for non-premium users.
for (const field of PREMIUM_METADATA_FIELDS) {
const previousValue = (currentKeyData.metadata as Record<string, unknown> | undefined)?.[field];
const previousValue =
(currentKeyData.metadata as Record<string, unknown> | undefined)?.[field] ??
(currentKeyData as unknown as Record<string, unknown>)[field];
if (isEmptyValue(formValues[field]) && isEmptyValue(previousValue)) {
delete formValues[field];
}