From 75aa418302e56a5b4882ffa5d32bdb1c490a0d16 Mon Sep 17 00:00:00 2001 From: Jose Rego Date: Thu, 20 Nov 2025 12:35:26 +0000 Subject: [PATCH 1/2] fix: resolve paths where filter value contains a colon --- src/scimPatch.ts | 7 ++++++- test/scimPatch.test.ts | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/scimPatch.ts b/src/scimPatch.ts index d91290fb..13e68500 100644 --- a/src/scimPatch.ts +++ b/src/scimPatch.ts @@ -63,6 +63,8 @@ const IS_ARRAY_SEARCH = /(\[|\])/; const ARRAY_SEARCH = /^(.+)\[(.+)\]$/; // Split path on periods const SPLIT_PERIOD = /(?!\B"[^[]*)\.(?![^\]]*"\B)/g; +// Regex to fetch the URN from a path. +const URN_MATCH = /^((?:[A-Za-z0-9][A-Za-z0-9.+-]*:)+[A-Za-z0-9.+-]*)/; // Valid patch operation, value needs to be in lowercase here. const AUTHORIZED_OPERATION = ['remove', 'add', 'replace']; @@ -144,7 +146,10 @@ function validatePatchOperation(operation: ScimPatchOperation): void { } function resolvePaths(path: string): string[] { - const uriIndex = path.lastIndexOf(':'); + // Identify the URN prefix if present + const urnPath = path.match(URN_MATCH); + // Find the last colon in the urn path + const uriIndex = urnPath ? (urnPath[1] ?? urnPath[0]).lastIndexOf(':') : -1; if (uriIndex < 0) { // No schema prefix - this is a core schema path diff --git a/test/scimPatch.test.ts b/test/scimPatch.test.ts index 3dc01860..4205c168 100644 --- a/test/scimPatch.test.ts +++ b/test/scimPatch.test.ts @@ -1195,6 +1195,23 @@ describe('SCIM PATCH', () => { expect(afterPatch.emails[3].newProperty).to.be.an('undefined'); return done(); }); + + it('REPLACE: should handle colon in quoted filter values', done => { + scimUser.roles = [ + { value: "3675b69e-8324-4110-bdca-059031aa8da3:admin", type: "admin" }, + { value: "other-role", type: "user" } + ]; + const expected = "updated"; + const patch: ScimPatchAddReplaceOperation = { + op: 'replace', + value: expected, + path: 'roles[value eq "3675b69e-8324-4110-bdca-059031aa8da3:admin"].value' + }; + const afterPatch = scimPatch(scimUser, [patch]); + expect(afterPatch.roles![0].value).to.be.eq(expected); + expect(afterPatch.roles![1].value).to.be.eq("other-role"); + return done(); + }); }); describe('invalid requests', () => { From 2883432c85a3587faa6cb93eb7f1db2a3cbf3864 Mon Sep 17 00:00:00 2001 From: Jose Rego Date: Thu, 20 Nov 2025 13:55:28 +0000 Subject: [PATCH 2/2] fix: remove redundancy Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/scimPatch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scimPatch.ts b/src/scimPatch.ts index 13e68500..fb6aa78b 100644 --- a/src/scimPatch.ts +++ b/src/scimPatch.ts @@ -149,7 +149,7 @@ function resolvePaths(path: string): string[] { // Identify the URN prefix if present const urnPath = path.match(URN_MATCH); // Find the last colon in the urn path - const uriIndex = urnPath ? (urnPath[1] ?? urnPath[0]).lastIndexOf(':') : -1; + const uriIndex = urnPath ? urnPath[1].lastIndexOf(':') : -1; if (uriIndex < 0) { // No schema prefix - this is a core schema path