const assert = require("node:assert/strict"); const { test } = require("node:test"); const { loadBackground, response } = require("./support/characterization.cjs"); const type = "opportunitiesExtension.requestPostServiceRequest"; const emailAddress = "signed.in+sr@example.invalid"; const payload = () => ({ AccountPartyId: 100000000000101, OpportunityName_Id_c: 202, ServiceNew_Id_c: 404, Title: "Service-OP1-Customer", RegionText_c: "LAD", CountryText_c: "BR", ProblemDescription: "Test description", Language_c: "ENGLISH", CustomerDeadline_c: "2027-01-31", TechPlatformLookUp_c: "NO_ALL_PLATFORM", PrimaryPillarNew_c: "Tech_Cloud_Infrastructure" }); const withClientId = (body, status, value) => { const result = response(body, status); result.headers.set("X-AppBuilder-Client-Id", value); return result; }; for (const family of ["chrome", "firefox"]) { test(`${family}: response client ID from resource lookup appears in confirmation and token request`, async () => { const calls = []; const h = loadBackground({ family, fetch: async (url, options) => { calls.push({ url, options }); if (url.includes("/resourceUsers?")) return withClientId({ resourcePartyId: 303 }, 200, "response-client"); if (url.endsWith("/Catalogue_c/505")) return response({ result: "test-token" }); return response({ SrNumber: "SR1" }, 201); } }); const prepared = await h.dispatch({ type, phase: "prepare", emailAddress, payload: payload() }); assert.equal(prepared.ok, true); assert.equal(prepared.headers.requestSrTokenCatalog["x-appbuilder-client-id"], "response-client"); assert.deepEqual(prepared.headers.requestPostServiceRequest, { ...prepared.headers.requestSrTokenCatalog, "vb-proxy-header-x-oracle-ectoken": "(generated after confirmation)" }); assert.equal(calls.length, 1); const result = await h.dispatch({ type, phase: "confirm", catalogId: 505, payload: prepared.payload }); assert.equal(result.ok, true); assert.equal(calls[1].options.headers["x-appbuilder-client-id"], "response-client"); assert.deepEqual({ ...calls[2].options.headers }, { ...calls[1].options.headers, "vb-proxy-header-x-oracle-ectoken": "test-token" }); assert.equal(calls.filter(call => call.url.endsWith("/mgmt/serviceRequests")).length, 1); }); } test("response observation includes background responses and excludes other apps and private requests", async () => { const h = loadBackground(); assert.equal(h.responseHeaderListeners.length, 1); const capture = h.responseHeaderListeners[0]; assert.deepEqual(capture.options, ["responseHeaders"]); const details = { tabId: -1, url: "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_initiation/live;profile=PROD/services/auth/1.1/proxy/example", responseHeaders: [{ name: "X-AppBuilder-Client-ID", value: "background-response-client" }, { name: "Set-Cookie", value: "not-retained" }] }; capture.listener({ ...details, incognito: true }); capture.listener({ ...details, url: details.url.replace("SeaaS_initiation", "unrelated") }); assert.deepEqual(h.sessionStorage, {}); capture.listener(details); assert.equal(Object.values(h.sessionStorage)[0].value, "background-response-client"); assert.ok(!JSON.stringify(h.sessionStorage).includes("not-retained")); }); test("token 403 retries once only with a newly returned client ID; SR POST is never retried", async () => { for (const mode of ["recovered", "still-forbidden", "unchanged", "no-header", "save-failure"]) { const calls = []; let tokens = 0; const h = loadBackground({ fetch: async (url, options) => { calls.push({ url, options }); if (url.includes("/resourceUsers?")) return withClientId({ resourcePartyId: 303 }, 200, "old-client"); if (url.endsWith("/Catalogue_c/505")) { tokens += 1; if (tokens === 1) return mode === "no-header" ? response({}, 403) : withClientId({}, 403, mode === "unchanged" ? "old-client" : "new-client"); if (mode === "still-forbidden") return withClientId({}, 403, "another-client"); return response({ result: "retry-token" }); } return response({ SrNumber: "SR1" }, mode === "save-failure" ? 403 : 201); } }); const prepared = await h.dispatch({ type, phase: "prepare", emailAddress, payload: payload() }); const result = await h.dispatch({ type, phase: "confirm", catalogId: 505, payload: prepared.payload }); assert.equal(result.ok, mode === "recovered"); const expectedTokens = ["unchanged", "no-header"].includes(mode) ? 1 : 2; assert.equal(tokens, expectedTokens); const tokenCalls = calls.filter(call => call.url.endsWith("/Catalogue_c/505")); assert.equal(tokenCalls[0].options.headers["x-appbuilder-client-id"], "old-client"); if (expectedTokens === 2) assert.equal(tokenCalls[1].options.headers["x-appbuilder-client-id"], "new-client"); assert.equal(calls.filter(call => call.url.endsWith("/mgmt/serviceRequests")).length, ["recovered", "save-failure"].includes(mode) ? 1 : 0); if (["recovered", "save-failure"].includes(mode)) { assert.deepEqual({ ...calls.at(-1).options.headers }, { ...tokenCalls.at(-1).options.headers, "vb-proxy-header-x-oracle-ectoken": "retry-token" }); } assert.ok(!JSON.stringify(result).includes("retry-token")); } }); for (const family of ["chrome", "firefox"]) { test(`${family}: Save resolves current user, discovers catalog, obtains token and creates SR once with protected diagnostics`, async () => { const calls = []; const h = loadBackground({ family, fetch: async (url, options) => { calls.push({ url, options }); if (calls.length === 1) return response({ emailAddress, resourceEmail: emailAddress, resourcePartyId: 303, resourceProfileId: 999 }); if (calls.length === 2) return response({ items: [{ Id: 505 }] }); if (calls.length === 3) return response({ result: "synthetic-secret-token" }); return response({ SrId: 606, SrNumber: "SR606" }, 201); } }); const prepared = await h.dispatch({ type, phase: "prepare", emailAddress, payload: { ...payload(), ReportedByPartyId: 999 } }); assert.equal(prepared.ok, true); assert.equal(calls.length, 1, "preview only resolves the user, never generates a token or creates SR"); assert.equal(h.headerRules.length, 0, "preview does not install request modifications"); assert.equal(prepared.headers.requestSrTokenCatalog["Content-Type"], "application/vnd.oracle.adf.action+json"); assert.equal(prepared.headers.requestPostServiceRequest["vb-proxy-header-x-oracle-ectoken"], "(generated after confirmation)"); assert.equal(prepared.payload.ReportedByPartyId, 303); const result = await h.dispatch({ type, phase: "confirm", payload: prepared.payload }); assert.equal(result.ok, true); assert.equal(result.result.SrNumber, "SR606"); assert.equal(calls.length, 4); assert.equal(calls[0].options.method, "GET"); assert.equal(new URL(calls[0].url).searchParams.get("emailAddress"), emailAddress); assert.ok(calls[0].url.includes("/set/seaas/crm/resourceUsers?")); assert.equal(calls[1].options.method, "GET"); assert.ok(calls[2].url.endsWith("/Catalogue_c/505")); assert.deepEqual(JSON.parse(calls[2].options.body), { name: "getJwtToken" }); assert.equal(calls[2].options.headers["Content-Type"], "application/vnd.oracle.adf.action+json"); assert.equal(calls[2].options.headers.Origin, new URL(calls[2].url).origin); assert.deepEqual({ ...calls[3].options.headers }, { ...calls[2].options.headers, "vb-proxy-header-x-oracle-ectoken": "synthetic-secret-token" }); assert.equal(h.headerRules.length, 1); const rule = h.headerRules[0].addRules[0]; const serviceRule = h.headerRules[0].addRules[1]; assert.ok(new RegExp(serviceRule.condition.regexFilter).test(calls[3].url)); assert.ok(!new RegExp(serviceRule.condition.regexFilter).test(calls[2].url)); assert.ok(!new RegExp(serviceRule.condition.regexFilter).test(calls[3].url + "/other")); assert.deepEqual(serviceRule.condition.initiatorDomains, ["synthetic-extension"]); assert.deepEqual(serviceRule.condition.requestMethods, ["post"]); assert.deepEqual(serviceRule.action, rule.action); assert.deepEqual(rule.condition.initiatorDomains, ["synthetic-extension"]); assert.deepEqual(rule.condition.requestMethods, ["post"]); assert.ok(new RegExp(rule.condition.regexFilter).test(calls[2].url)); assert.ok(!new RegExp(rule.condition.regexFilter).test(calls[3].url)); assert.ok(!new RegExp(rule.condition.regexFilter).test(calls[2].url + "/other")); assert.deepEqual(rule.action.requestHeaders, [{ header: "Origin", operation: "set", value: new URL(calls[2].url).origin }]); assert.equal(calls[3].options.method, "POST"); assert.ok(calls[3].url.endsWith("/set/seaas/mgmt/serviceRequests")); assert.equal(calls[3].options.headers["vb-proxy-header-x-oracle-ectoken"], "synthetic-secret-token"); assert.ok(calls.slice(0, 3).every(call => !call.options.headers["vb-proxy-header-x-oracle-ectoken"])); assert.ok(calls.every(call => call.options.credentials === "include" && call.options.headers.Authorization === "Session")); assert.deepEqual(JSON.parse(calls[3].options.body), { ...payload(), ReportedByPartyId: 303, SvcQuestionsCollection_c: [], SourceCd: "SVC_OPPORTUNITY_SCREEN", SeverityCd: "ORA_SVC_SEV2", ChannelTypeCd: "ORA_SVC_WEB" }); assert.equal(calls[3].options.body, JSON.stringify(prepared.payload)); assert.ok(!JSON.stringify(result).includes("synthetic-secret-token")); assert.equal(h.tabs.length, 0); }); } test("missing region, invalid dates or unsafe IDs stop before token acquisition", async () => { const h = loadBackground({ fetch: async () => assert.fail("Unexpected network") }); for (const change of [{ RegionText_c: null }, { CustomerDeadline_c: "2027-02-30" }, { AccountPartyId: "9007199254740993" }, { OpportunityName_Id_c: "bad/id" }]) { assert.equal((await h.dispatch({ type, phase: "prepare", emailAddress, payload: { ...payload(), ...change } })).ok, false); } assert.equal((await h.dispatch({ type, phase: "prepare", payload: payload() })).ok, false); assert.equal((await h.dispatch({ type, phase: "confirm", payload: payload() })).ok, false); assert.equal((await h.dispatch({ type, emailAddress, payload: payload() })).ok, false); }); for (const family of ["chrome", "firefox"]) { test(`${family}: captures only SeaaS client ID, reuses it after worker restart and expires stale values`, async () => { const tokenCalls = []; const sessionStorage = {}; const fetch = async (url, options) => { if (url.includes("/resourceUsers?")) return response({ resourcePartyId: 303 }); if (url.endsWith("/Catalogue_c/505")) { tokenCalls.push(options); return response({ result: "synthetic-token" }); } return response({ SrNumber: "SR1" }, 201); }; const h = loadBackground({ family, fetch, sessionStorage }); assert.equal(h.headerListeners.length, 1); const capture = h.headerListeners[0]; assert.deepEqual(capture.options, ["requestHeaders"]); assert.deepEqual(capture.filter.types, ["xmlhttprequest"]); const request = { tabId: 12, url: "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_initiation/live;profile=PROD/services/auth/1.1/proxy/example", requestHeaders: [{ name: "X-AppBuilder-Client-Id", value: "synthetic-client" }, { name: "Cookie", value: "do-not-store-cookie" }, { name: "Authorization", value: "do-not-store-auth" }] }; capture.listener({ ...request, url: request.url.replace("SeaaS_initiation", "otherApp") }); capture.listener({ ...request, url: request.url.replace("comcipapic-oalprod.integration.ocp.oraclecloud.com", "other.example") }); capture.listener({ ...request, tabId: -1 }); capture.listener({ ...request, incognito: true }); capture.listener({ ...request, requestHeaders: [{ name: "x-appbuilder-client-id", value: "invalid\r\nheader" }] }); assert.deepEqual(sessionStorage, {}); capture.listener(request); assert.equal(Object.keys(sessionStorage).length, 1); assert.ok(!JSON.stringify(sessionStorage).includes("do-not-store")); const prepared = await h.dispatch({ type, phase: "prepare", emailAddress, payload: payload() }); assert.equal(prepared.headers.requestSrTokenCatalog["x-appbuilder-client-id"], "synthetic-client"); assert.equal(tokenCalls.length, 0); const restarted = loadBackground({ family, fetch, sessionStorage }); const result = await restarted.dispatch({ type, phase: "confirm", catalogId: 505, payload: prepared.payload }); assert.equal(result.ok, true); assert.equal(tokenCalls[0].headers["x-appbuilder-client-id"], "synthetic-client"); assert.equal(result.debugRequests[0].metadata.appBuilderClientId, "Observed in SeaaS requests"); restarted.advance(60 * 60 * 1000 + 1); const expired = await restarted.dispatch({ type, phase: "confirm", catalogId: 505, payload: prepared.payload }); assert.equal(expired.ok, true); assert.equal(tokenCalls[1].headers["x-appbuilder-client-id"], undefined); assert.equal(expired.debugRequests[0].metadata.appBuilderClientId, "Not observed in SeaaS requests"); capture.listener({ ...request, requestHeaders: [{ name: "x-appbuilder-client-id", value: "renewed-client" }] }); const refreshed = await h.dispatch({ type, phase: "prepare", emailAddress, payload: payload() }); assert.equal(refreshed.headers.requestSrTokenCatalog["x-appbuilder-client-id"], "renewed-client"); assert.equal(h.tabs.length, 0, "header discovery does not add background page loads"); }); } test("Origin rule failure blocks token acquisition and SR creation", async () => { const h = loadBackground({ ruleError: true, fetch: async () => assert.fail("No request expected") }); const result = await h.dispatch({ type, phase: "confirm", catalogId: 505, payload: { ...payload(), ReportedByPartyId: 303 } }); assert.equal(result.ok, false); assert.match(result.error, /Rule permission denied/); }); test("resource lookup failures or invalid resourcePartyId never obtain a token or create SR", async () => { for (const body of [{ resourcePartyId: null }, { resourceProfileId: 999 }, { resourcePartyId: "9007199254740993" }, { resourcePartyId: 0 }, "unauthorized"]) { let calls = 0; const h = loadBackground({ fetch: async () => { calls += 1; return response(body, body === "unauthorized" ? 401 : 200); } }); const result = await h.dispatch({ type, phase: "prepare", emailAddress, payload: payload() }); assert.equal(result.ok, false); assert.equal(calls, 1); assert.equal(result.debugRequests[0].name, "requestResourceUser"); } }); test("token rejection never creates SR; creation failures are never automatically retried", async () => { for (const failure of ["token", "create", "empty-token", "network"]) { let calls = 0; const h = loadBackground({ fetch: async () => { calls += 1; if (calls === 1) return response({ resourcePartyId: 303 }); if (calls === 2) return failure === "token" ? response({}, 401) : response({ result: failure === "empty-token" ? "" : "secret-token" }); if (failure === "network") throw new Error("Network error"); return response({}, 500); } }); const prepared = await h.dispatch({ type, phase: "prepare", emailAddress, payload: payload() }); const result = await h.dispatch({ type, phase: "confirm", catalogId: 505, payload: prepared.payload }); assert.equal(result.ok, false); assert.equal(calls, failure === "token" || failure === "empty-token" ? 2 : 3); assert.ok(!JSON.stringify(result).includes("secret-token")); assert.equal(h.tabs.length, 0); } });