@@ -3,6 +3,26 @@ import { BASE_URL } from "../core/env";
|
||||
import { consoleLogger } from "../core/logger";
|
||||
import { hashAPIPath } from "../core/hash";
|
||||
|
||||
const buildHashedQueryUrl = async (queryUrl) => {
|
||||
try {
|
||||
const signRes = await axios.get(
|
||||
"/api/endpoint/gethash_api?path=" + encodeURIComponent(queryUrl)
|
||||
);
|
||||
|
||||
if (!signRes?.data?.hash) {
|
||||
throw new Error("Hash signature unavailable");
|
||||
}
|
||||
|
||||
return queryUrl + signRes.data.hash;
|
||||
} catch (error) {
|
||||
if (typeof window === "undefined" && process.env.HASHKEY) {
|
||||
return queryUrl + hashAPIPath(queryUrl);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getPersonalAccount = (contactid) => {
|
||||
return axios
|
||||
.get(
|
||||
@@ -105,7 +125,7 @@ export const getPortalLogin = async (emailAddress) => {
|
||||
"/api/endpoint/getportallogin_api?emailAddress=" + emailAddress;
|
||||
|
||||
return axios
|
||||
.get(BASE_URL + queryUrl + hashAPIPath(queryUrl))
|
||||
.get(BASE_URL + (await buildHashedQueryUrl(queryUrl)))
|
||||
.then((res) => res.data)
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
|
||||
@@ -3,6 +3,26 @@ import { BASE_URL } from "../core/env";
|
||||
import { consoleLogger } from "../core/logger";
|
||||
import { hashAPIPath } from "../core/hash";
|
||||
|
||||
const buildHashedQueryUrl = async (queryUrl) => {
|
||||
try {
|
||||
const signRes = await axios.get(
|
||||
"/api/endpoint/gethash_api?path=" + encodeURIComponent(queryUrl)
|
||||
);
|
||||
|
||||
if (!signRes?.data?.hash) {
|
||||
throw new Error("Hash signature unavailable");
|
||||
}
|
||||
|
||||
return queryUrl + signRes.data.hash;
|
||||
} catch (error) {
|
||||
if (typeof window === "undefined" && process.env.HASHKEY) {
|
||||
return queryUrl + hashAPIPath(queryUrl);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getAwaitingSubmissionFromBlob = (containerName) => {
|
||||
return axios
|
||||
.get(
|
||||
@@ -132,9 +152,11 @@ export const uploadFiles = async (
|
||||
|
||||
var queryUrl = "/api/file/upload";
|
||||
|
||||
const hashedUrl = await buildHashedQueryUrl(queryUrl);
|
||||
|
||||
const config = {
|
||||
method: "post",
|
||||
url: queryUrl,
|
||||
url: hashedUrl,
|
||||
data: formData,
|
||||
headers: { "content-type": "multipart/form-data" }
|
||||
};
|
||||
@@ -160,9 +182,11 @@ export const uploadSingleFile = async (filesObj, containerID, casefolderID) => {
|
||||
|
||||
var queryUrl = "/api/file/uploadsinglefile";
|
||||
|
||||
const hashedUrl = await buildHashedQueryUrl(queryUrl);
|
||||
|
||||
const config = {
|
||||
method: "post",
|
||||
url: queryUrl,
|
||||
url: hashedUrl,
|
||||
data: formData,
|
||||
headers: { "content-type": "multipart/form-data" }
|
||||
};
|
||||
@@ -189,9 +213,11 @@ export const uploadRepFiles = async (
|
||||
|
||||
var queryUrl = "/api/file/upload";
|
||||
|
||||
const hashedUrl = await buildHashedQueryUrl(queryUrl);
|
||||
|
||||
const config = {
|
||||
method: "post",
|
||||
url: queryUrl,
|
||||
url: hashedUrl,
|
||||
data: formData,
|
||||
headers: { "content-type": "multipart/form-data" }
|
||||
};
|
||||
|
||||
@@ -3,6 +3,26 @@ import { BASE_URL } from "../core/env";
|
||||
import { consoleLogger } from "../core/logger";
|
||||
import { hashAPIPath } from "../core/hash";
|
||||
|
||||
const buildHashedQueryUrl = async (queryUrl) => {
|
||||
try {
|
||||
const signRes = await axios.get(
|
||||
"/api/endpoint/gethash_api?path=" + encodeURIComponent(queryUrl)
|
||||
);
|
||||
|
||||
if (!signRes?.data?.hash) {
|
||||
throw new Error("Hash signature unavailable");
|
||||
}
|
||||
|
||||
return queryUrl + signRes.data.hash;
|
||||
} catch (error) {
|
||||
if (typeof window === "undefined" && process.env.HASHKEY) {
|
||||
return queryUrl + hashAPIPath(queryUrl);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getMyCases = (loggedInUserId) => {
|
||||
return axios
|
||||
.get(
|
||||
@@ -234,8 +254,11 @@ export const sendCaseCompleteMessage = async (
|
||||
"&tempcaseref=" +
|
||||
caseReference +
|
||||
"&inv=" +
|
||||
inv +
|
||||
hashAPIPath(hashQueryPath);
|
||||
inv;
|
||||
|
||||
var signedQueryUrl = await buildHashedQueryUrl(hashQueryPath);
|
||||
|
||||
queryUrl = queryUrl + signedQueryUrl.replace(hashQueryPath, "");
|
||||
|
||||
var config = {
|
||||
method: "get",
|
||||
@@ -280,7 +303,7 @@ export const sendRepCompleteMessage = async (
|
||||
caseReference,
|
||||
fileName
|
||||
) => {
|
||||
var queryUrl =
|
||||
var hashQueryPath =
|
||||
"/api/file/createrepcompletemessage_api?container=" +
|
||||
containerID +
|
||||
"&tempcaseref=" +
|
||||
@@ -288,6 +311,8 @@ export const sendRepCompleteMessage = async (
|
||||
"&repid=" +
|
||||
fileName;
|
||||
|
||||
var queryUrl = await buildHashedQueryUrl(hashQueryPath);
|
||||
|
||||
var config = {
|
||||
method: "get",
|
||||
url: queryUrl
|
||||
|
||||
@@ -20,7 +20,11 @@ import fieldLookup from "../../data/crmfieldlookuptranslations.json";
|
||||
import pickListLookup from "../../data/picklistLookups.json";
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
import { bytesToSize, getThumbnailIconByExtension } from "../utils";
|
||||
import {
|
||||
bytesToSize,
|
||||
getThumbnailIconByExtension,
|
||||
updateLinks
|
||||
} from "../utils";
|
||||
import { setFileCount } from "../../store/appealType/action";
|
||||
|
||||
import {
|
||||
|
||||
@@ -0,0 +1,479 @@
|
||||
# Active Context — PEDW FrontEnd
|
||||
|
||||
## Current development focus (from recent commits)
|
||||
|
||||
- Search/case navigation correctness, especially breadcrumb and back-link behavior.
|
||||
- My Portal "view all" and DNS application path handling.
|
||||
- Welsh/English email behavior for specific notification templates.
|
||||
- PDF output formatting and hyperlink behavior.
|
||||
|
||||
## Recently changed areas (high signal)
|
||||
|
||||
- `components/breadcrumbs.js`
|
||||
- `components/case/summary.js`
|
||||
- `components/search/searchresults.js`
|
||||
- `components/search/addresssearchresults.js`
|
||||
- `components/myportal/viewall.js`
|
||||
- `pages/myportal/case/[ticketnumber].js`
|
||||
- `pages/api/email/notify.js`
|
||||
- `actions/index.js`
|
||||
- `actions/core/env.js`
|
||||
- `actions/core/logger.js`
|
||||
- `actions/core/hash.js`
|
||||
- `actions/core/token.js`
|
||||
- `actions/core/headers.js`
|
||||
- `actions/services/legacyActionsService.js`
|
||||
- `i18n.js`
|
||||
|
||||
## Active concerns
|
||||
|
||||
- Breadcrumb and route-state logic is complex and query-dependent (`va`, `adv`, `ads`, `key`), so regressions are easy.
|
||||
- Locale-specific route and label behavior is still a high-risk area due to rewrite + component logic coupling.
|
||||
- Sensitive logging remains present in auth/email/actions paths and should be reduced/redacted over time.
|
||||
- Hash validation on some file endpoints appears inconsistent (some checks active, some commented), requiring careful change discipline.
|
||||
|
||||
## Refactor status update (2026-03-12)
|
||||
|
||||
- Priority 1 refactor (Phase 1) is in place:
|
||||
- `actions/index.js` now acts as a compatibility barrel.
|
||||
- Core helper concerns were extracted into `actions/core/*`.
|
||||
- Existing API/file/domain wrappers were moved into `actions/services/legacyActionsService.js` with backward-compatible exports retained via the barrel.
|
||||
- No intentional behavior changes were introduced in this phase; focus was structural risk reduction.
|
||||
- Priority 1 refactor (Phase 2) is now in place:
|
||||
- Domain service grouping modules added under `actions/services/*`.
|
||||
- `actions/services/index.js` now provides grouped service barrel exports.
|
||||
- `actions/index.js` now re-exports from `./services` and `./core/*` while preserving existing public action names.
|
||||
- `legacyActionsService` remains as a compatibility backing module and should be slimmed in later increments as consumers move to direct service imports.
|
||||
|
||||
## Refactor status update (Priority 1 execution pass — 2026-03-12)
|
||||
|
||||
- Completed an additional Priority 1 consumer-migration pass focused on high-use portal/form helpers.
|
||||
- Updated these files to use focused service/core imports instead of broad `actions` barrel imports:
|
||||
- `components/case/representation/representationElements.js`
|
||||
- `components/elements/index.js`
|
||||
- `components/utils/index.js`
|
||||
- `lib/newappeal/loadNewAppealPage.js`
|
||||
- `lib/myportal/loadMyPortalAppealPage.js`
|
||||
- `components/myportal/topthree.js`
|
||||
- `components/myportal/topthree_reps.js`
|
||||
- `components/myportal/awaitingsubmissionfromblob.js`
|
||||
- Compatibility model remains in place via `actions/index.js`; migration is incremental and non-breaking by design.
|
||||
|
||||
## Refactor status update (Priority 1 execution pass — viewall/search/unsubscribe)
|
||||
|
||||
- Completed another focused import migration pass to reduce broad `actions` barrel coupling in user-facing high-use areas:
|
||||
- `components/myportal/viewall.js`
|
||||
- `components/search/addresssearchresults.js`
|
||||
- `pages/unsubscribe/[watchlistid].js`
|
||||
- `pages/unsubscribeall/[watchlistid].js`
|
||||
- These files now use explicit imports from `actions/services/*` and `actions/core/*` modules.
|
||||
- Remaining non-comment broad `actions` imports are now primarily in selected `pages/api/endpoint/*` and `pages/api/file/*` handlers.
|
||||
|
||||
## Refactor status update (Priority 1 execution pass — endpoint/file proxies)
|
||||
|
||||
- Completed focused import migration for selected endpoint and file proxy handlers:
|
||||
- `pages/api/endpoint/getmylpacases_api.js`
|
||||
- `pages/api/endpoint/getbasicdnssearchpaged_api.js`
|
||||
- `pages/api/endpoint/getsearchdocumentdetailspaged_api.js`
|
||||
- `pages/api/endpoint/getbasicsearchpaged_api.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/createappealcompletemessageproxy_api.js`
|
||||
- Replaced broad `../../../actions` imports with focused `actions/core/*` and service-module imports.
|
||||
- Eliminated duplicated local hash helper in `getmylpacases_api.js` by reusing shared `actions/core/hash`.
|
||||
- Current broad-import scan indicates only comment-only legacy references remain.
|
||||
|
||||
## Delivery handover status (2026-03-13)
|
||||
|
||||
- Current import-migration wave has been checked in and completed through PR.
|
||||
- This branch is now treated as the completed migration baseline.
|
||||
- Next implementation chunk should start on a **new branch** and target decomposition of `actions/services/legacyActionsService.js`.
|
||||
- Immediate focus for next branch:
|
||||
1. extract low-risk reference/search wrappers into direct service/client modules,
|
||||
2. migrate portal/document internals in small parity-checked batches,
|
||||
3. slim compatibility layer once parity is proven.
|
||||
|
||||
## Phase 5 kickoff status (2026-03-13)
|
||||
|
||||
- Branch in progress: `TASK21997-phase5-legacyactions-split`.
|
||||
- First decomposition slice completed:
|
||||
- search wrappers extracted to `actions/services/searchDirectService.js`
|
||||
- reference-data wrappers extracted to `actions/services/referenceDataDirectService.js`
|
||||
- `searchService` and `referenceDataService` now route through these direct modules.
|
||||
- `legacyActionsService` remains in place for non-migrated domains (portal/document/account/case/admin/notify/integration) pending next slices.
|
||||
|
||||
## Phase 5 status update (2026-03-13 — document slice)
|
||||
|
||||
- Added `actions/services/documentDirectService.js` and migrated `documentService.js` to route through it.
|
||||
- `legacyActionsService` now remains for:
|
||||
- portal, account, case, admin, notify, integration domains.
|
||||
- Search/reference/document grouped services now point at dedicated direct modules.
|
||||
|
||||
## Phase 5 completion status (2026-03-13)
|
||||
|
||||
- Grouped services now route through focused direct modules for all domains:
|
||||
- search, reference-data, document, portal, account, case, admin, integration, notify.
|
||||
- `actions/services/legacyActionsService.js` has been removed.
|
||||
- Current architecture baseline:
|
||||
- `actions/index.js` -> compatibility barrel re-exporting `actions/services` + core modules
|
||||
- `actions/services/*Service.js` -> grouped public service boundaries
|
||||
- `actions/services/*DirectService.js` -> implementation modules per domain
|
||||
- Validation checkpoints completed:
|
||||
- zero `legacyActionsService` imports in `actions/services/*.js`
|
||||
- lint passes with warnings only
|
||||
- build succeeds
|
||||
|
||||
## Phase 6 hardening status (2026-03-13 — in progress)
|
||||
|
||||
- Working branch: `TASK21998-phase6-postphase5-hardening` (created from `SIPS-Development`).
|
||||
- Main hardening actions completed so far:
|
||||
- Added focused parity test harness:
|
||||
- `tests/phase6/service-parity.test.cjs`
|
||||
- verifies grouped service import/export parity and `actions/services/index.js` re-export stability.
|
||||
- Added shared error-path helper:
|
||||
- `actions/services/httpServiceUtils.js`
|
||||
- consolidates repeated `consoleLogger + error.response` and `ErrResponse` generation patterns.
|
||||
- Applied safe duplication reduction in:
|
||||
- `searchDirectService.js`
|
||||
- `referenceDataDirectService.js`
|
||||
- `caseDirectService.js`
|
||||
- `adminDirectService.js`
|
||||
- Logging cleanup for sensitive/noisy service paths (removed debug `console.log` usage) in:
|
||||
- `searchDirectService.js`
|
||||
- `documentDirectService.js`
|
||||
- `portalDirectService.js`
|
||||
- `caseDirectService.js`
|
||||
- `adminDirectService.js`
|
||||
|
||||
### Current validation evidence
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `npm run lint` -> warnings only
|
||||
- Targeted local smoke snapshots:
|
||||
- `GET /advancedsearch` and `GET /cy/advancedsearch` -> 200
|
||||
- `GET /case` and `GET /cy/case` -> 200
|
||||
- `GET /myportal` and `GET /cy/myportal` -> 307 redirect to `/auth/signin` (unauthenticated negative path)
|
||||
- `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> 400 (negative path)
|
||||
- `POST /api/email/notify` with empty payload -> 400 (negative path)
|
||||
|
||||
### Active caveat
|
||||
|
||||
- `GET /searchresults` and `GET /cy/searchresults` return 500 in current local dev run due pre-existing SSR serialization issue:
|
||||
- `initialState.search.searchString` is undefined in `getServerSideProps` payload.
|
||||
- captured in `/tmp/phase6-dev.log`.
|
||||
|
||||
## Phase 7 hardening status (2026-03-13)
|
||||
|
||||
- Working branch created from `origin/SIPS-Development`:
|
||||
- `TASK21988a-phase7-postphase6-hardening`
|
||||
- Pre-existing search results SSR serialization issue now addressed:
|
||||
- `pages/searchresults.js`
|
||||
- changed `setSearch(query.q)` to `setSearch(query?.q || "")` in `getServerSideProps`.
|
||||
- local smoke result: both `/searchresults` and `/cy/searchresults` return 200 in this run.
|
||||
- Behavioural test expansion delivered for remaining service domains:
|
||||
- `tests/phase7/service-behaviour.test.cjs`
|
||||
- covers document, portal, account, notify, integration.
|
||||
|
||||
### Phase 7 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `npm run lint` -> warnings only (existing react-hooks dependency warnings; no new lint errors)
|
||||
|
||||
### Phase 7 smoke/negative-path snapshot
|
||||
|
||||
- Dev server auto-bound to `localhost:3001` (3000 already in use).
|
||||
- `GET /searchresults`, `GET /cy/searchresults` -> 200
|
||||
- `GET /case`, `GET /cy/case` -> 200
|
||||
- `GET /myportal`, `GET /cy/myportal` -> 307 redirect to `/auth/signin`
|
||||
- `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> 400
|
||||
- `POST /api/email/notify` with `{}` -> 400
|
||||
|
||||
### Testing strategy decision (captured)
|
||||
|
||||
- Current phase includes **both**:
|
||||
1. migration/parity guard tests,
|
||||
2. focused behavioural unit tests for critical response/error contracts.
|
||||
- Broader behavioural coverage remains a follow-on expansion item after this focused baseline.
|
||||
|
||||
## Phase 8 hardening status (2026-03-13)
|
||||
|
||||
- Working branch created from `origin/SIPS-Development`:
|
||||
- `TASK22017-phase8-hardening-slice`
|
||||
- Sensitive API hardening slice completed across:
|
||||
- `pages/api/file/deleteblobcase.js`
|
||||
- `pages/api/file/deleteblobrep.js`
|
||||
- `pages/api/file/createappealcompletemessage_api.js`
|
||||
- `pages/api/endpoint/getportallogin_api.js`
|
||||
- Hash/integrity posture updates:
|
||||
- re-enabled hash validation on previously bypassed/commented file handlers
|
||||
- added standardized early 400 handling for missing/invalid hash and missing key params
|
||||
- preserved response-shape contracts and function signatures
|
||||
- Logging discipline updates:
|
||||
- removed noisy direct `console.log` usage in `createappealcompletemessage_api`
|
||||
- routed error paths through `consoleLogger` in updated sensitive flow
|
||||
- Required consumer parity updates applied:
|
||||
- `actions/services/documentDirectService.js`
|
||||
- now appends hash for `deleteblobcase` and `deleteblobrep` calls
|
||||
- `actions/services/portalDirectService.js`
|
||||
- now appends hash for `createappealcompletemessage_api` call using existing hash path contract
|
||||
|
||||
### Phase 8 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
### Phase 8 manual HTTP snapshot
|
||||
|
||||
- Dev server on `http://localhost:3001`.
|
||||
- Negative-path checks for invalid/missing hash (and missing required params where relevant) return **400** across all 4 target handlers.
|
||||
- Valid-hash spot-check for `getportallogin_api` reached hash-validated path but still returned **400** due local upstream relay/CRM dependency behavior.
|
||||
|
||||
## Phase 9 hardening status (2026-03-13)
|
||||
|
||||
- Working branch created from `origin/SIPS-Development`:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Additional sensitive API hardening slice completed across:
|
||||
- `pages/api/file/createrepcompletemessage_api.js`
|
||||
- `pages/api/file/upload.js`
|
||||
- `pages/api/file/uploadsinglefile.js`
|
||||
- `pages/api/file/setupcontainer.js`
|
||||
- Hash/integrity posture updates:
|
||||
- re-enabled/enforced hash checks in handlers where hash validation was bypassed/commented
|
||||
- standardized early 400 handling for missing/invalid hash and missing key query/body values
|
||||
- preserved response-shape contracts and function signatures
|
||||
- Logging discipline updates:
|
||||
- removed noisy `console.log` traces from sensitive upload/rep-complete message paths
|
||||
- retained centralized error logging via `consoleLogger` where present
|
||||
- Required caller parity updates applied:
|
||||
- `actions/services/portalDirectService.js`
|
||||
- `sendRepCompleteMessage` now appends hash
|
||||
- `actions/services/documentDirectService.js`
|
||||
- `uploadFiles`, `uploadRepFiles`, `uploadSingleFile` now append hash
|
||||
|
||||
### Phase 9 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
### Phase 9 manual HTTP snapshot
|
||||
|
||||
- Negative-path checks for missing/invalid hash and invalid/missing key params on all 4 phase-9 handlers return **400** on local server (`localhost:3000`).
|
||||
- Valid-hash happy-path spot-check completed using `.env.local` hash key:
|
||||
- `POST /api/file/uploadsinglefile?hash=<valid>` -> **200**
|
||||
|
||||
## Phase 10 hardening status (2026-03-13)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Additional sensitive API hardening slice completed across:
|
||||
- `pages/api/file/getawaitingsubmissionfromblob.js`
|
||||
- `pages/api/file/getprogressobjblob.js`
|
||||
- `pages/api/file/getbloblist.js`
|
||||
- `pages/api/file/getrepsblob.js`
|
||||
- Hash/integrity posture updates:
|
||||
- explicit early 400 guards for missing/empty required query inputs and hash
|
||||
- standardized early hash-mismatch 400 behaviour in all 4 handlers
|
||||
- preserved response-shape contracts and function signatures
|
||||
- Logging discipline updates:
|
||||
- removed old commented debug traces in touched handlers
|
||||
- Caller parity:
|
||||
- no additional service-layer updates required in this slice; existing direct services already append hash for these APIs.
|
||||
|
||||
### Phase 10 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
### Phase 10 manual HTTP snapshot
|
||||
|
||||
- Missing-hash negative-path checks for all 4 handlers return **400** (`localhost:3000`).
|
||||
- Valid-hash spot-check result:
|
||||
- `getbloblist` returned **500** with valid hash in local environment (consistent with downstream/local dependency constraints; hash gate passed).
|
||||
|
||||
## Phase 11 hardening status (2026-03-13)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Additional sensitive API hardening slice completed across:
|
||||
- `pages/api/file/getbloblist.js`
|
||||
- `pages/api/file/deleteblob.js`
|
||||
- `pages/api/file/deleteawaitingsubmissionfromblob.js`
|
||||
- Hash/integrity posture updates:
|
||||
- explicit early 400 guards for missing/empty required query inputs and hash
|
||||
- standardized early hash-mismatch 400 behaviour in all touched handlers
|
||||
- preserved response-shape contracts and function signatures
|
||||
- Logging discipline updates:
|
||||
- removed old commented debug traces in touched handlers
|
||||
- Caller parity:
|
||||
- no additional service-layer updates required in this slice.
|
||||
|
||||
### Phase 11 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `npm run lint` -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
### Phase 11 manual HTTP snapshot
|
||||
|
||||
- Missing/invalid-hash negative-path checks for selected handlers return **400** (`localhost:3000`).
|
||||
- Valid-hash spot-check result:
|
||||
- `getbloblist` returned **500** with valid hash in local environment (consistent with downstream/local dependency constraints; hash gate passed).
|
||||
|
||||
## Phase 12 hardening status (2026-03-13)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Additional sensitive API hardening slice completed across:
|
||||
- `pages/api/file/downloadblob.js`
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
- Hash/integrity posture updates:
|
||||
- explicit early 400 guards for missing/empty required query inputs
|
||||
- standardized early hash-mismatch 400 behaviour in `downloadblob`
|
||||
- preserved response-shape contracts and function signatures
|
||||
|
||||
### Phase 12 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `npm run lint` -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
### Phase 12 manual HTTP snapshot
|
||||
|
||||
- Missing/invalid-input negative-path checks for selected handlers return **400** (`localhost:3000`).
|
||||
- Valid-hash spot-check result:
|
||||
- `downloadblob` returned **500** with valid hash in local environment (consistent with downstream/local dependency constraints; hash gate passed).
|
||||
|
||||
## Phase 13 hardening status (2026-03-13)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Additional sensitive API hardening slice completed across:
|
||||
- `pages/api/file/deleteblobcase.js`
|
||||
- `pages/api/file/deleteblobrep.js`
|
||||
- `pages/api/file/createcaseinvolvement_api.js`
|
||||
- `pages/api/file/createrepinvolvement_api.js`
|
||||
- Hash/integrity posture updates:
|
||||
- explicit early 400 guards for missing/empty required query/body inputs
|
||||
- standardized early hash-mismatch 400 behaviour in delete-blob handlers
|
||||
- preserved response-shape contracts and function signatures
|
||||
- Logging discipline updates:
|
||||
- removed noisy direct body/query logging from involvement handlers
|
||||
|
||||
### Phase 13 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7)
|
||||
- `npm run lint` -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
### Phase 13 manual HTTP snapshot
|
||||
|
||||
- Missing/invalid-input negative-path checks for selected handlers return **400** (`localhost:3000`).
|
||||
- Valid-hash spot-check result:
|
||||
- `deleteblobcase` returned **500** with valid hash in local environment (consistent with downstream/local dependency constraints; hash gate passed).
|
||||
|
||||
## Phase 14 hardening status (2026-03-13)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Addressed browser runtime error in authenticated new-appeal journey:
|
||||
- `TypeError` in `hashAPIPath` caused by client-side code attempting to parse server-only `HASHKEY`.
|
||||
- Implemented server-side hash signing bridge for browser callers:
|
||||
- new endpoint `pages/api/endpoint/gethash_api.js`
|
||||
- session-gated (`getSession`), allow-listed supported API prefixes, returns `{ hash }`.
|
||||
- Updated direct service callers to use signer endpoint instead of direct client hash computation:
|
||||
- `actions/services/documentDirectService.js`
|
||||
- `actions/services/portalDirectService.js`
|
||||
- Maintained contract compatibility for target file APIs and existing response shapes.
|
||||
|
||||
### Phase 14 validation evidence snapshot
|
||||
|
||||
- phase6 parity/behaviour tests -> pass
|
||||
- phase7/8/9/10/11/12/13 behaviour tests -> pass
|
||||
- phase14 behaviour tests -> pass (4/4)
|
||||
- lint -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
## Phase 14 closeout follow-up status (2026-03-13)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Browser-safe hash signing expanded for portal login flow:
|
||||
- `actions/services/accountDirectService.js`
|
||||
- `getPortalLogin` now requests signed hash from `/api/endpoint/gethash_api`
|
||||
- server fallback retained for non-browser contexts when `HASHKEY` is present
|
||||
- `pages/api/endpoint/gethash_api.js`
|
||||
- allow-list now includes `/api/endpoint/getportallogin_api`
|
||||
- Contract alignment + runtime fix updates:
|
||||
- `pages/api/file/getrepsblob.js`
|
||||
- removed hard requirement for `casefolderID` to match actual route contract (`container + hash`)
|
||||
- `components/elements/index.js`
|
||||
- restored missing `updateLinks` import required by Quill-related runtime path
|
||||
|
||||
### Follow-up validation evidence
|
||||
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- full previously-run phase6–phase14 suite remains passing
|
||||
- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` set)
|
||||
|
||||
### Active risk posture after follow-up
|
||||
|
||||
- Signer endpoint scope remains controlled by strict allow-list (single new path added).
|
||||
- Response-shape contract stability preserved for touched handlers/services.
|
||||
- Remaining risk is primarily external dependency behavior on valid-hash happy paths in local environments (relay/storage), not hash-bypass behavior.
|
||||
|
||||
## Likely next steps
|
||||
|
||||
1. Stabilize and simplify breadcrumb/back-link decision logic with focused regression checks.
|
||||
2. Standardize hash-check enforcement patterns across file and endpoint APIs.
|
||||
3. Reduce verbose logging in sensitive flows (auth/email/file/account).
|
||||
4. Expand automated tests for navigation and representation eligibility edge-cases (currently minimal `tests/`).
|
||||
|
||||
See `memory-bank/refactor-backlog.md` for the prioritized refactor plan and sequencing.
|
||||
Priority 1 detailed execution plan is documented in `memory-bank/refactor-plan-actions-index.md`.
|
||||
|
||||
## Areas currently important for contributors
|
||||
|
||||
- `components/breadcrumbs.js`
|
||||
- `components/case/summary.js`
|
||||
- `pages/api/endpoint/**`
|
||||
- `pages/api/file/**`
|
||||
- `pages/api/auth/[...nextauth].js`
|
||||
- `pages/api/email/notify.js`
|
||||
- `next.config.js`, `i18n.js`, `locales/**`
|
||||
@@ -0,0 +1,931 @@
|
||||
# Change Log (AI/Human Curated)
|
||||
|
||||
## Entry Template
|
||||
|
||||
```
|
||||
date: YYYY-MM-DD
|
||||
author: <agent|name>
|
||||
scope: <files/routes/features>
|
||||
type: change
|
||||
rationale: <why change was made>
|
||||
impact: <user/system/security/i18n/a11y>
|
||||
status: completed|rolled-back|partial
|
||||
|
||||
Summary:
|
||||
Validation:
|
||||
Follow-ups:
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CL-001: Initial AI Enablement Bundle
|
||||
|
||||
date: 2026-03-11
|
||||
author: Cline
|
||||
scope: `.clinerules`, `ai-prompts/`, `context/`, `memory-bank/`
|
||||
type: change
|
||||
rationale: Establish consistent AI collaboration, delivery guardrails, and durable project context.
|
||||
impact: Higher consistency/safety in future changes, especially around auth/i18n/public-service reliability.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
Created repository-specific governance, prompt templates, context documentation, and memory protocols with seed entries.
|
||||
|
||||
Validation:
|
||||
|
||||
- File structure and contents created in-repo.
|
||||
- Content aligned to detected stack and key paths (`next-auth`, Prisma, middleware, i18n rewrites, Redux HYDRATE/persist).
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Confirm owner assignments for open questions.
|
||||
- Add automation checks to enforce key guardrails over time.
|
||||
|
||||
---
|
||||
|
||||
### CL-002: Priority 1 Refactor (Phase 1) — `actions/index.js` split foundation
|
||||
|
||||
date: 2026-03-12
|
||||
author: Cline
|
||||
scope: `actions/index.js`, `actions/core/*`, `actions/services/legacyActionsService.js`, `actions/clients/README.md`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Reduce coupling in the actions monolith by extracting core helpers while keeping backward-compatible exports for existing consumers.
|
||||
impact: Lower regression blast radius for future actions-related changes; no intended functional behavior change.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
Extracted helper concerns from `actions/index.js` into focused `actions/core` modules (`env`, `logger`, `hash`, `token`, `headers`). Replaced `actions/index.js` with a compatibility barrel and moved operational wrappers into `actions/services/legacyActionsService.js` with imports from core helpers.
|
||||
|
||||
Validation:
|
||||
|
||||
- Branch created: `0000-update-actions-monolith`.
|
||||
- Compatibility preserved by re-exporting legacy service functions plus core exports from `actions/index.js`.
|
||||
- Lint run for regression check.
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Phase 2: split `legacyActionsService` by domain into dedicated service/client modules.
|
||||
- Add helper-focused automated tests for core modules and export parity checks.
|
||||
|
||||
---
|
||||
|
||||
### CL-003: Priority 1 Refactor (Phase 2) — service grouping via compatibility layer
|
||||
|
||||
date: 2026-03-12
|
||||
author: Cline
|
||||
scope: `actions/services/*`, `actions/index.js`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Continue reducing monolith risk by introducing domain service boundaries while preserving public action exports.
|
||||
impact: Maintains backward compatibility for existing `../actions` imports; improves maintainability and safer future migration to targeted imports.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
Added grouped service modules (`searchService`, `caseService`, `accountService`, `portalService`, `documentService`, `referenceDataService`, `notifyService`, `adminService`, `integrationService`) plus `actions/services/index.js` barrel. Updated `actions/index.js` to export from `./services` (and core modules), keeping legacy function names/signatures available.
|
||||
|
||||
Validation:
|
||||
|
||||
- Service export coverage check confirms all legacy exports are represented in grouped services.
|
||||
- `npm run lint` still fails due legacy Next/ESLint option incompatibility (tooling issue, unchanged by this refactor).
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Incrementally migrate high-churn consumers to direct service imports.
|
||||
- Add automated export-parity and helper unit tests.
|
||||
|
||||
---
|
||||
|
||||
### CL-004: Priority 1 Refactor (Phase 3) — targeted consumer import migration
|
||||
|
||||
date: 2026-03-12
|
||||
author: Cline
|
||||
scope: `components/case/summary.js`, `pages/api/email/notify.js`, selected `pages/api/endpoint/*`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Begin replacing broad `actions` barrel imports with focused service/core module imports in high-churn and representative endpoint areas.
|
||||
impact: Lower coupling to monolithic action entrypoint while preserving behavior and public compatibility.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
Migrated targeted consumers to direct imports from `actions/services/*` and `actions/core/*` without changing function signatures or route contracts.
|
||||
|
||||
Validation:
|
||||
|
||||
- Lint still blocked by repository ESLint/Next option compatibility issue (pre-existing tooling configuration).
|
||||
- Manual testing remains required for search/case/myportal/auth/notify/file matrix.
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Continue phased import migration for additional `pages/api/endpoint/**` handlers.
|
||||
- Add export-parity and helper-level tests as planned.
|
||||
|
||||
---
|
||||
|
||||
### CL-005: Priority 1 Refactor (Phase 4) — helper hardening + redacted logging baseline
|
||||
|
||||
date: 2026-03-12
|
||||
author: Cline
|
||||
scope: `actions/core/{guards,logger}.js`, `actions/index.js`, selected API handlers
|
||||
type: change
|
||||
rationale: Introduce low-risk guard and redaction primitives, then apply them to sensitive/high-churn API paths to reduce injection/privacy risk while preserving behavior.
|
||||
impact: Better input hygiene and safer diagnostics in selected notify/login/contact flows; no intended contract changes.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
Added `guards` helper module (`isNonEmptyString`, `sanitizeString`, `escapeODataString`) and logger redaction utility (`redactSensitive`). Adopted these helpers in `notify`, `getpreferredlanguage_api`, and `createcrmtask_api` handlers.
|
||||
|
||||
Validation:
|
||||
|
||||
- `npm run lint` remains blocked by existing Next/ESLint options incompatibility in repository tooling.
|
||||
- Targeted diff review confirms changes are scoped to helper hardening and selected handlers.
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Continue Phase 4 adoption for additional sensitive file/email/auth handlers.
|
||||
- Add focused unit tests for `guards` and `redactSensitive` behavior.
|
||||
|
||||
---
|
||||
|
||||
### CL-006: Priority 1 Refactor — consumer migration pass (portal/form/admin utilities)
|
||||
|
||||
date: 2026-03-12
|
||||
author: Cline
|
||||
scope: `components/admin/*`, `components/case/*`, `components/myportal/*`, `components/elements/index.js`, `components/utils/index.js`, `lib/*`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Continue Phase 3-style decoupling by replacing broad `actions` barrel imports with focused service/core imports in high-use consumer files while preserving behavior.
|
||||
impact: Lower coupling to monolithic action barrel and clearer dependency boundaries; no intended functional behavior change.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
Migrated a targeted set of portal/form/admin utility consumers from `../../actions`/`../../../actions` to explicit imports from `actions/services/*` and `actions/core/*`. Also resolved migration-side compile issues in `components/myportal/topthree_reps.js` (duplicate import source and invalid `res.status` usage in client context).
|
||||
|
||||
Validation:
|
||||
|
||||
- In-scope consumer files now have no broad `from "../../actions"` / `from "../../../actions"` imports.
|
||||
- `npm run lint` re-run; result unchanged and blocked by pre-existing Next/ESLint option incompatibility.
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Continue migrating remaining broad `actions` imports in `components/myportal/viewall.js`, `components/search/addresssearchresults.js`, unsubscribe flows, and selected API endpoints.
|
||||
- Add focused manual smoke checks for myportal representations and awaiting-submission deletion/edit flows after this import migration.
|
||||
|
||||
---
|
||||
|
||||
### CL-007: Priority 1 Refactor — consumer migration pass (viewall/search/unsubscribe)
|
||||
|
||||
date: 2026-03-12
|
||||
author: Cline
|
||||
scope: `components/myportal/viewall.js`, `components/search/addresssearchresults.js`, `pages/unsubscribe/[watchlistid].js`, `pages/unsubscribeall/[watchlistid].js`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Continue Phase 3 decoupling by removing additional broad `actions` barrel imports in high-use myportal/search/unsubscribe flows and replacing them with focused service/core imports.
|
||||
impact: Reduced coupling to monolithic action barrel with intended behavior parity; no API contract changes intended.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
Migrated four additional consumers away from `../../actions`:
|
||||
|
||||
- `components/myportal/viewall.js` -> `actions/services/documentService`, `actions/services/portalService`, `actions/core/logger`
|
||||
- `components/search/addresssearchresults.js` -> `actions/services/portalService`
|
||||
- `pages/unsubscribe/[watchlistid].js` -> `actions/core/{hash,token,headers,logger}`
|
||||
- `pages/unsubscribeall/[watchlistid].js` -> `actions/core/{hash,token,headers,logger}`
|
||||
|
||||
Validation:
|
||||
|
||||
- Regex verification confirms these four files no longer import from the broad `actions` barrel.
|
||||
- Repository-wide broad-import scan now reports 11 matches total, including comment-only occurrences and remaining endpoint/file handlers pending migration.
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Migrate remaining non-comment broad imports in selected `pages/api/endpoint/*` and `pages/api/file/*` handlers.
|
||||
- Run focused manual smoke checks for myportal view-all watch/unwatch + unsubscribe routes (EN/CY path sanity and negative paths).
|
||||
|
||||
---
|
||||
|
||||
### CL-008: Priority 1 Refactor — endpoint/file proxy import migration chunk
|
||||
|
||||
date: 2026-03-12
|
||||
author: Cline
|
||||
scope: `pages/api/endpoint/*`, `pages/api/file/*` (selected handlers), `memory-bank/*`
|
||||
type: change
|
||||
rationale: Continue Phase 3 migration by replacing broad `actions` barrel imports in selected endpoint/file proxy handlers with focused `actions/core/*` and service module imports.
|
||||
impact: Further reduces monolithic import coupling in API paths while preserving existing request/response behavior and hash/token/header patterns.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
Migrated these handlers away from broad `../../../actions` imports:
|
||||
|
||||
- `pages/api/endpoint/getmylpacases_api.js`
|
||||
- `getLPA` -> `actions/services/referenceDataService`
|
||||
- `azureHeaders`, `consoleLogger`, `getToken`, `hashAPIPath` -> `actions/core/*`
|
||||
- removed local duplicated `hashAPIPath` implementation
|
||||
- `pages/api/endpoint/getbasicdnssearchpaged_api.js`
|
||||
- `pages/api/endpoint/getsearchdocumentdetailspaged_api.js`
|
||||
- `pages/api/endpoint/getbasicsearchpaged_api.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/createappealcompletemessageproxy_api.js`
|
||||
|
||||
Validation:
|
||||
|
||||
- Regex scans over `pages/api/endpoint` and `pages/api/file` show **0** remaining broad `from "../../../actions"` imports.
|
||||
- `git status --short` confirms this chunk is isolated to the targeted endpoint/file handlers.
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Run focused manual smoke checks for touched endpoint/file flows (paged search APIs, LPA case retrieval, blob proxy endpoints).
|
||||
- Continue hardening pass for sensitive handlers with guard/redaction helpers where not yet applied.
|
||||
|
||||
---
|
||||
|
||||
### CL-009: Priority 1 import-migration wave checked in + PR completed; handover to next branch
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `actions/services/*` consumer and endpoint migrations (completed), planning handover docs
|
||||
type: change
|
||||
rationale: Record that the current import-migration wave has been checked in and completed via pull request, and set the next refactor slice to start on a new branch.
|
||||
impact: Clear project continuity and reduced risk of overlap between completed import migration work and upcoming `legacyActionsService` decomposition.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Import migration wave is now completed, checked in, and PR’d.
|
||||
- Latest commits in this wave include:
|
||||
- `f0202bb` — viewall/search/unsubscribe focused imports
|
||||
- `fa98535` — endpoint/file proxy focused imports
|
||||
- `bef8f25` — stale legacy comment cleanup
|
||||
- Next chunk is explicitly designated as a new-branch activity focused on splitting `actions/services/legacyActionsService.js` into smaller direct service/client modules.
|
||||
|
||||
Validation:
|
||||
|
||||
- Broad `.../actions` import scans now show no active matches in `.js` files (legacy references are comment-only/removed).
|
||||
- Branch history confirms migration commits are present and ordered for safe rollback.
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Create new branch for Phase 5 decomposition work.
|
||||
- Start with low-risk extraction slices from `legacyActionsService.js` (reference/search first), then portal/document batches.
|
||||
|
||||
---
|
||||
|
||||
### CL-010: Phase 5 kickoff — first legacy split slice (search/reference direct modules)
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `actions/services/searchDirectService.js`, `actions/services/referenceDataDirectService.js`, `actions/services/{searchService,referenceDataService}.js`
|
||||
type: change
|
||||
rationale: Start Phase 5 decomposition on a new branch by extracting low-risk search/reference wrappers from `legacyActionsService.js` into direct domain modules while keeping service exports stable.
|
||||
impact: Search/reference service exports now route through focused direct modules; compatibility signatures preserved for callers importing from service barrels.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Created branch `TASK21997-phase5-legacyactions-split` from `SIPS-Development`.
|
||||
- Added `searchDirectService.js` containing extracted search/address/document-search wrapper implementations.
|
||||
- Added `referenceDataDirectService.js` containing extracted reference-data wrapper implementations.
|
||||
- Updated `searchService.js` and `referenceDataService.js` to import from the new direct modules instead of `legacyActionsService`.
|
||||
|
||||
Validation:
|
||||
|
||||
- `npm run lint` (result unchanged): still fails due pre-existing Next/ESLint options incompatibility in repository tooling.
|
||||
- Import checks confirm:
|
||||
- `searchService.js` -> `./searchDirectService`
|
||||
- `referenceDataService.js` -> `./referenceDataDirectService`
|
||||
- Branch/status check confirms only Phase 5 slice files are modified on the new branch.
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Continue portal/document extraction slices from `legacyActionsService.js` in small batches.
|
||||
- After each slice, re-point corresponding grouped service modules and remove dead wrappers once no longer referenced.
|
||||
|
||||
---
|
||||
|
||||
### CL-011: Phase 5 document slice — direct document module extraction
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `actions/services/documentDirectService.js`, `actions/services/documentService.js`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Continue Phase 5 decomposition by extracting document/file wrappers from `legacyActionsService.js` into a dedicated direct module while preserving grouped service API compatibility.
|
||||
impact: Document/file grouped service exports now route through focused direct implementation; legacy coupling reduced for document domain with no expected caller contract changes.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Added `documentDirectService.js` with extracted blob/file upload, download, pdf, and container helpers.
|
||||
- Re-pointed `documentService.js` imports to `./documentDirectService`.
|
||||
- Kept export names and signatures unchanged at grouped service boundary.
|
||||
|
||||
Validation:
|
||||
|
||||
- Service import scan confirms `documentService.js` no longer imports from `legacyActionsService`.
|
||||
- Remaining legacy-backed grouped modules: `portalService`, `accountService`, `caseService`, `adminService`, `notifyService`, `integrationService`.
|
||||
- `npm run lint` completes with warnings only (no blocking errors).
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Next recommended slice: `portalDirectService` extraction, then `account/case`.
|
||||
- Continue per-slice parity checks and legacy import reduction scan.
|
||||
|
||||
---
|
||||
|
||||
### CL-012: Phase 5 portal slice — direct portal module extraction
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `actions/services/portalDirectService.js`, `actions/services/portalService.js`
|
||||
type: change
|
||||
rationale: Continue Phase 5 decomposition by extracting portal-domain wrappers from `legacyActionsService` into a direct module while preserving grouped service contract stability.
|
||||
impact: Portal grouped exports now route through a focused direct module; reduced coupling to legacy monolith.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Added `portalDirectService.js`.
|
||||
- Updated `portalService.js` to import from `./portalDirectService`.
|
||||
|
||||
Validation:
|
||||
|
||||
- Legacy import scan reduced remaining `legacyActionsService`-backed grouped modules.
|
||||
- `npm run lint` completes with warnings only.
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Extract account + case direct modules.
|
||||
|
||||
---
|
||||
|
||||
### CL-013: Phase 5 account/case slice — direct module extraction
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `actions/services/{accountDirectService,caseDirectService,accountService,caseService}.js`
|
||||
type: change
|
||||
rationale: Continue Phase 5 by moving account and case wrappers out of legacy module into dedicated direct modules while keeping grouped service API stable.
|
||||
impact: Account/case grouped services now point to direct implementations; further legacy decoupling.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Added `accountDirectService.js` and `caseDirectService.js`.
|
||||
- Re-pointed `accountService.js` and `caseService.js`.
|
||||
|
||||
Validation:
|
||||
|
||||
- Legacy import scan left only admin/integration/notify using legacy.
|
||||
- `npm run lint` completes with warnings only.
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Extract admin + integration + notify direct modules.
|
||||
|
||||
---
|
||||
|
||||
### CL-014: Phase 5 final extraction slice — admin/integration/notify direct modules
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `actions/services/{adminDirectService,integrationDirectService,notifyDirectService,adminService,integrationService,notifyService}.js`
|
||||
type: change
|
||||
rationale: Complete Phase 5 domain decomposition by extracting final legacy-backed grouped services into direct modules.
|
||||
impact: All grouped service modules now route through direct implementations.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Added `adminDirectService.js`, `integrationDirectService.js`, `notifyDirectService.js`.
|
||||
- Re-pointed `adminService.js`, `integrationService.js`, `notifyService.js`.
|
||||
|
||||
Validation:
|
||||
|
||||
- `actions/services` scan reports zero `./legacyActionsService` imports.
|
||||
- `npm run lint` completes with warnings only.
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Remove dead `legacyActionsService.js` implementation.
|
||||
|
||||
---
|
||||
|
||||
### CL-015: Phase 5 cleanup — remove legacy actions service
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `actions/services/legacyActionsService.js` (deleted)
|
||||
type: change
|
||||
rationale: Finalize Phase 5 after full routing migration by removing dead legacy implementation module.
|
||||
impact: Monolithic legacy service removed; architecture now uses grouped service façade + direct per-domain modules.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Deleted `actions/services/legacyActionsService.js` after zero-reference verification.
|
||||
|
||||
Validation:
|
||||
|
||||
- Project scan confirms no `legacyActionsService` references in `.js` files.
|
||||
- `npm run lint` completes with warnings only.
|
||||
- `npm run build` succeeds.
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Begin next phase: post-split hardening/tests/logging cleanup.
|
||||
|
||||
---
|
||||
|
||||
### CL-016: Phase 6 hardening — parity tests, safe dedupe, and logging cleanup
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `actions/services/*DirectService.js`, `actions/services/httpServiceUtils.js`, `tests/phase6/service-parity.test.cjs`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Start post-Phase-5 hardening by adding focused parity checks, reducing repeated axios/error-handling patterns without contract changes, and removing noisy logs in sensitive service paths.
|
||||
impact: Improved maintainability and safety posture in service layer with preserved grouped-service signatures/return shapes; added regression guard for service export stability.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Added `tests/phase6/service-parity.test.cjs` to verify:
|
||||
- grouped service import/export parity for search/reference/document/portal/account/case/admin/integration/notify
|
||||
- `actions/services/index.js` re-export list stability
|
||||
- Added `actions/services/httpServiceUtils.js` with shared helpers:
|
||||
- `logAndReturnResponse`
|
||||
- `buildEmptyValueErrorResponse`
|
||||
- `logAndReturnEmptyValueErrorResponse`
|
||||
- Applied low-risk dedupe refactors in:
|
||||
- `searchDirectService.js`
|
||||
- `referenceDataDirectService.js`
|
||||
- `caseDirectService.js`
|
||||
- `adminDirectService.js`
|
||||
- Removed debug `console.log` traces from sensitive/noisy direct service flows in:
|
||||
- `searchDirectService.js`
|
||||
- `documentDirectService.js`
|
||||
- `portalDirectService.js`
|
||||
- `caseDirectService.js`
|
||||
- `adminDirectService.js`
|
||||
- Added focused behavioural service test pack:
|
||||
- `tests/phase6/service-behaviour.test.cjs`
|
||||
- mocked axios and logger checks to assert success/error contract handling for selected critical functions.
|
||||
|
||||
Validation:
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `npm run lint` -> warnings only (pre-existing warning set)
|
||||
- Targeted smoke/negative checks on local dev server:
|
||||
- `GET /advancedsearch` and `GET /cy/advancedsearch` -> 200
|
||||
- `GET /case` and `GET /cy/case` -> 200
|
||||
- `GET /myportal` and `GET /cy/myportal` -> 307 to `/auth/signin` (unauthenticated negative path)
|
||||
- `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> 400 (negative path)
|
||||
- `POST /api/email/notify` with `{}` -> 400 (negative path)
|
||||
- `GET /searchresults` and `/cy/searchresults` -> 500 due pre-existing SSR serialization issue (`initialState.search.searchString` undefined)
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Investigate/fix pre-existing `/searchresults` SSR serialization issue before broader search smoke confidence sign-off.
|
||||
- Optional next increment: extend behavioural coverage to document/portal/account/notify/integration direct-service contracts.
|
||||
|
||||
---
|
||||
|
||||
### CL-017: Phase 7 hardening — search SSR fix + behavioural expansion for remaining service domains
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `pages/searchresults.js`, `tests/phase7/service-behaviour.test.cjs`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Start Phase 7 from a new branch based on `origin/SIPS-Development`, fix known pre-existing `/searchresults` SSR serialization failure, and extend behavioural/negative-path coverage for remaining direct-service domains.
|
||||
impact: Search results SSR now safely serializes when query `q` is absent; behavioural confidence improved across document/portal/account/notify/integration service contracts with no signature/return-shape changes.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Created branch: `TASK21988a-phase7-postphase6-hardening` (from `origin/SIPS-Development`).
|
||||
- Fixed pre-existing SSR issue in `pages/searchresults.js` by changing:
|
||||
- `setSearch(query.q)` -> `setSearch(query?.q || "")`
|
||||
- Added `tests/phase7/service-behaviour.test.cjs` with mocked-axios behavioural assertions for:
|
||||
- document
|
||||
- portal
|
||||
- account
|
||||
- notify
|
||||
- integration
|
||||
- Included feasible negative-path checks for relay/hash/token-sensitive behavior patterns (hashed URL composition and existing per-function error contracts).
|
||||
|
||||
Validation:
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `npm run lint` -> warnings only, no new lint errors introduced
|
||||
- Manual smoke/negative-path checks (local dev on `localhost:3001` due `3000` in use):
|
||||
- `/searchresults`, `/cy/searchresults` -> 200
|
||||
- `/case`, `/cy/case` -> 200
|
||||
- `/myportal`, `/cy/myportal` -> 307 to `/auth/signin`
|
||||
- `/api/file/getbloblistproxy?container=test&casefolderID=test` -> 400
|
||||
- `POST /api/email/notify` with `{}` -> 400
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Continue incremental hardening in sensitive relay/hash/token flows without changing external contracts.
|
||||
- Keep lint warning backlog separate from this refactor stream unless explicitly scoped.
|
||||
|
||||
Rollback plan:
|
||||
|
||||
- Revert `pages/searchresults.js` and remove `tests/phase7/service-behaviour.test.cjs` if regression is observed.
|
||||
|
||||
---
|
||||
|
||||
### CL-018: Phase 8 hardening — hash enforcement and negative-path standardization in sensitive APIs
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `pages/api/file/{deleteblobcase,deleteblobrep,createappealcompletemessage_api}.js`, `pages/api/endpoint/getportallogin_api.js`, `actions/services/{documentDirectService,portalDirectService}.js`, `tests/phase8/service-behaviour.test.cjs`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Deliver a small reversible hardening slice by re-enforcing hash guards in high-risk handlers, standardizing invalid-input negative paths, and reducing noisy/sensitive logging while preserving external contracts.
|
||||
impact: Stronger hash/integrity guard posture and consistent 400 negative paths for invalid/missing hash and required params; no intended response-shape or signature changes.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Started from latest `origin/SIPS-Development` on new branch `TASK22017-phase8-hardening-slice`.
|
||||
- Re-enabled/enforced hash validation in:
|
||||
- `deleteblobcase`
|
||||
- `deleteblobrep`
|
||||
- `createappealcompletemessage_api`
|
||||
- Standardized early 400 handling for missing required query params where feasible:
|
||||
- container/casefolder/repfile/tempcaseref/emailAddress checks as applicable
|
||||
- Hardened `getportallogin_api`:
|
||||
- explicit early validation for email/hash before token fetch
|
||||
- removed unnecessary lodash branch complexity while preserving output behavior
|
||||
- Improved logging discipline in sensitive flow:
|
||||
- removed noisy `console.log` traces from `createappealcompletemessage_api`
|
||||
- switched error logging to `consoleLogger`
|
||||
- Added parity updates required for existing callers after hash re-enforcement:
|
||||
- `documentDirectService` now appends hash on `deleteblobcase` and `deleteblobrep`
|
||||
- `portalDirectService` now appends hash for `createappealcompletemessage_api` call using existing hash path contract
|
||||
- Added focused phase-8 tests:
|
||||
- `tests/phase8/service-behaviour.test.cjs`
|
||||
- covers invalid/missing hash and missing key inputs as applicable across the 4 target handlers
|
||||
- includes one valid-hash happy-path contract check for `getportallogin_api` via mocks
|
||||
|
||||
Validation:
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings; no new lint errors)
|
||||
- Manual HTTP checks (local server `http://localhost:3001`):
|
||||
- invalid/missing hash for all 4 handlers -> 400
|
||||
- missing required key params where tested -> 400
|
||||
- valid-hash spot-check (`getportallogin_api`) still returned 400 due upstream relay/CRM behavior in local env (hash gate passed, downstream dependency failed)
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Investigate local relay/CRM dependency behavior for `getportallogin_api` happy path in integrated environment.
|
||||
- Continue incremental hash/negative-path hardening for other sensitive `pages/api/file/**` handlers still carrying commented bypass patterns.
|
||||
|
||||
Rollback plan:
|
||||
|
||||
- Revert the four hardened API files and the two direct-service hash append updates.
|
||||
- Remove `tests/phase8/service-behaviour.test.cjs` if the full phase-8 slice is rolled back.
|
||||
- Re-run phase6/phase7 baseline tests and lint to confirm rollback parity.
|
||||
|
||||
---
|
||||
|
||||
### CL-019: Phase 9 hardening — additional file-handler hash enforcement slice
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `pages/api/file/{createrepcompletemessage_api,upload,uploadsinglefile,setupcontainer}.js`, `actions/services/{portalDirectService,documentDirectService}.js`, `tests/phase9/service-behaviour.test.cjs`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Continue incremental hardening with a small reversible slice focused on additional sensitive file handlers still showing bypassed/commented hash checks or inconsistent negative-path behavior.
|
||||
impact: Stronger hash/integrity guard posture and standardized 400 negative paths for invalid/missing hash and key params; no intended signature or response-shape contract changes.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Started from latest `origin/SIPS-Development` on branch `TASK22019-phase-9-hardening`.
|
||||
- Re-enabled/enforced hash validation and early 400 guards in:
|
||||
- `createrepcompletemessage_api`
|
||||
- `upload`
|
||||
- `uploadsinglefile`
|
||||
- `setupcontainer`
|
||||
- Reduced noisy logs in sensitive paths and retained structured error logging where applicable.
|
||||
- Added required caller parity updates:
|
||||
- `portalDirectService.sendRepCompleteMessage` now appends hash
|
||||
- `documentDirectService.uploadFiles/uploadRepFiles/uploadSingleFile` now append hash
|
||||
- Added focused phase-9 tests:
|
||||
- `tests/phase9/service-behaviour.test.cjs`
|
||||
- negative-path coverage for the 4 selected phase-9 handlers
|
||||
|
||||
Validation:
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings; no new lint errors)
|
||||
- Manual HTTP negative-path checks on `localhost:3000`:
|
||||
- missing/invalid hash for each selected handler -> 400
|
||||
- missing required key params where tested -> 400
|
||||
- Valid-hash HTTP spot-check:
|
||||
- `POST /api/file/uploadsinglefile?hash=<valid>` -> 200 (hash generated from `.env.local` key)
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Continue incremental hardening slices for remaining sensitive handlers with commented/bypassed hash checks.
|
||||
|
||||
Rollback plan:
|
||||
|
||||
- Revert the 4 hardened API handlers and 2 caller parity service files.
|
||||
- Remove `tests/phase9/service-behaviour.test.cjs` if rolling back full phase-9 slice.
|
||||
- Re-run phase6/7/8/9 tests and lint to confirm rollback parity.
|
||||
|
||||
---
|
||||
|
||||
### CL-020: Phase 10 hardening — file retrieval handlers negative-path standardization
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `pages/api/file/{getawaitingsubmissionfromblob,getprogressobjblob,getbloblist,getrepsblob}.js`, `tests/phase10/service-behaviour.test.cjs`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Continue connected hardening slices on the same work-item branch, targeting additional sensitive file retrieval handlers with inconsistent early guards and legacy commented hash/debug handling.
|
||||
impact: Stronger and more consistent 400 negative-path behavior for missing/invalid hash and missing key params, with no intended signature or response-shape contract changes.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Continued from Phase 9 on branch `TASK22019-phase-9-hardening`.
|
||||
- Hardened 4 additional handlers:
|
||||
- `getawaitingsubmissionfromblob`
|
||||
- `getprogressobjblob`
|
||||
- `getbloblist`
|
||||
- `getrepsblob`
|
||||
- Added explicit early guards for required query/hash inputs.
|
||||
- Standardized hash mismatch handling to early 400 return.
|
||||
- Removed legacy commented debug blocks in touched handlers.
|
||||
- Added focused phase-10 tests:
|
||||
- `tests/phase10/service-behaviour.test.cjs`
|
||||
- includes negative-path coverage for all 4 handlers and one valid-hash mocked happy path.
|
||||
|
||||
Validation:
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings)
|
||||
- Manual HTTP checks (`localhost:3000`):
|
||||
- missing hash for each selected phase-10 handler -> 400
|
||||
- valid hash `getbloblist` spot-check -> 500 due local downstream/storage dependency constraints
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Continue next incremental slice for remaining sensitive handlers with commented/bypassed hash checks.
|
||||
|
||||
Rollback plan:
|
||||
|
||||
- Revert the 4 hardened API handlers.
|
||||
- Remove `tests/phase10/service-behaviour.test.cjs` if rolling back full phase-10 slice.
|
||||
- Re-run phase6/7/8/9/10 tests + lint to confirm rollback parity.
|
||||
|
||||
---
|
||||
|
||||
### CL-021: Phase 11 hardening — delete/bloblist hash guard standardization
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `pages/api/file/{getbloblist,deleteblob,deleteawaitingsubmissionfromblob}.js`, `tests/phase11/service-behaviour.test.cjs`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Continue connected hardening slices on the same work-item branch, targeting additional sensitive blob/delete handlers with inconsistent early guards and legacy commented traces.
|
||||
impact: More consistent and explicit 400 negative-path handling for missing/invalid hash and key params, with no intended signature or response-shape contract changes.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Continued on branch `TASK22019-phase-9-hardening`.
|
||||
- Hardened 3 additional handlers:
|
||||
- `getbloblist`
|
||||
- `deleteblob`
|
||||
- `deleteawaitingsubmissionfromblob`
|
||||
- Added explicit early guards for required query/hash inputs.
|
||||
- Standardized hash mismatch handling to early 400 return.
|
||||
- Removed legacy commented debug traces in touched handlers.
|
||||
- Added focused phase-11 tests:
|
||||
- `tests/phase11/service-behaviour.test.cjs`
|
||||
- includes negative-path coverage and one valid-hash mocked happy path.
|
||||
|
||||
Validation:
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings)
|
||||
- Manual HTTP checks (`localhost:3000`):
|
||||
- missing/invalid hash for selected phase-11 handlers -> 400
|
||||
- valid-hash `getbloblist` spot-check -> 500 due local downstream/storage dependency constraints
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Continue next incremental slice for remaining sensitive handlers with commented/bypassed hash checks.
|
||||
|
||||
Rollback plan:
|
||||
|
||||
- Revert the 3 hardened API handlers.
|
||||
- Remove `tests/phase11/service-behaviour.test.cjs` if rolling back full phase-11 slice.
|
||||
- Re-run phase6/7/8/9/10/11 tests + lint to confirm rollback parity.
|
||||
|
||||
---
|
||||
|
||||
### CL-022: Phase 12 hardening — download/proxy param and hash guard standardization
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `pages/api/file/{downloadblob,getbloblistproxy,getrepsblobproxy,getawaitingsubmissionfromblobproxy}.js`, `tests/phase12/service-behaviour.test.cjs`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Continue connected hardening slices on the same work-item branch, targeting additional sensitive download/proxy handlers with inconsistent early guards.
|
||||
impact: More consistent and explicit 400 negative-path handling for missing/invalid hash and key params, with no intended signature or response-shape contract changes.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Continued on branch `TASK22019-phase-9-hardening`.
|
||||
- Hardened 4 additional handlers:
|
||||
- `downloadblob`
|
||||
- `getbloblistproxy`
|
||||
- `getrepsblobproxy`
|
||||
- `getawaitingsubmissionfromblobproxy`
|
||||
- Added explicit early guards for required query/hash inputs.
|
||||
- Standardized hash mismatch handling to early 400 return for `downloadblob`.
|
||||
- Added focused phase-12 tests:
|
||||
- `tests/phase12/service-behaviour.test.cjs`
|
||||
- includes negative-path coverage and one valid-hash mocked happy path.
|
||||
|
||||
Validation:
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings)
|
||||
- Manual HTTP checks (`localhost:3000`):
|
||||
- missing/invalid inputs for selected phase-12 handlers -> 400
|
||||
- valid-hash `downloadblob` spot-check -> 500 due local downstream/storage dependency constraints
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Continue next incremental slice for remaining sensitive handlers with commented/bypassed hash checks.
|
||||
|
||||
Rollback plan:
|
||||
|
||||
- Revert the 4 hardened API handlers.
|
||||
- Remove `tests/phase12/service-behaviour.test.cjs` if rolling back full phase-12 slice.
|
||||
- Re-run phase6/7/8/9/10/11/12 tests + lint to confirm rollback parity.
|
||||
|
||||
---
|
||||
|
||||
### CL-023: Phase 13 hardening — delete and involvement handler guard standardization
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `pages/api/file/{deleteblobcase,deleteblobrep,createcaseinvolvement_api,createrepinvolvement_api}.js`, `tests/phase13/service-behaviour.test.cjs`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Continue connected hardening slices on the same work-item branch, targeting additional sensitive delete/involvement handlers with inconsistent early guard and logging behavior.
|
||||
impact: More consistent and explicit 400 negative-path handling for missing/invalid hash and required body keys, with no intended signature or response-shape contract changes.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Continued on branch `TASK22019-phase-9-hardening`.
|
||||
- Hardened 4 additional handlers:
|
||||
- `deleteblobcase`
|
||||
- `deleteblobrep`
|
||||
- `createcaseinvolvement_api`
|
||||
- `createrepinvolvement_api`
|
||||
- Added explicit early guards for required hash/body inputs.
|
||||
- Standardized hash mismatch handling to early 400 return for delete handlers.
|
||||
- Removed noisy body/query logs from involvement handlers.
|
||||
- Added focused phase-13 tests:
|
||||
- `tests/phase13/service-behaviour.test.cjs`
|
||||
- includes negative-path coverage and valid-input mocked happy paths.
|
||||
|
||||
Validation:
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7)
|
||||
- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings)
|
||||
- Manual HTTP checks (`localhost:3000`):
|
||||
- missing/invalid inputs for selected phase-13 handlers -> 400
|
||||
- valid-hash `deleteblobcase` spot-check -> 500 due local downstream/storage dependency constraints
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Continue next incremental slice for remaining sensitive handlers with commented/bypassed hash checks.
|
||||
|
||||
Rollback plan:
|
||||
|
||||
- Revert the 4 hardened API handlers.
|
||||
- Remove `tests/phase13/service-behaviour.test.cjs` if rolling back full phase-13 slice.
|
||||
- Re-run phase6/7/8/9/10/11/12/13 tests + lint to confirm rollback parity.
|
||||
|
||||
---
|
||||
|
||||
### CL-024: Phase 14 fix — authenticated server-side hash signing for browser callers
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `actions/services/{documentDirectService,portalDirectService}.js`, `pages/api/endpoint/gethash_api.js`, `tests/phase14/service-behaviour.test.cjs`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Fix runtime break in authenticated new-appeal journey where client-side hash generation attempted to use server-only `HASHKEY`.
|
||||
impact: Restores browser flow while preserving hash-guard posture by moving hash generation to authenticated server endpoint; no intended external API contract changes.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Added `gethash_api` endpoint to sign allow-listed API paths server-side.
|
||||
- Endpoint enforces authenticated session and rejects unsupported paths.
|
||||
- Updated direct services to fetch hash from signer endpoint for browser calls.
|
||||
- Added server-side fallback hashing only when `HASHKEY` exists (non-browser contexts).
|
||||
- Added phase-14 tests for missing-path, invalid-path, unauthenticated, and happy-path signer behavior.
|
||||
|
||||
Validation:
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> pass
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> pass
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `npm run lint` -> warnings only (pre-existing warnings)
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Keep signer allow-list tight and expand only for explicitly required browser-side hash use cases.
|
||||
- Continue removing legacy client-side direct hash assumptions as encountered.
|
||||
|
||||
---
|
||||
|
||||
### CL-025: Phase 14 closeout follow-up — portal-login signer adoption + contract alignment fixes
|
||||
|
||||
date: 2026-03-13
|
||||
author: Cline
|
||||
scope: `actions/services/accountDirectService.js`, `pages/api/endpoint/gethash_api.js`, `tests/phase7/service-behaviour.test.cjs`, `tests/phase14/service-behaviour.test.cjs`, `pages/api/file/getrepsblob.js`, `components/elements/index.js`, `memory-bank/*`
|
||||
type: change
|
||||
rationale: Extend browser-safe hash signing to portal-login call path, keep signer allow-list explicit, and align an over-tightened file guard with actual endpoint contract discovered during runtime verification.
|
||||
impact: Removes remaining browser-side hash risk in portal login path; preserves API response contracts while restoring route-accurate parameter validation and resolving Quill runtime import issue.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Updated `accountDirectService.getPortalLogin` to use `/api/endpoint/gethash_api` for signed hash retrieval in browser contexts.
|
||||
- Added `/api/endpoint/getportallogin_api` to signer endpoint allow-list in `gethash_api.js`.
|
||||
- Updated tests to reflect signer-driven behavior and allow-list coverage:
|
||||
- `tests/phase7/service-behaviour.test.cjs`
|
||||
- `tests/phase14/service-behaviour.test.cjs`
|
||||
- Applied follow-up runtime/contract fixes confirmed during manual verification:
|
||||
- `pages/api/file/getrepsblob.js`: removed `casefolderID` hard requirement and pass-through argument to align with route usage (`container + hash`).
|
||||
- `components/elements/index.js`: restored missing `updateLinks` import required by Quill-related flow.
|
||||
- Branch pushed with follow-up commits:
|
||||
- `6094874`
|
||||
- `b8fa514`
|
||||
|
||||
Validation:
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7)
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Keep signer allow-list expansion minimal and task-driven.
|
||||
- Continue replacing remaining browser-side direct hash assumptions only where flows require it.
|
||||
- Confirm work-item/branch naming alignment for any subsequent phase slices if strict tracker continuity is required.
|
||||
@@ -0,0 +1,632 @@
|
||||
# Progress — PEDW FrontEnd
|
||||
|
||||
## Completed / evidenced milestones
|
||||
|
||||
- Bilingual routing structure is established with extensive Welsh rewrites and locale namespace mapping.
|
||||
- Next-auth + Prisma SQL Server persistence is integrated for user/session lifecycle.
|
||||
- Broad API surface exists for search, case, portal, admin, and file/document operations.
|
||||
- CRM/relay hash pattern is implemented across many endpoint handlers.
|
||||
- Recent shipped updates focused on:
|
||||
- search/case back-navigation and breadcrumb behavior,
|
||||
- DNS/view-all navigation logic,
|
||||
- preferred-language handling for notify template selection,
|
||||
- PDF formatting/hyperlink fixes,
|
||||
- upload validation character updates.
|
||||
|
||||
## Work in progress signals
|
||||
|
||||
- Ongoing iterative fixes in breadcrumb/case-summary flows suggest navigation consistency is still being tuned.
|
||||
- Mixed proxy/non-proxy endpoint implementations continue to evolve in parallel.
|
||||
- Priority 1 refactor plan execution started for `actions/index.js` split (Phase 1 foundation complete).
|
||||
|
||||
## Planned / partially implemented (inferred from code state)
|
||||
|
||||
- Partial migration or coexistence of deployment/runtime patterns (Next runtime plus custom server artifacts).
|
||||
- Continued refinement of document/email workflow behavior (template/language and formatting quality).
|
||||
- Prioritized structural refactor backlog documented in `memory-bank/refactor-backlog.md`.
|
||||
|
||||
## Known technical debt
|
||||
|
||||
- `actions/services/legacyActionsService.js` still holds broad domain wrappers after Phase 1 extraction (core helpers now separated).
|
||||
- Significant duplication of token/hash/relay logic across endpoint files.
|
||||
- Inconsistent security/hash guard enforcement in some file routes.
|
||||
- Sparse automated test coverage (`tests/` currently empty).
|
||||
- Verbose logging in sensitive flows (auth/email/actions/file) increases privacy risk.
|
||||
|
||||
## Latest update (2026-03-12)
|
||||
|
||||
- Branch `0000-update-actions-monolith` created from development branch for Priority 1 refactor implementation.
|
||||
- `actions/index.js` reduced to a compatibility barrel.
|
||||
- New core helper modules added under `actions/core/`:
|
||||
- `env.js`
|
||||
- `logger.js`
|
||||
- `hash.js`
|
||||
- `token.js`
|
||||
- `headers.js`
|
||||
- Existing action wrappers moved to `actions/services/legacyActionsService.js` and continue to be exported via the barrel for compatibility.
|
||||
- `actions/clients/` scaffolded for upcoming client extraction phase.
|
||||
- Phase 2 service grouping completed with dedicated service files and `actions/services/index.js` barrel.
|
||||
- Export parity check confirms grouped service modules cover all legacy exported action names.
|
||||
- Phase 3 migration started by moving selected high-churn consumers and representative endpoint handlers to direct `actions/services/*` and `actions/core/*` imports.
|
||||
- Phase 4 hardening baseline added with new guard helpers and redacted logging, adopted in selected notify/login/contact API handlers.
|
||||
- Additional Priority 1 consumer migration pass completed for high-use portal/form/representation helpers:
|
||||
- Updated direct service/core imports in:
|
||||
- `components/admin/tabs/documents.js`
|
||||
- `components/admin/tabs/storage.js`
|
||||
- `components/admin/utils/serverside.js`
|
||||
- `components/case/documents.js`
|
||||
- `components/case/representation/representationComplete.js`
|
||||
- `components/case/representation/representationElements.js`
|
||||
- `components/elements/index.js`
|
||||
- `components/myportal/awaitingsubmissionfromblob.js`
|
||||
- `components/myportal/topthree.js`
|
||||
- `components/myportal/topthree_reps.js`
|
||||
- `components/utils/index.js`
|
||||
- `lib/myportal/loadMyPortalAppealPage.js`
|
||||
- `lib/newappeal/loadNewAppealPage.js`
|
||||
- Additional Priority 1 consumer migration pass completed for view-all/search/unsubscribe flows:
|
||||
- Updated direct service/core imports in:
|
||||
- `components/myportal/viewall.js`
|
||||
- `components/search/addresssearchresults.js`
|
||||
- `pages/unsubscribe/[watchlistid].js`
|
||||
- `pages/unsubscribeall/[watchlistid].js`
|
||||
- Broad `actions` barrel import count reduced again; remaining non-comment usages are now concentrated in selected `pages/api/endpoint/*` and `pages/api/file/*` handlers.
|
||||
- Additional Priority 1 endpoint/file proxy migration chunk completed:
|
||||
- Updated imports in:
|
||||
- `pages/api/endpoint/getmylpacases_api.js`
|
||||
- `pages/api/endpoint/getbasicdnssearchpaged_api.js`
|
||||
- `pages/api/endpoint/getsearchdocumentdetailspaged_api.js`
|
||||
- `pages/api/endpoint/getbasicsearchpaged_api.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/createappealcompletemessageproxy_api.js`
|
||||
- Migrated from broad `../../../actions` imports to focused `actions/core/*` + service imports.
|
||||
- Removed duplicated local hash helper in `getmylpacases_api.js` and reused `actions/core/hash`.
|
||||
- Broad `actions` import scan now reports only comment-only references (no active broad imports in `.js` files).
|
||||
- Lint check re-run outcome unchanged: `next lint` fails due legacy/unsupported ESLint options in repo tooling config (not introduced by this refactor pass).
|
||||
|
||||
## Handover update (2026-03-13)
|
||||
|
||||
- Priority 1 import-migration wave has been checked in and completed via pull request.
|
||||
- Recent migration commits captured in this wave:
|
||||
- `f0202bb`
|
||||
- `fa98535`
|
||||
- `bef8f25`
|
||||
- Active broad `.../actions` imports are now eliminated from live `.js` code paths.
|
||||
- Next refactor phase will begin on a **new branch** and focus on splitting `actions/services/legacyActionsService.js` into smaller direct implementation modules.
|
||||
- Recommended decomposition order for the new branch:
|
||||
1. reference/search extraction
|
||||
2. portal/document extraction
|
||||
3. compatibility layer slimming + dead wrapper removal
|
||||
|
||||
## Latest update (2026-03-13 — Phase 5 kickoff)
|
||||
|
||||
- New branch created from `SIPS-Development`: `TASK21997-phase5-legacyactions-split`.
|
||||
- Completed first Phase 5 decomposition slice from `legacyActionsService`:
|
||||
- Added `actions/services/searchDirectService.js`
|
||||
- Added `actions/services/referenceDataDirectService.js`
|
||||
- Updated `actions/services/searchService.js` to source from `searchDirectService`
|
||||
- Updated `actions/services/referenceDataService.js` to source from `referenceDataDirectService`
|
||||
- Compatibility approach preserved: public grouped service exports and function signatures remain unchanged for callers.
|
||||
- Validation status unchanged:
|
||||
- `npm run lint` still fails due pre-existing Next/ESLint option incompatibility in repo tooling configuration.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 5 document slice)
|
||||
|
||||
- Continued on branch `TASK21997-phase5-legacyactions-split`.
|
||||
- Completed second decomposition slice from `legacyActionsService`:
|
||||
- Added `actions/services/documentDirectService.js`
|
||||
- Updated `actions/services/documentService.js` to source from `documentDirectService`
|
||||
- Compatibility approach preserved:
|
||||
- grouped service export names/signatures unchanged for consumers.
|
||||
- Verification:
|
||||
- service import scan now shows remaining legacy-backed grouped modules are:
|
||||
- `portalService`, `accountService`, `caseService`, `adminService`, `notifyService`, `integrationService`
|
||||
- `npm run lint` passes with warnings only (no blocking errors).
|
||||
|
||||
## Latest update (2026-03-13 — Phase 5 completion)
|
||||
|
||||
- Continued decomposition and completed all remaining slices on `TASK21997-phase5-legacyactions-split`:
|
||||
- portal direct extraction
|
||||
- account + case direct extraction
|
||||
- admin + integration + notify direct extraction
|
||||
- legacy cleanup/removal
|
||||
- New direct modules now in place:
|
||||
- `portalDirectService.js`
|
||||
- `accountDirectService.js`
|
||||
- `caseDirectService.js`
|
||||
- `adminDirectService.js`
|
||||
- `integrationDirectService.js`
|
||||
- `notifyDirectService.js`
|
||||
- `actions/services/legacyActionsService.js` removed after import parity checks.
|
||||
- Validation evidence:
|
||||
- `actions/services` import scan: zero `./legacyActionsService` references
|
||||
- `npm run lint`: warnings only, no blocking errors
|
||||
- `npm run build`: successful production build
|
||||
|
||||
## Latest update (2026-03-13 — Phase 6 post-Phase-5 hardening, in progress)
|
||||
|
||||
- Branch created from `SIPS-Development`: `TASK21998-phase6-postphase5-hardening`.
|
||||
- Added focused parity checks for grouped/direct service stability and service index barrel stability:
|
||||
- `tests/phase6/service-parity.test.cjs`
|
||||
- validates grouped service import/export parity across:
|
||||
- search, referenceData, document, portal, account, case, admin, integration, notify
|
||||
- validates `actions/services/index.js` export list stability/order.
|
||||
- Added shared service error helper:
|
||||
- `actions/services/httpServiceUtils.js`
|
||||
- centralizes common `consoleLogger + return error.response` and `ErrResponse` shape patterns.
|
||||
- Applied low-risk duplication reduction in direct services (no signature/shape changes intended):
|
||||
- `searchDirectService.js`
|
||||
- `referenceDataDirectService.js`
|
||||
- `caseDirectService.js`
|
||||
- `adminDirectService.js`
|
||||
- Logging cleanup/redaction-oriented hardening (sensitive-flow noisy logs removed):
|
||||
- removed debug `console.log` statements from:
|
||||
- `searchDirectService.js`
|
||||
- `documentDirectService.js`
|
||||
- `portalDirectService.js`
|
||||
- `caseDirectService.js`
|
||||
- `adminDirectService.js`
|
||||
|
||||
### Validation snapshot (Phase 6)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `npm run lint` -> **warnings only** (same pre-existing warnings)
|
||||
|
||||
### Decision captured (Phase 6)
|
||||
|
||||
- Agreed approach: keep parity guard tests **and** add focused behavioural unit tests in the current refactor stream (instead of deferring all behavioural checks to long-term roadmap).
|
||||
- Implemented now:
|
||||
- `tests/phase6/service-behaviour.test.cjs`
|
||||
- mocked-axios behavioural checks for critical success/error contracts across search/reference/case/admin direct services.
|
||||
- Wider behavioural expansion remains on roadmap for additional domains/functions.
|
||||
|
||||
### Targeted smoke snapshot (local dev server)
|
||||
|
||||
- Search flow:
|
||||
- `GET /searchresults` (EN/CY) -> **500** in local env due existing serialization issue (`initialState.search.searchString` undefined in SSR payload), observed in `/tmp/phase6-dev.log`.
|
||||
- `GET /advancedsearch` and `GET /cy/advancedsearch` -> **200**
|
||||
- Case flow:
|
||||
- `GET /case` and `GET /cy/case` -> **200**
|
||||
- My Portal flow (negative-path):
|
||||
- `GET /myportal` and `GET /cy/myportal` -> **307** redirect to `/auth/signin` (expected unauthenticated behavior)
|
||||
- Document flow (negative-path):
|
||||
- `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> **400**
|
||||
- Notify flow (negative-path):
|
||||
- `POST /api/email/notify` with `{}` -> **400**
|
||||
|
||||
## Latest update (2026-03-13 — Phase 8 hardening slice)
|
||||
|
||||
- New branch created from `origin/SIPS-Development` with work item prefix:
|
||||
- `TASK22017-phase8-hardening-slice`
|
||||
- Hardened four sensitive API handlers with minimal reversible guards:
|
||||
- `pages/api/file/deleteblobcase.js`
|
||||
- `pages/api/file/deleteblobrep.js`
|
||||
- `pages/api/file/createappealcompletemessage_api.js`
|
||||
- `pages/api/endpoint/getportallogin_api.js`
|
||||
- Scope delivered:
|
||||
- re-enabled/enforced hash checks where bypassed/commented
|
||||
- standardized early 400 negative paths for missing/invalid required query inputs
|
||||
- reduced noisy sensitive-path logging and routed errors through `consoleLogger`
|
||||
- preserved function signatures and existing response-shape contracts
|
||||
- Consumer parity updates (required to preserve behaviour after hash enforcement):
|
||||
- `actions/services/documentDirectService.js`
|
||||
- append hash for delete-blob-case/delete-blob-rep calls
|
||||
- `actions/services/portalDirectService.js`
|
||||
- append hash for create-appeal-complete-message call (hash path preserved to existing API contract)
|
||||
- Added focused tests:
|
||||
- `tests/phase8/service-behaviour.test.cjs`
|
||||
- covers negative paths for all 4 handlers (missing/invalid hash and missing key params as applicable)
|
||||
- includes one happy-path check for `getportallogin_api` with valid hash via mocked dependencies
|
||||
|
||||
### Validation snapshot (Phase 8)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `npm run lint` -> **warnings only** (pre-existing react-hooks dependency warnings; no new lint errors)
|
||||
|
||||
### Manual HTTP checks (Phase 8)
|
||||
|
||||
- Local dev server on `http://localhost:3001`.
|
||||
- Negative-path checks:
|
||||
- `GET /api/file/deleteblobcase?...` missing hash -> **400**
|
||||
- `GET /api/file/deleteblobcase?...&hash=bad` -> **400**
|
||||
- `GET /api/file/deleteblobrep?...` missing hash -> **400**
|
||||
- `GET /api/file/deleteblobrep?...&hash=bad` -> **400**
|
||||
- `GET /api/file/deleteblobrep?...` missing `repfile` -> **400**
|
||||
- `GET /api/file/createappealcompletemessage_api?...` missing hash -> **400**
|
||||
- `GET /api/file/createappealcompletemessage_api?...&hash=bad` -> **400**
|
||||
- `GET /api/file/createappealcompletemessage_api?...` missing `tempcaseref` -> **400**
|
||||
- `GET /api/endpoint/getportallogin_api?...` missing hash -> **400**
|
||||
- `GET /api/endpoint/getportallogin_api?...&hash=bad` -> **400**
|
||||
- `GET /api/endpoint/getportallogin_api?...` missing `emailAddress` -> **400**
|
||||
- Valid-hash spot-check:
|
||||
- `GET /api/endpoint/getportallogin_api?...&hash=<valid>` reached handler with valid hash but returned **400** from upstream relay/CRM call in local environment (expected environmental dependency risk, not hash-guard bypass).
|
||||
|
||||
## Latest update (2026-03-13 — Phase 9 hardening slice)
|
||||
|
||||
- New branch created from `origin/SIPS-Development` with work item prefix:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Hardened four additional sensitive file handlers with minimal reversible changes:
|
||||
- `pages/api/file/createrepcompletemessage_api.js`
|
||||
- `pages/api/file/upload.js`
|
||||
- `pages/api/file/uploadsinglefile.js`
|
||||
- `pages/api/file/setupcontainer.js`
|
||||
- Scope delivered:
|
||||
- re-enabled/enforced hash validation where bypassed/commented
|
||||
- added/standardized early 400 negative paths for missing/invalid hash and missing key parameters
|
||||
- reduced noisy logging in sensitive file-upload/message paths
|
||||
- preserved handler signatures and external response-shape contracts
|
||||
- Consumer parity updates:
|
||||
- `actions/services/portalDirectService.js`
|
||||
- append hash for `createrepcompletemessage_api` call
|
||||
- `actions/services/documentDirectService.js`
|
||||
- append hash for `upload` and `uploadsinglefile` calls
|
||||
- Added focused tests:
|
||||
- `tests/phase9/service-behaviour.test.cjs`
|
||||
- covers negative paths across all 4 phase-9 handlers
|
||||
|
||||
### Validation snapshot (Phase 9)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors)
|
||||
|
||||
### Manual HTTP checks (Phase 9)
|
||||
|
||||
- Negative-path checks on `localhost:3000`:
|
||||
- `GET /api/file/createrepcompletemessage_api?...` missing hash -> **400**
|
||||
- `GET /api/file/createrepcompletemessage_api?...&hash=bad` -> **400**
|
||||
- `POST /api/file/upload` missing hash -> **400**
|
||||
- `POST /api/file/upload?hash=bad` -> **400**
|
||||
- `POST /api/file/uploadsinglefile` missing hash -> **400**
|
||||
- `POST /api/file/uploadsinglefile?hash=bad` -> **400**
|
||||
- `GET /api/file/setupcontainer?ident=...` missing hash -> **400**
|
||||
- `GET /api/file/setupcontainer?ident=...&hash=bad` -> **400**
|
||||
- `GET /api/file/setupcontainer?hash=bad` (missing ident) -> **400**
|
||||
- Valid-hash happy-path spot-check:
|
||||
- Completed using `.env.local` runtime key: `POST /api/file/uploadsinglefile?hash=<valid>` -> **200**
|
||||
|
||||
### Rollback plan (Phase 9)
|
||||
|
||||
1. Revert the four hardened API handlers.
|
||||
2. Revert direct-service hash append changes in `documentDirectService` and `portalDirectService`.
|
||||
3. Remove `tests/phase9/service-behaviour.test.cjs` if full slice rollback required.
|
||||
4. Re-run phase6/7/8/9 baseline tests + lint after rollback.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 10 hardening slice)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Hardened four additional sensitive file handlers with minimal reversible changes:
|
||||
- `pages/api/file/getawaitingsubmissionfromblob.js`
|
||||
- `pages/api/file/getprogressobjblob.js`
|
||||
- `pages/api/file/getbloblist.js`
|
||||
- `pages/api/file/getrepsblob.js`
|
||||
- Scope delivered:
|
||||
- added explicit early 400 handling for missing/empty required inputs (`container`, `casefolderID` where applicable, `hash`)
|
||||
- standardized hash-mismatch negative-path checks to early return 400
|
||||
- removed legacy/noisy commented debug blocks from touched handlers
|
||||
- preserved existing handler signatures and response-shape contracts
|
||||
- Caller parity impact:
|
||||
- no new caller changes required in this slice because direct-service consumers already append hash for these APIs.
|
||||
- Added focused tests:
|
||||
- `tests/phase10/service-behaviour.test.cjs`
|
||||
- covers negative paths for all 4 selected phase-10 handlers
|
||||
- includes one valid-hash contract-preserving happy-path check (`getbloblist` via mocked dependencies)
|
||||
|
||||
### Validation snapshot (Phase 10)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors)
|
||||
|
||||
### Manual HTTP checks (Phase 10)
|
||||
|
||||
- Negative-path checks on `localhost:3000`:
|
||||
- `GET /api/file/getawaitingsubmissionfromblob?container=test` (missing hash) -> **400**
|
||||
- `GET /api/file/getprogressobjblob?container=test&casefolderID=case-1` (missing hash) -> **400**
|
||||
- `GET /api/file/getbloblist?container=test&casefolderID=case-1` (missing hash) -> **400**
|
||||
- `GET /api/file/getrepsblob?container=test&casefolderID=case-1` (missing hash) -> **400**
|
||||
- Valid-hash happy-path spot-check:
|
||||
- `GET /api/file/getbloblist?container=test&casefolderID=case-1&hash=<valid>` -> **500**
|
||||
- expected due local storage/upstream dependency constraints, while confirming hash gate is no longer the failing check.
|
||||
|
||||
### Rollback plan (Phase 10)
|
||||
|
||||
1. Revert the four hardened API handlers.
|
||||
2. Remove `tests/phase10/service-behaviour.test.cjs` if full phase-10 rollback required.
|
||||
3. Re-run phase6/7/8/9/10 baseline tests + lint after rollback.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 11 hardening slice)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Hardened three additional sensitive file handlers with minimal reversible changes:
|
||||
- `pages/api/file/getbloblist.js`
|
||||
- `pages/api/file/deleteblob.js`
|
||||
- `pages/api/file/deleteawaitingsubmissionfromblob.js`
|
||||
- Scope delivered:
|
||||
- added explicit early 400 handling for missing/empty required query inputs (`container`, `casefolderID`, `blobname`, `hash` as applicable)
|
||||
- standardized hash-mismatch negative-path checks to early return 400
|
||||
- removed legacy/noisy commented debug traces in touched handlers
|
||||
- preserved existing handler signatures and response-shape contracts
|
||||
- Caller parity impact:
|
||||
- no new caller changes required in this slice; direct-service consumers already pass expected query/hash data.
|
||||
- Added focused tests:
|
||||
- `tests/phase11/service-behaviour.test.cjs`
|
||||
- covers negative paths for selected phase-11 handlers
|
||||
- includes one valid-hash contract-preserving happy-path check (`getbloblist` via mocked dependencies)
|
||||
|
||||
### Validation snapshot (Phase 11)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors)
|
||||
|
||||
### Manual HTTP checks (Phase 11)
|
||||
|
||||
- Negative-path checks on `localhost:3000`:
|
||||
- `GET /api/file/getbloblist?container=test&casefolderID=case-1` (missing hash) -> **400**
|
||||
- `GET /api/file/deleteblob?container=test&casefolderID=case-1&blobname=file.pdf` (missing hash) -> **400**
|
||||
- `GET /api/file/deleteawaitingsubmissionfromblob?container=test&casefolderID=case-1&blobname=file.pdf` (missing hash) -> **400**
|
||||
- `GET /api/file/deleteblob?container=test&casefolderID=case-1&hash=bad` (missing blobname/invalid hash) -> **400**
|
||||
- Valid-hash happy-path spot-check:
|
||||
- `GET /api/file/getbloblist?container=test&casefolderID=case-1&hash=<valid>` -> **500**
|
||||
- expected due local storage/upstream dependency constraints, while confirming hash gate is no longer the failing check.
|
||||
|
||||
### Rollback plan (Phase 11)
|
||||
|
||||
1. Revert the three hardened API handlers.
|
||||
2. Remove `tests/phase11/service-behaviour.test.cjs` if full phase-11 rollback required.
|
||||
3. Re-run phase6/7/8/9/10/11 baseline tests + lint after rollback.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 12 hardening slice)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Hardened four additional sensitive handlers with minimal reversible changes:
|
||||
- `pages/api/file/downloadblob.js`
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
- Scope delivered:
|
||||
- added explicit early 400 handling for missing/empty required query inputs (`container`, `casefolderID`, `blobname`, `hash` as applicable)
|
||||
- standardized hash-mismatch negative-path checks for `downloadblob`
|
||||
- preserved existing function signatures and response-shape contracts
|
||||
- Added focused tests:
|
||||
- `tests/phase12/service-behaviour.test.cjs`
|
||||
- covers negative paths for selected phase-12 handlers
|
||||
- includes one valid-hash contract-preserving happy-path check (`downloadblob` via mocked dependencies)
|
||||
|
||||
### Validation snapshot (Phase 12)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors)
|
||||
|
||||
### Manual HTTP checks (Phase 12)
|
||||
|
||||
- Negative-path checks on `localhost:3000`:
|
||||
- `GET /api/file/downloadblob?container=test&casefolderID=case-1&blobname=file.pdf` (missing hash) -> **400**
|
||||
- `GET /api/file/downloadblob?container=test&casefolderID=case-1&blobname=file.pdf&hash=bad` -> **400**
|
||||
- `GET /api/file/getbloblistproxy?casefolderID=case-1` (missing container) -> **400**
|
||||
- `GET /api/file/getrepsblobproxy` (missing container) -> **400**
|
||||
- `GET /api/file/getawaitingsubmissionfromblobproxy` (missing container) -> **400**
|
||||
- Valid-hash happy-path spot-check:
|
||||
- `GET /api/file/downloadblob?container=test&casefolderID=case-1&blobname=file.pdf&hash=<valid>` -> **500**
|
||||
- expected due local storage/upstream dependency constraints, while confirming hash gate is no longer the failing check.
|
||||
|
||||
### Rollback plan (Phase 12)
|
||||
|
||||
1. Revert the four hardened API handlers.
|
||||
2. Remove `tests/phase12/service-behaviour.test.cjs` if full phase-12 rollback required.
|
||||
3. Re-run phase6/7/8/9/10/11/12 baseline tests + lint after rollback.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 13 hardening slice)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Hardened four additional sensitive handlers with minimal reversible changes:
|
||||
- `pages/api/file/deleteblobcase.js`
|
||||
- `pages/api/file/deleteblobrep.js`
|
||||
- `pages/api/file/createcaseinvolvement_api.js`
|
||||
- `pages/api/file/createrepinvolvement_api.js`
|
||||
- Scope delivered:
|
||||
- added explicit early 400 handling for missing/empty required query/body inputs (`hash`, `contactid`, `incidentid` as applicable)
|
||||
- standardized hash-mismatch negative-path checks for delete-blob handlers
|
||||
- removed noisy body/query logging in involvement handlers
|
||||
- preserved existing function signatures and response-shape contracts
|
||||
- Added focused tests:
|
||||
- `tests/phase13/service-behaviour.test.cjs`
|
||||
- covers negative paths for selected phase-13 handlers
|
||||
- includes valid-hash/valid-body contract-preserving happy-path checks via mocked dependencies
|
||||
|
||||
### Validation snapshot (Phase 13)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7)
|
||||
- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors)
|
||||
|
||||
### Manual HTTP checks (Phase 13)
|
||||
|
||||
- Negative-path checks on `localhost:3000`:
|
||||
- `GET /api/file/deleteblobcase?container=test&casefolderID=case-1` (missing hash) -> **400**
|
||||
- `GET /api/file/deleteblobcase?container=test&casefolderID=case-1&hash=bad` -> **400**
|
||||
- `GET /api/file/deleteblobrep?container=test&casefolderID=case-1&repfile=r.pdf` (missing hash) -> **400**
|
||||
- `POST /api/file/createcaseinvolvement_api` with `{}` -> **400**
|
||||
- `POST /api/file/createrepinvolvement_api` with `{}` -> **400**
|
||||
- Valid-hash happy-path spot-check:
|
||||
- `GET /api/file/deleteblobcase?container=test&casefolderID=case-1&hash=<valid>` -> **500**
|
||||
- expected due local storage/upstream dependency constraints, while confirming hash gate is no longer the failing check.
|
||||
|
||||
### Rollback plan (Phase 13)
|
||||
|
||||
1. Revert the four hardened API handlers.
|
||||
2. Remove `tests/phase13/service-behaviour.test.cjs` if full phase-13 rollback required.
|
||||
3. Re-run phase6/7/8/9/10/11/12/13 baseline tests + lint after rollback.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 14 client-hash signing fix)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Fixed authenticated user-journey runtime error during new appeal flow where client-side hashing tried to use server-only `HASHKEY`.
|
||||
- Added authenticated server-side hash signer endpoint:
|
||||
- `pages/api/endpoint/gethash_api.js`
|
||||
- requires session (`getSession`), allow-lists supported API paths, returns `{ hash }`.
|
||||
- Updated direct services to request hash from server signer for browser calls, with server-side fallback only when `HASHKEY` exists:
|
||||
- `actions/services/documentDirectService.js`
|
||||
- `actions/services/portalDirectService.js`
|
||||
- Preserved existing API contracts and response shapes in file handlers.
|
||||
- Added focused tests:
|
||||
- `tests/phase14/service-behaviour.test.cjs`
|
||||
- covers signer endpoint negative paths + authenticated happy path.
|
||||
|
||||
### Validation snapshot (Phase 14)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7)
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `npm run lint` -> **warnings only** (pre-existing hook dependency warnings)
|
||||
|
||||
### Rollback plan (Phase 14)
|
||||
|
||||
1. Revert `pages/api/endpoint/gethash_api.js`.
|
||||
2. Revert direct-service hash signer usage in `documentDirectService.js` and `portalDirectService.js`.
|
||||
3. Remove `tests/phase14/service-behaviour.test.cjs` if rolling back full phase-14 slice.
|
||||
4. Re-run phase6–phase14 tests + lint.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 14 closeout follow-up)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Completed follow-up hardening and contract-alignment after runtime verification:
|
||||
- `actions/services/accountDirectService.js`
|
||||
- `getPortalLogin` now uses authenticated signer endpoint (`/api/endpoint/gethash_api`) for browser-safe hash generation
|
||||
- retains server-only fallback to local `hashAPIPath` when `HASHKEY` is available
|
||||
- `pages/api/endpoint/gethash_api.js`
|
||||
- allow-list expanded for `/api/endpoint/getportallogin_api`
|
||||
- `pages/api/file/getrepsblob.js`
|
||||
- removed enforced `casefolderID` guard and argument pass-through to align with route contract (`/api/file/getrepsblob?container=...`)
|
||||
- `components/elements/index.js`
|
||||
- added missing `updateLinks` import from `components/utils` to resolve Quill runtime error
|
||||
- Tests updated:
|
||||
- `tests/phase7/service-behaviour.test.cjs`
|
||||
- updated `getPortalLogin` expectations for signer endpoint behavior
|
||||
- `tests/phase14/service-behaviour.test.cjs`
|
||||
- added allow-list coverage for signer path `/api/endpoint/getportallogin_api`
|
||||
|
||||
### Validation snapshot (Phase 14 follow-up)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7)
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `npm run lint` -> **warnings only** (pre-existing hook dependency warnings)
|
||||
|
||||
### Risks + mitigations (follow-up)
|
||||
|
||||
- Risk: signer endpoint over-expansion could broaden hash issuance.
|
||||
- Mitigation: strict allow-list retained; only required `getportallogin_api` path added.
|
||||
- Risk: tightened/changed guards could break existing caller contracts.
|
||||
- Mitigation: `getrepsblob` guard aligned back to actual route contract; response shape unchanged.
|
||||
- Risk: UI runtime dependency regressions during hardening verification.
|
||||
- Mitigation: missing `updateLinks` import restored with minimal diff.
|
||||
|
||||
### Rollback plan (follow-up)
|
||||
|
||||
1. Revert signer-path migration commit `6094874` (or files: `accountDirectService.js`, `gethash_api.js`, `tests/phase7`, `tests/phase14`).
|
||||
2. Revert contract/import alignment commit `b8fa514` (or files: `getrepsblob.js`, `components/elements/index.js`).
|
||||
3. Re-run phase6–phase14 tests and lint to confirm rollback parity.
|
||||
|
||||
### Rollback plan (Phase 8)
|
||||
|
||||
1. Revert the four hardened API handlers.
|
||||
2. Revert direct-service hash append changes in `documentDirectService` and `portalDirectService`.
|
||||
3. Remove `tests/phase8/service-behaviour.test.cjs` if full slice rollback required.
|
||||
4. Re-run phase6/7 baseline tests + lint after rollback.
|
||||
|
||||
## Outstanding risks / gaps
|
||||
|
||||
- Navigation regressions across EN/CY + route query combinations.
|
||||
- Drift between rewrite config and component-level locale path logic.
|
||||
- Deployment ambiguity due to multiple CI/CD artifacts (Azure pipeline, Jenkins, Docker) with unclear active source of truth.
|
||||
- Security posture variability where hash checks are bypassed/commented in selected handlers.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 7 post-Phase-6 hardening)
|
||||
|
||||
- New branch created from `origin/SIPS-Development` with required work item prefix:
|
||||
- `TASK21988a-phase7-postphase6-hardening`
|
||||
- Fixed known pre-existing SSR serialization issue on search results route:
|
||||
- `pages/searchresults.js`
|
||||
- updated SSR dispatch fallback from `setSearch(query.q)` to `setSearch(query?.q || "")`
|
||||
- result: `/searchresults` and `/cy/searchresults` now return 200 in local smoke checks (no 500 observed in this run).
|
||||
- Added expanded behavioural coverage for remaining direct-service domains:
|
||||
- new test file: `tests/phase7/service-behaviour.test.cjs`
|
||||
- includes document, portal, account, notify, integration behavioural checks
|
||||
- includes negative-path assertions for relay/hash/token-sensitive behaviors where feasible:
|
||||
- hashed URL append checks (`hashAPIPath`)
|
||||
- error handling contracts (undefined/error string/rethrow depending on existing function contract)
|
||||
|
||||
### Validation snapshot (Phase 7)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `npm run lint` -> **warnings only** (pre-existing hook dependency warnings; no new lint errors)
|
||||
|
||||
### Targeted smoke snapshot (local dev server)
|
||||
|
||||
- Note: dev server auto-started on `http://localhost:3001` because port `3000` was in use.
|
||||
- Search flow:
|
||||
- `GET /searchresults` and `GET /cy/searchresults` -> **200**
|
||||
- Case flow:
|
||||
- `GET /case` and `GET /cy/case` -> **200**
|
||||
- My Portal flow (negative-path):
|
||||
- `GET /myportal` and `GET /cy/myportal` -> **307** redirect to `/auth/signin`
|
||||
- Document flow (negative-path):
|
||||
- `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> **400**
|
||||
- Notify flow (negative-path):
|
||||
- `POST /api/email/notify` with `{}` -> **400**
|
||||
@@ -0,0 +1,747 @@
|
||||
# Refactor Plan — Priority 1 (`actions/index.js` split)
|
||||
|
||||
Last updated: 2026-03-13
|
||||
|
||||
## Handover note (2026-03-13)
|
||||
|
||||
- Import-migration wave from `actions` barrel to focused modules has been checked in and completed via PR.
|
||||
- Next chunk will be delivered from a **new branch** and should start at legacy decomposition.
|
||||
|
||||
### Next branch kickoff scope (Phase 5)
|
||||
|
||||
Primary objective: split `actions/services/legacyActionsService.js` into smaller direct implementations while preserving function signatures.
|
||||
|
||||
Recommended first slice:
|
||||
|
||||
1. Extract reference/search internals from `legacyActionsService.js` into dedicated modules.
|
||||
2. Keep `actions/services/*` exports stable and route through new direct implementations.
|
||||
3. Add focused parity checks per extracted function group (inputs, headers, hash behavior, return shapes).
|
||||
|
||||
Then continue with:
|
||||
|
||||
4. Portal/document extraction in small batches.
|
||||
5. Remove dead wrappers from `legacyActionsService.js` once call paths are fully migrated.
|
||||
|
||||
### Phase 5 slice roadmap (completed)
|
||||
|
||||
Status key: `[x] done`, `[ ] pending`
|
||||
|
||||
1. `[x]` Search + reference direct extraction
|
||||
- `searchDirectService.js`, `referenceDataDirectService.js`
|
||||
- `searchService.js` / `referenceDataService.js` re-pointed
|
||||
2. `[x]` Document direct extraction
|
||||
- create `documentDirectService.js`
|
||||
- re-point `documentService.js`
|
||||
- parity checks: blob paths/hash behavior/return shapes
|
||||
3. `[x]` Portal direct extraction
|
||||
- create `portalDirectService.js`
|
||||
- re-point `portalService.js`
|
||||
- parity checks: watched-case and completion-message flows
|
||||
4. `[x]` Account + case direct extraction
|
||||
- create `accountDirectService.js`, `caseDirectService.js`
|
||||
- re-point grouped services
|
||||
5. `[x]` Notify + integration + admin direct extraction
|
||||
- create `notifyDirectService.js`, `integrationDirectService.js`, `adminDirectService.js`
|
||||
6. `[x]` Legacy slim-down pass
|
||||
- remove dead wrappers from `legacyActionsService.js`
|
||||
- keep only temporary compatibility exports still required
|
||||
7. `[x]` Final cleanup + validation pass
|
||||
- grep checks for remaining `./legacyActionsService` imports
|
||||
- lint/manual smoke checks
|
||||
|
||||
### Phase 5 completion snapshot (2026-03-13)
|
||||
|
||||
- All grouped service modules now route through focused direct modules under `actions/services/*DirectService.js`.
|
||||
- `actions/services/legacyActionsService.js` has been removed.
|
||||
- Verification completed:
|
||||
- `actions/services` scan returns zero `./legacyActionsService` imports.
|
||||
- `npm run lint` completes with warnings only.
|
||||
- `npm run build` completes successfully.
|
||||
|
||||
### Next phase kickoff recommendation
|
||||
|
||||
Focus on post-split hardening and cleanup:
|
||||
|
||||
1. Add parity-focused tests for extracted direct services and `actions/services/index.js` export stability.
|
||||
2. Consolidate repeated axios/error-handling patterns into shared clients/utilities where safe.
|
||||
3. Reduce verbose debug logging in direct services (especially account/case/document paths) with redaction discipline.
|
||||
4. Run targeted manual smoke matrix for search/case/myportal/document/notify with EN/CY parity checks.
|
||||
|
||||
### Phase 6 completion snapshot (2026-03-13)
|
||||
|
||||
Status key: `[x] done`, `[ ] pending`
|
||||
|
||||
1. `[x]` Add parity-focused tests for extracted services and barrel stability
|
||||
- `tests/phase6/service-parity.test.cjs`
|
||||
- validates grouped/direct service export parity
|
||||
- validates `actions/services/index.js` export stability
|
||||
2. `[x]` Reduce repeated axios/error-handling patterns safely
|
||||
- added shared helper: `actions/services/httpServiceUtils.js`
|
||||
- adopted in selected direct modules without signature/return-shape changes
|
||||
3. `[x]` Logging cleanup in sensitive direct-service flows
|
||||
- removed noisy debug logs from search/document/portal/case/admin direct services
|
||||
4. `[x]` Add focused behavioural contract tests in current phase
|
||||
- `tests/phase6/service-behaviour.test.cjs`
|
||||
- success/error contract checks with mocked axios/logger (8/8 passing)
|
||||
5. `[x]` Run targeted validation/smoke checks
|
||||
- parity test: pass
|
||||
- behavioural test: pass
|
||||
- manual smoke matrix executed (search/case/myportal/document/notify, EN/CY + negative paths)
|
||||
|
||||
Notes:
|
||||
|
||||
- Known pre-existing caveat during smoke checks:
|
||||
- `/searchresults` and `/cy/searchresults` return 500 in local dev due SSR serialization issue (`initialState.search.searchString` undefined).
|
||||
- treated as existing issue, not introduced by this refactor phase.
|
||||
|
||||
### Future requirements / next-phase backlog (post-Phase-6)
|
||||
|
||||
1. Investigate and fix `/searchresults` SSR serialization issue (EN/CY parity).
|
||||
2. Expand behavioural service tests to remaining domains:
|
||||
- document
|
||||
- portal
|
||||
- account
|
||||
- notify
|
||||
- integration
|
||||
3. Add focused negative-path tests for token/hash/relay-sensitive handlers.
|
||||
4. Continue small-batch hardening with reversible commits and parity checks per batch.
|
||||
5. Prepare PR evidence bundle for each increment:
|
||||
- lint + test commands
|
||||
- behavioural/parity test outputs
|
||||
- manual EN/CY + negative-path smoke matrix
|
||||
|
||||
### Phase 7 completion snapshot (2026-03-13)
|
||||
|
||||
Status key: `[x] done`, `[ ] pending`
|
||||
|
||||
1. `[x]` Create new branch from `origin/SIPS-Development` with required work item prefix
|
||||
- branch: `TASK21988a-phase7-postphase6-hardening`
|
||||
2. `[x]` Fix pre-existing `/searchresults` SSR serialization issue with EN/CY parity
|
||||
- updated `pages/searchresults.js`:
|
||||
- `setSearch(query.q)` -> `setSearch(query?.q || "")`
|
||||
3. `[x]` Expand behavioural tests to remaining service domains
|
||||
- added `tests/phase7/service-behaviour.test.cjs`
|
||||
- coverage includes: document, portal, account, notify, integration
|
||||
4. `[x]` Add feasible negative-path tests for token/hash/relay-sensitive flows
|
||||
- validated hashed path composition (e.g., `hashAPIPath` usage)
|
||||
- validated existing function error contracts (undefined/error string/rethrow)
|
||||
5. `[x]` Execute validation bundle
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `npm run lint` -> warnings only (no new errors)
|
||||
6. `[x]` Execute targeted manual smoke matrix (EN/CY + negative paths)
|
||||
- local server on `localhost:3001` (3000 occupied)
|
||||
- `/searchresults`, `/cy/searchresults` -> 200
|
||||
- `/case`, `/cy/case` -> 200
|
||||
- `/myportal`, `/cy/myportal` -> 307 -> `/auth/signin`
|
||||
- `/api/file/getbloblistproxy?container=test&casefolderID=test` -> 400
|
||||
- `POST /api/email/notify` with `{}` -> 400
|
||||
|
||||
### Phase 7 rollback notes
|
||||
|
||||
- Revert `pages/searchresults.js` fallback change if search behaviour regresses unexpectedly.
|
||||
- Remove `tests/phase7/service-behaviour.test.cjs` if test scope needs to be rolled back.
|
||||
- Reset branch to pre-Phase-7 commit if full rollback required.
|
||||
|
||||
### Phase 8 completion snapshot (2026-03-13)
|
||||
|
||||
Status key: `[x] done`, `[ ] pending`
|
||||
|
||||
1. `[x]` Create new branch from `origin/SIPS-Development` with required work item prefix
|
||||
- branch: `TASK22017-phase8-hardening-slice`
|
||||
2. `[x]` Re-enable/enforce hash validation in 4 sensitive target handlers
|
||||
- `pages/api/file/deleteblobcase.js`
|
||||
- `pages/api/file/deleteblobrep.js`
|
||||
- `pages/api/file/createappealcompletemessage_api.js`
|
||||
- `pages/api/endpoint/getportallogin_api.js`
|
||||
3. `[x]` Standardize negative-path behavior for invalid/missing hash and required keys
|
||||
- added early 400 guards for missing required query params where applicable
|
||||
- preserved response-shape contracts/signatures
|
||||
4. `[x]` Improve logging discipline in sensitive flow
|
||||
- removed noisy direct console output in `createappealcompletemessage_api`
|
||||
- routed updated error path logging via `consoleLogger`
|
||||
5. `[x]` Keep caller behavior compatible after hash re-enforcement
|
||||
- `actions/services/documentDirectService.js` now appends hash for:
|
||||
- `deleteblobcase`
|
||||
- `deleteblobrep`
|
||||
- `actions/services/portalDirectService.js` now appends hash for:
|
||||
- `createappealcompletemessage_api` (existing hash-path contract retained)
|
||||
6. `[x]` Add focused Phase 8 tests
|
||||
- added `tests/phase8/service-behaviour.test.cjs`
|
||||
- includes negative-path coverage for all 4 target handlers
|
||||
- includes one valid-hash happy-path contract check (`getportallogin_api`) via mocks
|
||||
7. `[x]` Execute validation bundle
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (pre-existing react-hooks dependency warnings)
|
||||
8. `[x]` Execute manual HTTP negative-path matrix + feasible happy-path spot-check
|
||||
- invalid/missing hash across 4 target handlers -> 400
|
||||
- missing required params where tested -> 400
|
||||
- valid-hash `getportallogin_api` spot-check returned 400 in local env due upstream relay/CRM dependency
|
||||
|
||||
### Phase 8 rollback notes
|
||||
|
||||
- Revert these files to rollback the full hardening slice:
|
||||
- `pages/api/file/deleteblobcase.js`
|
||||
- `pages/api/file/deleteblobrep.js`
|
||||
- `pages/api/file/createappealcompletemessage_api.js`
|
||||
- `pages/api/endpoint/getportallogin_api.js`
|
||||
- `actions/services/documentDirectService.js`
|
||||
- `actions/services/portalDirectService.js`
|
||||
- `tests/phase8/service-behaviour.test.cjs`
|
||||
- Re-run phase6/phase7 baseline tests and lint after rollback to confirm parity.
|
||||
|
||||
### Phase 9 completion snapshot (2026-03-13)
|
||||
|
||||
Status key: `[x] done`, `[ ] pending`
|
||||
|
||||
1. `[x]` Create new branch from `origin/SIPS-Development` with required work item prefix
|
||||
- branch: `TASK22019-phase-9-hardening`
|
||||
2. `[x]` Re-enable/enforce hash validation in 4 additional sensitive file handlers
|
||||
- `pages/api/file/createrepcompletemessage_api.js`
|
||||
- `pages/api/file/upload.js`
|
||||
- `pages/api/file/uploadsinglefile.js`
|
||||
- `pages/api/file/setupcontainer.js`
|
||||
3. `[x]` Standardize negative-path behavior for invalid/missing hash and key params
|
||||
- added early 400 handling for missing required query/body values where applicable
|
||||
4. `[x]` Improve logging discipline in sensitive paths
|
||||
- removed noisy direct console logging in touched handlers
|
||||
5. `[x]` Keep caller behavior compatible after hash re-enforcement
|
||||
- `actions/services/portalDirectService.js`
|
||||
- `sendRepCompleteMessage` now appends hash
|
||||
- `actions/services/documentDirectService.js`
|
||||
- upload-related calls now append hash
|
||||
6. `[x]` Add focused Phase 9 tests
|
||||
- added `tests/phase9/service-behaviour.test.cjs`
|
||||
- negative-path tests for all 4 selected handlers
|
||||
7. `[x]` Execute validation bundle
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (no new lint errors)
|
||||
8. `[x]` Execute manual HTTP negative-path matrix
|
||||
- missing/invalid hash checks across selected handlers -> 400
|
||||
- missing key params where tested -> 400
|
||||
9. `[x]` Valid-hash HTTP happy-path spot-check
|
||||
- `POST /api/file/uploadsinglefile?hash=<valid>` -> 200 (hash generated from `.env.local` key)
|
||||
|
||||
### Phase 9 rollback notes
|
||||
|
||||
- Revert these files to rollback the full hardening slice:
|
||||
- `pages/api/file/createrepcompletemessage_api.js`
|
||||
- `pages/api/file/upload.js`
|
||||
- `pages/api/file/uploadsinglefile.js`
|
||||
- `pages/api/file/setupcontainer.js`
|
||||
- `actions/services/portalDirectService.js`
|
||||
- `actions/services/documentDirectService.js`
|
||||
- `tests/phase9/service-behaviour.test.cjs`
|
||||
- Re-run phase6/phase7/phase8/phase9 baseline tests and lint after rollback to confirm parity.
|
||||
|
||||
### Phase 10 completion snapshot (2026-03-13)
|
||||
|
||||
Status key: `[x] done`, `[ ] pending`
|
||||
|
||||
1. `[x]` Continue connected hardening slices on same branch
|
||||
- branch: `TASK22019-phase-9-hardening`
|
||||
2. `[x]` Re-enable/standardize hash + param guard handling in 4 additional file retrieval handlers
|
||||
- `pages/api/file/getawaitingsubmissionfromblob.js`
|
||||
- `pages/api/file/getprogressobjblob.js`
|
||||
- `pages/api/file/getbloblist.js`
|
||||
- `pages/api/file/getrepsblob.js`
|
||||
3. `[x]` Standardize negative-path behavior
|
||||
- added explicit early 400 for missing required query/hash values
|
||||
- standardized early 400 for hash mismatch
|
||||
4. `[x]` Improve logging discipline in touched handlers
|
||||
- removed old commented debug traces
|
||||
5. `[x]` Add focused Phase 10 tests
|
||||
- added `tests/phase10/service-behaviour.test.cjs`
|
||||
- includes negative-path tests for all 4 handlers
|
||||
6. `[x]` Execute validation bundle
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (no new lint errors)
|
||||
7. `[x]` Execute manual HTTP negative-path matrix + valid-hash spot-check
|
||||
- missing hash across selected handlers -> 400
|
||||
- valid hash `getbloblist` spot-check -> 500 (downstream/local dependency)
|
||||
|
||||
### Phase 10 rollback notes
|
||||
|
||||
- Revert these files to rollback the full hardening slice:
|
||||
- `pages/api/file/getawaitingsubmissionfromblob.js`
|
||||
- `pages/api/file/getprogressobjblob.js`
|
||||
- `pages/api/file/getbloblist.js`
|
||||
- `pages/api/file/getrepsblob.js`
|
||||
- `tests/phase10/service-behaviour.test.cjs`
|
||||
- Re-run phase6/phase7/phase8/phase9/phase10 baseline tests and lint after rollback to confirm parity.
|
||||
|
||||
### Phase 11 completion snapshot (2026-03-13)
|
||||
|
||||
Status key: `[x] done`, `[ ] pending`
|
||||
|
||||
1. `[x]` Continue connected hardening slices on same branch
|
||||
- branch: `TASK22019-phase-9-hardening`
|
||||
2. `[x]` Re-enable/standardize hash + param guard handling in additional sensitive handlers
|
||||
- `pages/api/file/getbloblist.js`
|
||||
- `pages/api/file/deleteblob.js`
|
||||
- `pages/api/file/deleteawaitingsubmissionfromblob.js`
|
||||
3. `[x]` Standardize negative-path behavior
|
||||
- added explicit early 400 for missing required query/hash values
|
||||
- standardized early 400 for hash mismatch
|
||||
4. `[x]` Improve logging discipline in touched handlers
|
||||
- removed old commented debug traces
|
||||
5. `[x]` Add focused Phase 11 tests
|
||||
- added `tests/phase11/service-behaviour.test.cjs`
|
||||
- includes negative-path tests for selected handlers
|
||||
6. `[x]` Execute validation bundle
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `npm run lint` -> warnings only (no new lint errors)
|
||||
7. `[x]` Execute manual HTTP negative-path matrix + valid-hash spot-check
|
||||
- missing/invalid hash across selected handlers -> 400
|
||||
- valid hash `getbloblist` spot-check -> 500 (downstream/local dependency)
|
||||
|
||||
### Phase 11 rollback notes
|
||||
|
||||
- Revert these files to rollback the full hardening slice:
|
||||
- `pages/api/file/getbloblist.js`
|
||||
- `pages/api/file/deleteblob.js`
|
||||
- `pages/api/file/deleteawaitingsubmissionfromblob.js`
|
||||
- `tests/phase11/service-behaviour.test.cjs`
|
||||
- Re-run phase6/phase7/phase8/phase9/phase10/phase11 baseline tests and lint after rollback to confirm parity.
|
||||
|
||||
### Phase 12 completion snapshot (2026-03-13)
|
||||
|
||||
Status key: `[x] done`, `[ ] pending`
|
||||
|
||||
1. `[x]` Continue connected hardening slices on same branch
|
||||
- branch: `TASK22019-phase-9-hardening`
|
||||
2. `[x]` Re-enable/standardize hash + param guard handling in additional sensitive handlers
|
||||
- `pages/api/file/downloadblob.js`
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
3. `[x]` Standardize negative-path behavior
|
||||
- added explicit early 400 for missing required query/hash values
|
||||
- standardized early 400 for hash mismatch in `downloadblob`
|
||||
4. `[x]` Add focused Phase 12 tests
|
||||
- added `tests/phase12/service-behaviour.test.cjs`
|
||||
- includes negative-path tests for selected handlers
|
||||
5. `[x]` Execute validation bundle
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `npm run lint` -> warnings only (no new lint errors)
|
||||
6. `[x]` Execute manual HTTP negative-path matrix + valid-hash spot-check
|
||||
- missing/invalid inputs across selected handlers -> 400
|
||||
- valid hash `downloadblob` spot-check -> 500 (downstream/local dependency)
|
||||
|
||||
### Phase 12 rollback notes
|
||||
|
||||
- Revert these files to rollback the full hardening slice:
|
||||
- `pages/api/file/downloadblob.js`
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
- `tests/phase12/service-behaviour.test.cjs`
|
||||
- Re-run phase6/phase7/phase8/phase9/phase10/phase11/phase12 baseline tests and lint after rollback to confirm parity.
|
||||
|
||||
### Phase 13 completion snapshot (2026-03-13)
|
||||
|
||||
Status key: `[x] done`, `[ ] pending`
|
||||
|
||||
1. `[x]` Continue connected hardening slices on same branch
|
||||
- branch: `TASK22019-phase-9-hardening`
|
||||
2. `[x]` Re-enable/standardize hash + param guard handling in additional sensitive handlers
|
||||
- `pages/api/file/deleteblobcase.js`
|
||||
- `pages/api/file/deleteblobrep.js`
|
||||
- `pages/api/file/createcaseinvolvement_api.js`
|
||||
- `pages/api/file/createrepinvolvement_api.js`
|
||||
3. `[x]` Standardize negative-path behavior
|
||||
- added explicit early 400 for missing required query/hash/body values
|
||||
- standardized early 400 for hash mismatch in delete handlers
|
||||
4. `[x]` Improve logging discipline in touched handlers
|
||||
- removed noisy body/query logging in involvement handlers
|
||||
5. `[x]` Add focused Phase 13 tests
|
||||
- added `tests/phase13/service-behaviour.test.cjs`
|
||||
- includes negative-path tests and valid-input mocked happy paths
|
||||
6. `[x]` Execute validation bundle
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7)
|
||||
- `npm run lint` -> warnings only (no new lint errors)
|
||||
7. `[x]` Execute manual HTTP negative-path matrix + valid-hash spot-check
|
||||
- missing/invalid inputs across selected handlers -> 400
|
||||
- valid hash `deleteblobcase` spot-check -> 500 (downstream/local dependency)
|
||||
|
||||
### Phase 13 rollback notes
|
||||
|
||||
- Revert these files to rollback the full hardening slice:
|
||||
- `pages/api/file/deleteblobcase.js`
|
||||
- `pages/api/file/deleteblobrep.js`
|
||||
- `pages/api/file/createcaseinvolvement_api.js`
|
||||
- `pages/api/file/createrepinvolvement_api.js`
|
||||
- `tests/phase13/service-behaviour.test.cjs`
|
||||
- Re-run phase6/phase7/phase8/phase9/phase10/phase11/phase12/phase13 baseline tests and lint after rollback to confirm parity.
|
||||
|
||||
### Phase 14 completion snapshot (2026-03-13)
|
||||
|
||||
Status key: `[x] done`, `[ ] pending`
|
||||
|
||||
1. `[x]` Diagnose authenticated browser journey runtime error
|
||||
- traced to client-side `hashAPIPath` usage reading server-only `HASHKEY`
|
||||
2. `[x]` Implement minimal reversible signing bridge
|
||||
- added `pages/api/endpoint/gethash_api.js`
|
||||
- session-gated with allow-listed API path prefixes
|
||||
3. `[x]` Keep client/service contracts stable
|
||||
- updated `documentDirectService` and `portalDirectService` to request hash from signer endpoint
|
||||
- kept server-side fallback hashing only when env key exists
|
||||
4. `[x]` Add focused phase-14 tests
|
||||
- added `tests/phase14/service-behaviour.test.cjs`
|
||||
- covers 400/401 negative paths and authenticated happy path
|
||||
5. `[x]` Execute validation bundle
|
||||
- phase6–phase14 test set all pass
|
||||
- lint warnings only (pre-existing)
|
||||
|
||||
### Phase 14 rollback notes
|
||||
|
||||
- Revert these files to rollback the fix slice:
|
||||
- `pages/api/endpoint/gethash_api.js`
|
||||
- `actions/services/documentDirectService.js`
|
||||
- `actions/services/portalDirectService.js`
|
||||
- `tests/phase14/service-behaviour.test.cjs`
|
||||
- Re-run phase6–phase14 tests + lint after rollback.
|
||||
|
||||
### Phase 14 closeout follow-up snapshot (2026-03-13)
|
||||
|
||||
Status key: `[x] done`, `[ ] pending`
|
||||
|
||||
1. `[x]` Expand signer usage to remaining browser-sensitive hashed call in account domain
|
||||
- `actions/services/accountDirectService.js`
|
||||
- `getPortalLogin` now requests hash from authenticated signer endpoint
|
||||
2. `[x]` Extend signer allow-list minimally for required route
|
||||
- `pages/api/endpoint/gethash_api.js`
|
||||
- added `/api/endpoint/getportallogin_api` only
|
||||
3. `[x]` Preserve and verify behavioural contract coverage
|
||||
- `tests/phase7/service-behaviour.test.cjs` updated for signer flow
|
||||
- `tests/phase14/service-behaviour.test.cjs` extended with allow-list path test
|
||||
4. `[x]` Apply runtime-discovered contract alignment fixes (minimal/reversible)
|
||||
- `pages/api/file/getrepsblob.js`
|
||||
- removed unnecessary `casefolderID` requirement to match endpoint contract
|
||||
- `components/elements/index.js`
|
||||
- restored missing `updateLinks` import for Quill path
|
||||
5. `[x]` Re-run required validation
|
||||
- phase6 parity + behaviour -> pass
|
||||
- phase7/8/9/10/11/12/13/14 behaviour -> pass
|
||||
- lint -> warnings only (pre-existing)
|
||||
6. `[x]` Push branch for review continuity
|
||||
- `TASK22019-phase-9-hardening` pushed to origin
|
||||
|
||||
### Phase 14 closeout follow-up rollback notes
|
||||
|
||||
- Revert `6094874` to remove portal-login signer migration and tests.
|
||||
- Revert `b8fa514` to remove getrepsblob contract-alignment + Quill import fix.
|
||||
- Re-run phase6–phase14 tests and lint after rollback.
|
||||
|
||||
## Safe execution mode for migration chunks (required)
|
||||
|
||||
To reduce terminal hangs during bulk migration work, run refactor chunks in **safe stepwise mode** instead of long chained commands.
|
||||
|
||||
Required command pattern:
|
||||
|
||||
1. Read/inspect target files.
|
||||
2. Apply edits only.
|
||||
3. Verify with targeted grep for remaining broad imports.
|
||||
4. Check `git status`.
|
||||
5. Stage files.
|
||||
6. Commit.
|
||||
7. Re-run verification and then continue to the next chunk.
|
||||
|
||||
Rules:
|
||||
|
||||
- Do **not** combine edit + verify + add + commit + log in one long chained command.
|
||||
- Keep each terminal call short and single-purpose.
|
||||
- If a command is interrupted, re-check `git status` and resume from the next incomplete step.
|
||||
- Preserve smallest viable diff and behavior parity.
|
||||
|
||||
## Implementation status snapshot (2026-03-12)
|
||||
|
||||
- Phase 1 completed:
|
||||
- Extracted core helpers into `actions/core/{env,logger,hash,token,headers}.js`.
|
||||
- Moved wrapper functions into `actions/services/legacyActionsService.js`.
|
||||
- Reduced `actions/index.js` to compatibility barrel re-exports.
|
||||
- Added `actions/clients/README.md` scaffold for upcoming client extraction.
|
||||
- Validation status:
|
||||
- `npm run lint` currently fails at framework/tooling option level (legacy ESLint options), not due to this refactor logic.
|
||||
- Manual test matrix is required next (search/case/myportal/auth/notify/file).
|
||||
|
||||
## Implementation status snapshot (Phase 2 update — 2026-03-12)
|
||||
|
||||
- Phase 2 completed:
|
||||
- Added grouped service modules under `actions/services/`:
|
||||
- `searchService.js`
|
||||
- `caseService.js`
|
||||
- `accountService.js`
|
||||
- `portalService.js`
|
||||
- `documentService.js`
|
||||
- `referenceDataService.js`
|
||||
- `notifyService.js`
|
||||
- `adminService.js`
|
||||
- `integrationService.js`
|
||||
- Added `actions/services/index.js` barrel.
|
||||
- Updated `actions/index.js` to export from `./services` and `./core/*`.
|
||||
- Verified export parity: all `legacyActionsService` exports are represented by grouped service modules.
|
||||
- Current compatibility model:
|
||||
- Consumers can continue importing from `../actions` with unchanged function names/signatures.
|
||||
- `legacyActionsService` remains an internal compatibility implementation module until Phase 3 consumer migration.
|
||||
|
||||
## Implementation status snapshot (Phase 3 update — 2026-03-12)
|
||||
|
||||
- Phase 3 started with targeted consumer migration to focused imports.
|
||||
- Updated high-churn consumers:
|
||||
- `components/case/summary.js`
|
||||
- `createWatchedCases`, `deleteWatchedCases`, `getWatchedCasesProxy`, `setCaseInvolvment` -> `actions/services/portalService`
|
||||
- `getLinkedCases` -> `actions/services/searchService`
|
||||
- `getPortalModuleDetailsProxy` -> `actions/services/caseService`
|
||||
- `pages/api/email/notify.js`
|
||||
- `consoleLogger` -> `actions/core/logger`
|
||||
- `getPreferredLanguage` -> `actions/services/accountService`
|
||||
- Updated selected endpoint handlers to core imports:
|
||||
- `pages/api/endpoint/getwatchedcases_api.js`
|
||||
- `pages/api/endpoint/getadvancedsearchpaged_api.js`
|
||||
- `pages/api/endpoint/getpreferredlanguage_api.js`
|
||||
- `pages/api/endpoint/createcrmtask_api.js`
|
||||
- Compatibility remains preserved via `actions/index.js` barrel while migration proceeds incrementally.
|
||||
|
||||
## Implementation status snapshot (Phase 4 update — 2026-03-12)
|
||||
|
||||
- Phase 4 started with targeted hardening helpers and sensitive-path adoption.
|
||||
- Added `actions/core/guards.js` with:
|
||||
- `isNonEmptyString`
|
||||
- `sanitizeString`
|
||||
- `escapeODataString`
|
||||
- Expanded `actions/core/logger.js` with redaction support:
|
||||
- `redactSensitive`
|
||||
- masking for likely email/token/secret patterns in logged content
|
||||
- Updated `actions/index.js` compatibility barrel to export `./core/guards`.
|
||||
- Applied hardening in selected sensitive/high-churn handlers:
|
||||
- `pages/api/email/notify.js`
|
||||
- email input sanitization + required-field guard
|
||||
- redacted logging for outbound payload diagnostics
|
||||
- `pages/api/endpoint/getpreferredlanguage_api.js`
|
||||
- sanitized/validated `emailAddress`
|
||||
- OData string escaping for query construction
|
||||
- redacted query logging
|
||||
- `pages/api/endpoint/createcrmtask_api.js`
|
||||
- sanitized/validated request inputs for subject/email/body
|
||||
- centralized structured error logging via `consoleLogger`
|
||||
|
||||
## Implementation status snapshot (Priority 1 execution pass — 2026-03-12)
|
||||
|
||||
- Completed another targeted consumer migration pass from broad `actions` barrel imports to focused service/core imports in these files:
|
||||
- `components/admin/tabs/documents.js`
|
||||
- `components/admin/tabs/storage.js`
|
||||
- `components/admin/utils/serverside.js`
|
||||
- `components/case/documents.js`
|
||||
- `components/case/representation/representationComplete.js`
|
||||
- `components/case/representation/representationElements.js`
|
||||
- `components/elements/index.js`
|
||||
- `components/myportal/awaitingsubmissionfromblob.js`
|
||||
- `components/myportal/topthree.js`
|
||||
- `components/myportal/topthree_reps.js`
|
||||
- `components/utils/index.js`
|
||||
- `lib/myportal/loadMyPortalAppealPage.js`
|
||||
- `lib/newappeal/loadNewAppealPage.js`
|
||||
- Kept compatibility behavior via existing `actions/index.js` barrel.
|
||||
- Validation note: `npm run lint` remains blocked by repository ESLint/Next option incompatibility (pre-existing tooling configuration).
|
||||
|
||||
## Goal
|
||||
|
||||
Reduce coupling and regression risk by splitting `actions/index.js` into focused modules while preserving existing behavior and call signatures during migration.
|
||||
|
||||
## Why this is first
|
||||
|
||||
`actions/index.js` is currently a high-risk hotspot: API wrappers, relay/hash helpers, token acquisition, logging, file helpers, and notification helpers are mixed in one module. This increases blast radius for every change.
|
||||
|
||||
## Scope (planned)
|
||||
|
||||
- In scope:
|
||||
- Module extraction and internal architecture cleanup.
|
||||
- Backward-compatible export strategy.
|
||||
- Migration plan for consumers under `components/**`, `pages/**`, and `pages/api/**`.
|
||||
- Out of scope (for this refactor phase):
|
||||
- Functional changes to business logic.
|
||||
- Contract changes to API handlers.
|
||||
- Dependency swaps.
|
||||
|
||||
## Proposed target structure
|
||||
|
||||
```text
|
||||
actions/
|
||||
index.js # compatibility barrel (temporary)
|
||||
core/
|
||||
env.js # BASE_URL/API_ROOT/relay roots
|
||||
logger.js # consoleLogger/conLog with redaction helpers
|
||||
hash.js # hashAPIPath/hashString/dehashString
|
||||
token.js # getToken + token request config
|
||||
headers.js # azureHeaders* helpers
|
||||
clients/
|
||||
relayClient.js # signed relay calls + shared axios behavior
|
||||
endpointClient.js # endpoint route wrappers
|
||||
fileClient.js # file route wrappers
|
||||
notifyClient.js # email/notify wrappers
|
||||
services/
|
||||
caseService.js
|
||||
searchService.js
|
||||
portalService.js
|
||||
accountService.js
|
||||
documentService.js
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Keep `actions/index.js` as a façade initially to avoid breaking imports.
|
||||
- Move internals first, then update call sites incrementally.
|
||||
|
||||
## Migration strategy (phased)
|
||||
|
||||
### Phase 1 — Safe extraction with no consumer changes
|
||||
|
||||
1. Create new modules under `actions/core/**` and `actions/clients/**`.
|
||||
2. Move utility functions (`hash`, `headers`, `token`, `logger`, env helpers).
|
||||
3. Re-export all existing functions from `actions/index.js` unchanged.
|
||||
4. Verify parity with lint + smoke checks.
|
||||
|
||||
### Phase 2 — Service grouping
|
||||
|
||||
1. Group route wrapper functions into service modules by domain (case/search/portal/account/document).
|
||||
2. Keep identical function names/signatures.
|
||||
3. Add thin unit tests for pure helpers first (`hash`, `env`, route builder helpers).
|
||||
|
||||
### Phase 3 — Consumer migration
|
||||
|
||||
1. Replace broad imports from `actions/index.js` with targeted imports from new modules.
|
||||
2. Migrate high-churn areas first:
|
||||
- `components/breadcrumbs.js`
|
||||
- `components/case/summary.js`
|
||||
- `pages/api/email/notify.js`
|
||||
- selected `pages/api/endpoint/**` handlers
|
||||
3. Keep index barrel until migration completion.
|
||||
|
||||
### Phase 4 — Harden + slim
|
||||
|
||||
1. Introduce typed/validated request helper boundaries (JS doc + runtime guard checks).
|
||||
2. Remove dead exports and duplicate wrappers.
|
||||
3. Finalize redacted logging policy in sensitive flows.
|
||||
|
||||
## Backward compatibility rules
|
||||
|
||||
- Do not change public function names/signatures during Phases 1–2.
|
||||
- Keep return shapes identical unless explicitly planned and validated.
|
||||
- Preserve existing hash and relay behavior contract.
|
||||
- Preserve EN/CY behavior where helper functions influence locale-sensitive flows.
|
||||
|
||||
## Validation plan
|
||||
|
||||
- `npm run lint`
|
||||
- Manual smoke paths:
|
||||
- search -> results -> case summary -> back nav
|
||||
- myportal viewall -> case summary -> breadcrumb return path
|
||||
- auth email sign-in flow
|
||||
- notify new case reference language selection path
|
||||
- file/document fetch paths touched by moved wrappers
|
||||
- Negative-path checks:
|
||||
- invalid hash or malformed query for sensitive handlers
|
||||
- token acquisition failures and relay timeout handling
|
||||
|
||||
## Regression tests and coverage plan (to add during implementation)
|
||||
|
||||
### Test tooling recommendation
|
||||
|
||||
Current repo has no active automated test runner configured in `package.json`. For this refactor, introduce a minimal unit test setup (recommended: Jest) focused on pure logic first.
|
||||
|
||||
Suggested scripts:
|
||||
|
||||
- `test`: run all unit tests
|
||||
- `test:watch`: local watch mode
|
||||
- `test:coverage`: coverage output for CI and PR evidence
|
||||
|
||||
### Minimum tests for Priority 1
|
||||
|
||||
1. `actions/core/hash.js`
|
||||
- deterministic hash for known input
|
||||
- query string handling (`?hash=` vs `&hash=`)
|
||||
- malformed/edge inputs
|
||||
2. `actions/core/headers.js`
|
||||
- expected OData/auth headers produced for each helper
|
||||
3. `actions/core/token.js`
|
||||
- token request config generation
|
||||
- success and error mapping behavior (mock axios)
|
||||
4. `actions/core/env.js`
|
||||
- server vs browser base URL resolution
|
||||
5. compatibility barrel (`actions/index.js`)
|
||||
- exports parity test to ensure existing function names remain available during migration
|
||||
|
||||
### Integration-style safeguards (mocked external calls)
|
||||
|
||||
- Relay client request assembly test:
|
||||
- signed URL includes hash
|
||||
- token is attached
|
||||
- timeout/error behavior is consistent
|
||||
- Notify client wrapper test:
|
||||
- language/template routing remains unchanged for PEDW-NEW-CASEREF path
|
||||
|
||||
### Coverage targets for this refactor
|
||||
|
||||
- `actions/core/**`: >= 90% lines/functions
|
||||
- `actions/clients/**`: >= 80% lines/functions
|
||||
- Global coverage gate for this phase: >= 70% (new tests only; avoid blocking unrelated legacy code)
|
||||
|
||||
### Regression gate in PR
|
||||
|
||||
Required evidence for each phase:
|
||||
|
||||
1. `npm run lint`
|
||||
2. `npm run test`
|
||||
3. `npm run test:coverage` (attach summary)
|
||||
4. Manual smoke matrix from this plan (search/case/myportal/auth/notify/file)
|
||||
|
||||
## Risks and mitigations
|
||||
|
||||
- Risk: import breakage due to broad existing usage.
|
||||
- Mitigation: keep compatibility barrel and migrate in small batches.
|
||||
- Risk: hidden behavior differences from refactor-only moves.
|
||||
- Mitigation: freeze signatures + add helper tests + run route smoke matrix each phase.
|
||||
- Risk: sensitive logging leakage while touching shared helpers.
|
||||
- Mitigation: centralize logger early and enforce redaction helper.
|
||||
|
||||
## Definition of done (for this priority)
|
||||
|
||||
1. `actions/index.js` reduced to compatibility exports only (minimal logic).
|
||||
2. Core helper modules and service modules exist and are used by migrated consumers.
|
||||
3. Lint and manual validation matrix pass.
|
||||
4. Memory docs updated (`activeContext`, `progress`, `change-log`).
|
||||
@@ -0,0 +1,36 @@
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import nextConnect from "next-connect";
|
||||
import { getSession } from "next-auth/react";
|
||||
|
||||
const ApiProxy = nextConnect();
|
||||
|
||||
ApiProxy.get(async (req, res) => {
|
||||
const session = await getSession({ req });
|
||||
|
||||
if (!session) {
|
||||
return res.status(401).json();
|
||||
}
|
||||
|
||||
const queryPath = req.query.path;
|
||||
const allowedPrefix = [
|
||||
"/api/endpoint/getportallogin_api",
|
||||
"/api/file/upload",
|
||||
"/api/file/uploadsinglefile",
|
||||
"/api/file/createrepcompletemessage_api",
|
||||
"/api/file/createappealcompletemessage_api"
|
||||
];
|
||||
|
||||
if (
|
||||
typeof queryPath !== "string" ||
|
||||
queryPath.length === 0 ||
|
||||
!queryPath.startsWith("/api/") ||
|
||||
!allowedPrefix.some((prefix) => queryPath.startsWith(prefix)) ||
|
||||
queryPath.includes("/api/endpoint/gethash_api")
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
return res.status(200).json({ hash: hashAPIPath(queryPath) });
|
||||
});
|
||||
|
||||
export default ApiProxy;
|
||||
@@ -34,6 +34,16 @@ const hashAPIPath = (queryPath) => {
|
||||
};
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
if (
|
||||
!req.body ||
|
||||
typeof req.body.contactid === "undefined" ||
|
||||
req.body.contactid.length === 0 ||
|
||||
typeof req.body.incidentid === "undefined" ||
|
||||
req.body.incidentid.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
var token = await getToken();
|
||||
var contactid = req.body.contactid;
|
||||
var queryUrl =
|
||||
@@ -41,8 +51,6 @@ export default async function ApiProxy(req, res) {
|
||||
req.body.incidentid +
|
||||
")/pinswg_incident_contact_case_involvement/$ref";
|
||||
|
||||
console.log(req.body, queryUrl);
|
||||
|
||||
var crmUrl = "https://" + process.env.CRMURL;
|
||||
|
||||
var data = {
|
||||
|
||||
@@ -2,6 +2,8 @@ import {
|
||||
getBlobs,
|
||||
createRepCompleteMessage
|
||||
} from "../../../actions/azurestorage";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
|
||||
import nextConnect from "next-connect";
|
||||
import middleware from "../middleware/middleware";
|
||||
@@ -13,26 +15,41 @@ ApiProxy.get(async (req, res) => {
|
||||
var containerName = req.query.container;
|
||||
var tempCaseRef = req.query.tempcaseref;
|
||||
var filename = req.query.repid;
|
||||
var checkHash = req.query.hash;
|
||||
|
||||
//console.log(hashAPIPath(checkquerypath), checkHash);
|
||||
//console.log(hashAPIPath(checkquerypath) == "&hash=" + checkHash);
|
||||
if (
|
||||
typeof containerName === "undefined" ||
|
||||
containerName.length === 0 ||
|
||||
typeof tempCaseRef === "undefined" ||
|
||||
tempCaseRef.length === 0 ||
|
||||
typeof filename === "undefined" ||
|
||||
filename.length === 0 ||
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
//if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
|
||||
await createRepCompleteMessage(containerName, tempCaseRef, filename).then(
|
||||
(data) => {
|
||||
console.log(
|
||||
"/////Create Rep complete Message:\n" + tempCaseRef,
|
||||
"\n" + "insertedOn:" + data.insertedOn,
|
||||
"\n" + "messageId:" + data.messageId,
|
||||
"\n" + "response.status:" + data._response.status,
|
||||
"\n//////////////"
|
||||
);
|
||||
var checkquerypath =
|
||||
"/api/file/createrepcompletemessage_api?container=" +
|
||||
containerName +
|
||||
"&tempcaseref=" +
|
||||
tempCaseRef +
|
||||
"&repid=" +
|
||||
filename;
|
||||
|
||||
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
await createRepCompleteMessage(containerName, tempCaseRef, filename)
|
||||
.then((data) => {
|
||||
return res.status(200).json(data);
|
||||
}
|
||||
);
|
||||
// } else {
|
||||
// return res.status(400).json();
|
||||
// }
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
return res.status(400).json();
|
||||
});
|
||||
});
|
||||
|
||||
export const config = {
|
||||
|
||||
@@ -34,6 +34,16 @@ const hashAPIPath = (queryPath) => {
|
||||
};
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
if (
|
||||
!req.body ||
|
||||
typeof req.body.contactid === "undefined" ||
|
||||
req.body.contactid.length === 0 ||
|
||||
typeof req.body.incidentid === "undefined" ||
|
||||
req.body.incidentid.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
var token = await getToken();
|
||||
var contactid = req.body.contactid;
|
||||
var queryUrl =
|
||||
@@ -41,8 +51,6 @@ export default async function ApiProxy(req, res) {
|
||||
req.body.incidentid +
|
||||
")/pinswg_incident_contact_case_involvement/$ref";
|
||||
|
||||
console.log(req.body, queryUrl);
|
||||
|
||||
var crmUrl = "https://" + process.env.CRMURL;
|
||||
var crmVersion = process.env.CRMURL_VERSION;
|
||||
|
||||
|
||||
@@ -13,6 +13,19 @@ ApiProxy.get(async (req, res) => {
|
||||
var blobName = req.query.blobname;
|
||||
var checkHash = req.query.hash;
|
||||
|
||||
if (
|
||||
typeof containerName === "undefined" ||
|
||||
containerName.length === 0 ||
|
||||
typeof casefolderID === "undefined" ||
|
||||
casefolderID.length === 0 ||
|
||||
typeof blobName === "undefined" ||
|
||||
blobName.length === 0 ||
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
var checkquerypath =
|
||||
"/api/file/deleteblob?container=" +
|
||||
containerName +
|
||||
@@ -21,8 +34,9 @@ ApiProxy.get(async (req, res) => {
|
||||
"&blobname=" +
|
||||
blobName;
|
||||
|
||||
//console.log(hashAPIPath(checkquerypath), checkHash);
|
||||
//console.log(hashAPIPath(checkquerypath) == "&hash=" + checkHash);
|
||||
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
|
||||
await deleteBlob(
|
||||
@@ -31,8 +45,6 @@ ApiProxy.get(async (req, res) => {
|
||||
).then((data) => {
|
||||
return res.status(200).json({ data: data });
|
||||
});
|
||||
} else {
|
||||
return res.status(400).json();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -13,6 +13,19 @@ ApiProxy.get(async (req, res) => {
|
||||
var blobName = req.query.blobname;
|
||||
var checkHash = req.query.hash;
|
||||
|
||||
if (
|
||||
typeof containerName === "undefined" ||
|
||||
containerName.length === 0 ||
|
||||
typeof casefolderID === "undefined" ||
|
||||
casefolderID.length === 0 ||
|
||||
typeof blobName === "undefined" ||
|
||||
blobName.length === 0 ||
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
var checkquerypath =
|
||||
"/api/file/deleteblob?container=" +
|
||||
containerName +
|
||||
@@ -21,6 +34,10 @@ ApiProxy.get(async (req, res) => {
|
||||
"&blobname=" +
|
||||
encodeURIComponent(blobName);
|
||||
|
||||
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
|
||||
await deleteBlob(
|
||||
containerName,
|
||||
@@ -28,8 +45,6 @@ ApiProxy.get(async (req, res) => {
|
||||
).then((data) => {
|
||||
return res.status(200).json({ data: data });
|
||||
});
|
||||
} else {
|
||||
return res.status(400).json();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -16,7 +16,9 @@ ApiProxy.get(async (req, res) => {
|
||||
typeof containerName === "undefined" ||
|
||||
containerName.length === 0 ||
|
||||
typeof casefolderID === "undefined" ||
|
||||
casefolderID.length === 0
|
||||
casefolderID.length === 0 ||
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
@@ -27,12 +29,14 @@ ApiProxy.get(async (req, res) => {
|
||||
"&casefolderID=" +
|
||||
casefolderID;
|
||||
|
||||
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
|
||||
await deleteBlobCase(containerName, casefolderID).then((data) => {
|
||||
return res.status(200).json({ data: data });
|
||||
});
|
||||
} else {
|
||||
return res.status(400).json();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ ApiProxy.get(async (req, res) => {
|
||||
typeof casefolderID === "undefined" ||
|
||||
casefolderID.length === 0 ||
|
||||
typeof repfile === "undefined" ||
|
||||
repfile.length === 0
|
||||
repfile.length === 0 ||
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
@@ -32,14 +34,16 @@ ApiProxy.get(async (req, res) => {
|
||||
"&repfile=" +
|
||||
repfile;
|
||||
|
||||
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
casefolderID = casefolderID + "/" + repfile;
|
||||
|
||||
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
|
||||
await deleteBlobRep(containerName, casefolderID).then((data) => {
|
||||
return res.status(200).json({ data: data });
|
||||
});
|
||||
} else {
|
||||
return res.status(400).json();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -16,6 +16,19 @@ ApiProxy.get(async (req, res) => {
|
||||
var blobName = req.query.blobname;
|
||||
var checkHash = req.query.hash;
|
||||
|
||||
if (
|
||||
typeof containerName === "undefined" ||
|
||||
containerName.length === 0 ||
|
||||
typeof casefolderID === "undefined" ||
|
||||
casefolderID.length === 0 ||
|
||||
typeof blobName === "undefined" ||
|
||||
blobName.length === 0 ||
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
var checkquerypath =
|
||||
"/api/file/downloadblob?container=" +
|
||||
containerName +
|
||||
@@ -24,6 +37,10 @@ ApiProxy.get(async (req, res) => {
|
||||
"&blobname=" +
|
||||
blobName.trim();
|
||||
|
||||
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
|
||||
const bloblocation =
|
||||
casefolderID + (blobName.indexOf(".json") > 0 ? "/" : "/files/");
|
||||
@@ -38,8 +55,6 @@ ApiProxy.get(async (req, res) => {
|
||||
"attachment; filename=" + decodeURI(blobName)
|
||||
);
|
||||
return res.status(200).send(downloaded);
|
||||
} else {
|
||||
return res.status(400).json();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -14,16 +14,21 @@ ApiProxy.get(async (req, res) => {
|
||||
var containerName = req.query.container;
|
||||
var checkHash = req.query.hash;
|
||||
|
||||
if (
|
||||
typeof containerName === "undefined" ||
|
||||
containerName.length === 0 ||
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
var checkquerypath =
|
||||
"/api/file/getawaitingsubmissionfromblob?container=" + containerName;
|
||||
|
||||
// console.log(
|
||||
// "///////////////////////\ngetawaitingsubmissionblob url :",
|
||||
// req.url,
|
||||
// "\n///////////////////////\n"
|
||||
// );
|
||||
//console.log(hashAPIPath(checkquerypath), checkHash);
|
||||
//console.log(hashAPIPath(checkquerypath) == "&hash=" + checkHash);
|
||||
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
|
||||
const blobObj = await getAllProgressBlobs(containerName)
|
||||
@@ -33,8 +38,6 @@ ApiProxy.get(async (req, res) => {
|
||||
.then((data) => {
|
||||
return res.status(200).json(data);
|
||||
});
|
||||
} else {
|
||||
return res.status(400).json();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -23,6 +23,11 @@ const BASE_URL = process.env.API_ROOT || `http://localhost:${port}`;
|
||||
export default async function ApiProxy(req, res) {
|
||||
var containerName = req.query.container;
|
||||
var checkHash = req.query.hash;
|
||||
|
||||
if (typeof containerName === "undefined" || containerName.length === 0) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
var token = await getToken();
|
||||
|
||||
var queryUrl =
|
||||
|
||||
@@ -43,18 +43,27 @@ ApiProxy.get(async (req, res) => {
|
||||
var casefolderID = req.query.casefolderID;
|
||||
|
||||
var checkHash = req.query.hash;
|
||||
|
||||
if (
|
||||
typeof containerName === "undefined" ||
|
||||
containerName.length === 0 ||
|
||||
typeof casefolderID === "undefined" ||
|
||||
casefolderID.length === 0 ||
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
var checkquerypath =
|
||||
"/api/file/getbloblist?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
casefolderID;
|
||||
|
||||
// console.log("-----", casefolderID);
|
||||
// console.log("-----", req.query);
|
||||
// console.log("-----", checkquerypath);
|
||||
// console.log("-----", hashAPIPath(checkquerypath));
|
||||
// console.log("-----", checkHash);
|
||||
// console.log(hashAPIPath(checkquerypath) == "&hash=" + checkHash);
|
||||
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
|
||||
casefolderID.split("/").length > 1
|
||||
@@ -68,8 +77,6 @@ ApiProxy.get(async (req, res) => {
|
||||
: await getBlobs(containerName, casefolderID).then((data) => {
|
||||
return res.status(200).json({ "value": [data] });
|
||||
});
|
||||
} else {
|
||||
return res.status(400).json();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -24,6 +24,16 @@ export default async function ApiProxy(req, res) {
|
||||
var containerName = req.query.container;
|
||||
var casefolderID = req.query.casefolderID;
|
||||
var checkHash = req.query.hash;
|
||||
|
||||
if (
|
||||
typeof containerName === "undefined" ||
|
||||
containerName.length === 0 ||
|
||||
typeof casefolderID === "undefined" ||
|
||||
casefolderID.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
var token = await getToken();
|
||||
|
||||
var queryUrl =
|
||||
|
||||
@@ -15,23 +15,31 @@ ApiProxy.get(async (req, res) => {
|
||||
var casefolderID = req.query.casefolderID;
|
||||
|
||||
var checkHash = req.query.hash;
|
||||
|
||||
if (
|
||||
typeof containerName === "undefined" ||
|
||||
containerName.length === 0 ||
|
||||
typeof casefolderID === "undefined" ||
|
||||
casefolderID.length === 0 ||
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
var checkquerypath =
|
||||
"/api/file/getprogressobjblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
casefolderID;
|
||||
|
||||
// console.log("-----", casefolderID);
|
||||
// console.log("-----", req.query);
|
||||
// console.log("-----", checkquerypath);
|
||||
// console.log("-----", hashAPIPath(checkquerypath));
|
||||
// console.log("-----", checkHash);
|
||||
// console.log(hashAPIPath(checkquerypath) == "&hash=" + checkHash);
|
||||
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
|
||||
const blobObj = await getProgressBlobs(containerName, casefolderID)
|
||||
.then((data) => {
|
||||
//console.log("Progress blob path:", data.path);
|
||||
return downloadProgressFile(
|
||||
containerName,
|
||||
data.path,
|
||||
@@ -41,8 +49,6 @@ ApiProxy.get(async (req, res) => {
|
||||
.then((data) => {
|
||||
return res.status(200).json(data);
|
||||
});
|
||||
} else {
|
||||
return res.status(400).json();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -47,17 +47,24 @@ ApiProxy.get(async (req, res) => {
|
||||
var casefolderID = req.query.casefolderID;
|
||||
|
||||
var checkHash = req.query.hash;
|
||||
|
||||
if (
|
||||
typeof containerName === "undefined" ||
|
||||
containerName.length === 0 ||
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
var checkquerypath = "/api/file/getrepsblob?container=" + containerName;
|
||||
|
||||
//console.log("-----", casefolderID);
|
||||
//console.log("-----", req.query);
|
||||
//console.log("-----", checkquerypath);
|
||||
//console.log("-----", hashAPIPath(checkquerypath));
|
||||
//console.log("-----", checkHash);
|
||||
//console.log(hashAPIPath(checkquerypath) == "&hash=" + checkHash);
|
||||
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
|
||||
const blobObj = await getRepsBlobs(containerName, casefolderID)
|
||||
const blobObj = await getRepsBlobs(containerName)
|
||||
.then(async (data) => {
|
||||
return data;
|
||||
})
|
||||
@@ -72,8 +79,6 @@ ApiProxy.get(async (req, res) => {
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
} else {
|
||||
return res.status(400).json();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -23,6 +23,11 @@ const BASE_URL = process.env.API_ROOT || `http://localhost:${port}`;
|
||||
export default async function ApiProxy(req, res) {
|
||||
var containerName = req.query.container;
|
||||
var checkHash = req.query.hash;
|
||||
|
||||
if (typeof containerName === "undefined" || containerName.length === 0) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
var token = await getToken();
|
||||
|
||||
var queryUrl = "/api/file/getrepsblob?container=" + containerName;
|
||||
|
||||
@@ -17,10 +17,17 @@ ApiProxy.use(middleware);
|
||||
ApiProxy.get(async (req, res) => {
|
||||
var containerName = req.query.ident;
|
||||
var checkHash = req.query.hash;
|
||||
var checkquerypath = "/api/file/setupcontainer?ident=" + containerName;
|
||||
|
||||
//console.log(checkquerypath, hashAPIPath(checkquerypath), checkHash);
|
||||
//console.log(hashAPIPath(checkquerypath) == "&hash=" + checkHash);
|
||||
if (
|
||||
typeof containerName === "undefined" ||
|
||||
containerName.length === 0 ||
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
var checkquerypath = "/api/file/setupcontainer?ident=" + containerName;
|
||||
|
||||
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
|
||||
await createContainer(containerName)
|
||||
@@ -32,11 +39,6 @@ ApiProxy.get(async (req, res) => {
|
||||
res.status(400).json(error);
|
||||
});
|
||||
} else {
|
||||
consoleLogger({
|
||||
name: "setupcontainer",
|
||||
code: "bad hash",
|
||||
query: JSON.stringify(req.query)
|
||||
});
|
||||
return res.status(400).json();
|
||||
}
|
||||
});
|
||||
|
||||
+20
-28
@@ -1,8 +1,9 @@
|
||||
import {
|
||||
createBlob,
|
||||
createRepBlob,
|
||||
uploadFile,
|
||||
uploadFile
|
||||
} from "../../../actions/azurestorage";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
|
||||
import nextConnect from "next-connect";
|
||||
import middleware from "../middleware/middleware";
|
||||
@@ -12,26 +13,26 @@ ApiProxy.use(middleware);
|
||||
|
||||
ApiProxy.post(async (req, res) => {
|
||||
var checkHash = req.query.hash;
|
||||
//console.log(JSON.stringify(req.body));
|
||||
//console.log(JSON.stringify(req.body.appealData));
|
||||
//console.log(req.files);
|
||||
|
||||
var checkquerypath = "/api/file/upload";
|
||||
|
||||
if (hashAPIPath(checkquerypath) != "?hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
const appealData = req.body.appealData;
|
||||
const containerID = req.body.containerID[0];
|
||||
const casefolderID = req.body.casefolderID[0];
|
||||
const containerID = req.body?.containerID?.[0];
|
||||
const casefolderID = req.body?.casefolderID?.[0];
|
||||
const repOrAppeal = req.body.repOrAppeal || false;
|
||||
|
||||
console.log("there are files:", Object.keys(req.files).length);
|
||||
|
||||
// var checkquerypath = "/api/file/upload";
|
||||
|
||||
//console.log(hashAPIPath(checkquerypath), checkHash);
|
||||
//console.log(hashAPIPath(checkquerypath) == "?hash=" + checkHash);
|
||||
|
||||
// if (hashAPIPath(checkquerypath) == "?hash=" + checkHash) {
|
||||
//createContainer(containerID).then((containerName) => {
|
||||
|
||||
console.log("does this get folder name:", containerID, casefolderID);
|
||||
if (
|
||||
typeof containerID === "undefined" ||
|
||||
containerID.length === 0 ||
|
||||
typeof casefolderID === "undefined" ||
|
||||
casefolderID.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
repOrAppeal
|
||||
? createRepBlob(appealData, containerID, casefolderID).then((data) => {
|
||||
@@ -41,7 +42,6 @@ ApiProxy.post(async (req, res) => {
|
||||
// return res.status(200).json({ data });
|
||||
// }
|
||||
// );
|
||||
console.log("================================\nRepfile updated");
|
||||
return res.status(200).json({ data });
|
||||
})
|
||||
: createBlob(appealData, containerID, casefolderID).then((data) => {
|
||||
@@ -51,22 +51,14 @@ ApiProxy.post(async (req, res) => {
|
||||
// return res.status(200).json({ data });
|
||||
// }
|
||||
// );
|
||||
console.log(
|
||||
"================================\nAppeal file updated"
|
||||
);
|
||||
return res.status(200).json({ data });
|
||||
});
|
||||
//});
|
||||
|
||||
// } else {
|
||||
// return res.status(400).json();
|
||||
// }
|
||||
});
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
bodyParser: false
|
||||
}
|
||||
};
|
||||
|
||||
export default ApiProxy;
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import nextConnect from "next-connect";
|
||||
import middleware from "../middleware/middleware";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { fileTypeFromBuffer } from "file-type";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
@@ -36,11 +37,25 @@ ApiProxy.use(middleware);
|
||||
|
||||
ApiProxy.post(async (req, res) => {
|
||||
var checkHash = req.query.hash;
|
||||
var checkquerypath = "/api/file/uploadsinglefile";
|
||||
|
||||
const containerID = req.body.containerID[0];
|
||||
const casefolderID = req.body.casefolderID[0];
|
||||
if (hashAPIPath(checkquerypath) != "?hash=" + checkHash) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
console.log("there are files:", Object.keys(req.files).length);
|
||||
const containerID = req.body?.containerID?.[0];
|
||||
const casefolderID = req.body?.casefolderID?.[0];
|
||||
|
||||
if (
|
||||
typeof containerID === "undefined" ||
|
||||
containerID.length === 0 ||
|
||||
typeof casefolderID === "undefined" ||
|
||||
casefolderID.length === 0
|
||||
) {
|
||||
return res.status(400).json();
|
||||
}
|
||||
|
||||
const uploadedFiles = req.files || {};
|
||||
|
||||
// Add other mimetypes here
|
||||
const allowedMimeTypes = [
|
||||
@@ -57,7 +72,7 @@ ApiProxy.post(async (req, res) => {
|
||||
var allowedFilesFormData = {};
|
||||
var invalidFiles = []; // To store the names of invalid files
|
||||
|
||||
for (const [fileName, fileDetails] of Object.entries(req.files)) {
|
||||
for (const [fileName, fileDetails] of Object.entries(uploadedFiles)) {
|
||||
const file = fileDetails[0];
|
||||
const filePath = file.path;
|
||||
|
||||
@@ -65,9 +80,6 @@ ApiProxy.post(async (req, res) => {
|
||||
const fnCheck = validateFilenameServer(file.originalFilename);
|
||||
|
||||
if (!fnCheck.ok) {
|
||||
console.log(
|
||||
`File ${file.originalFilename} rejected: ${fnCheck.reason}`
|
||||
);
|
||||
invalidFiles.push(`${file.originalFilename} - Invalid filename`);
|
||||
continue; // do not process further
|
||||
}
|
||||
@@ -80,7 +92,6 @@ ApiProxy.post(async (req, res) => {
|
||||
|
||||
try {
|
||||
const type = await fileTypeFromBuffer(buffer); // Correct usage of fileTypeFromBuffer
|
||||
console.log("checking mime type ", type);
|
||||
if (type && allowedMimeTypes.includes(type.mime)) {
|
||||
// If the MIME type from the file signature matches the allowed list
|
||||
allowedFilesFormData[fileName] = fileDetails.map(
|
||||
@@ -94,21 +105,12 @@ ApiProxy.post(async (req, res) => {
|
||||
})
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
`\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n\nFile ${fileName} has an invalid MIME type based on its content.\n\n\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\`
|
||||
);
|
||||
invalidFiles.push(fileName); // Track invalid file
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(
|
||||
`Error reading file ${fileName} for MIME type validation`,
|
||||
error
|
||||
);
|
||||
consoleLogger(error);
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
`\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n\nFile ${fileName} has an unsupported MIME type: ${fileMimeType}\n\n\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\`
|
||||
);
|
||||
invalidFiles.push(fileName); // Track invalid file
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const vm = require("vm");
|
||||
const assert = require("assert");
|
||||
|
||||
const rootDir = path.resolve(__dirname, "..", "..");
|
||||
|
||||
const loadModule = (relativePath, injected = {}) => {
|
||||
const filePath = path.join(rootDir, relativePath);
|
||||
let source = fs.readFileSync(filePath, "utf8");
|
||||
|
||||
source = source.replace(/import[\s\S]*?from\s+"[^"]+";\n?/g, "");
|
||||
source = source.replace(
|
||||
/export default async function\s+(\w+)\s*\(/,
|
||||
"async function $1("
|
||||
);
|
||||
source = source.replace(/export const\s+/g, "const ");
|
||||
source = source.replace(
|
||||
/export default\s+(\w+);/g,
|
||||
"module.exports.default = $1;"
|
||||
);
|
||||
|
||||
source +=
|
||||
'\nif (typeof ApiProxy !== "undefined" && !module.exports.default) module.exports.default = ApiProxy;\n';
|
||||
|
||||
const context = {
|
||||
module: { exports: {} },
|
||||
exports: {},
|
||||
require,
|
||||
process,
|
||||
console: {
|
||||
log: () => {},
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
error: () => {}
|
||||
},
|
||||
...injected
|
||||
};
|
||||
|
||||
vm.runInNewContext(source, context, { filename: filePath });
|
||||
return context.module.exports;
|
||||
};
|
||||
|
||||
const createNextConnectMock = () => {
|
||||
const router = {
|
||||
handler: null,
|
||||
use: () => {},
|
||||
get(fn) {
|
||||
this.handler = fn;
|
||||
}
|
||||
};
|
||||
|
||||
return () => router;
|
||||
};
|
||||
|
||||
const createRes = () => {
|
||||
const state = {
|
||||
statusCode: null,
|
||||
jsonBody: undefined
|
||||
};
|
||||
|
||||
return {
|
||||
state,
|
||||
setHeader: () => {},
|
||||
status(code) {
|
||||
state.statusCode = code;
|
||||
return this;
|
||||
},
|
||||
json(payload) {
|
||||
state.jsonBody = payload;
|
||||
return payload;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const tests = [];
|
||||
const test = (name, fn) => tests.push({ name, fn });
|
||||
|
||||
test("getawaitingsubmissionfromblob rejects missing hash with 400", async () => {
|
||||
const calls = [];
|
||||
const nextConnect = createNextConnectMock();
|
||||
|
||||
const mod = loadModule("pages/api/file/getawaitingsubmissionfromblob.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
getAllProgressBlobs: async (...args) => {
|
||||
calls.push(args);
|
||||
return [];
|
||||
},
|
||||
downloadAllProgressFiles: async () => [],
|
||||
_: { isEmpty: (value) => !value },
|
||||
nextConnect,
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { container: "c1" } };
|
||||
const res = createRes();
|
||||
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(calls.length, 0);
|
||||
});
|
||||
|
||||
test("getprogressobjblob rejects missing casefolderID with 400", async () => {
|
||||
const calls = [];
|
||||
const nextConnect = createNextConnectMock();
|
||||
|
||||
const mod = loadModule("pages/api/file/getprogressobjblob.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
getProgressBlobs: async (...args) => {
|
||||
calls.push(args);
|
||||
return { path: "x" };
|
||||
},
|
||||
downloadProgressFile: async () => ({}),
|
||||
_: { isEmpty: (value) => !value },
|
||||
nextConnect,
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: { container: "c1", hash: "expected" }
|
||||
};
|
||||
const res = createRes();
|
||||
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(calls.length, 0);
|
||||
});
|
||||
|
||||
test("getbloblist rejects invalid hash with 400", async () => {
|
||||
const calls = [];
|
||||
const nextConnect = createNextConnectMock();
|
||||
|
||||
const mod = loadModule("pages/api/file/getbloblist.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
getBlobs: async (...args) => {
|
||||
calls.push(args);
|
||||
return [];
|
||||
},
|
||||
getRepsFilesBlobs: async () => [],
|
||||
nextConnect,
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: {
|
||||
container: "c1",
|
||||
casefolderID: "case-1",
|
||||
hash: "wrong"
|
||||
}
|
||||
};
|
||||
const res = createRes();
|
||||
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(calls.length, 0);
|
||||
});
|
||||
|
||||
test("getrepsblob rejects missing hash with 400", async () => {
|
||||
const calls = [];
|
||||
const nextConnect = createNextConnectMock();
|
||||
|
||||
const mod = loadModule("pages/api/file/getrepsblob.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
getRepsBlobs: async (...args) => {
|
||||
calls.push(args);
|
||||
return [];
|
||||
},
|
||||
downloadAllRepsFiles: async () => [],
|
||||
consoleLogger: () => {},
|
||||
_: { isEmpty: (value) => !value },
|
||||
nextConnect,
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: {
|
||||
container: "c1",
|
||||
casefolderID: "case-1"
|
||||
}
|
||||
};
|
||||
const res = createRes();
|
||||
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(calls.length, 0);
|
||||
});
|
||||
|
||||
test("getbloblist happy path with valid hash returns 200", async () => {
|
||||
const nextConnect = createNextConnectMock();
|
||||
|
||||
const mod = loadModule("pages/api/file/getbloblist.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
getBlobs: async () => ["file-1"],
|
||||
getRepsFilesBlobs: async () => ["file-rep"],
|
||||
nextConnect,
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: {
|
||||
container: "c1",
|
||||
casefolderID: "case-1",
|
||||
hash: "expected"
|
||||
}
|
||||
};
|
||||
const res = createRes();
|
||||
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 200);
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(res.state.jsonBody)), {
|
||||
value: [["file-1"]]
|
||||
});
|
||||
});
|
||||
|
||||
const run = async () => {
|
||||
let passed = 0;
|
||||
|
||||
for (const currentTest of tests) {
|
||||
await currentTest.fn();
|
||||
passed += 1;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Phase 10 behavioural tests passed (${passed}/${tests.length}).`
|
||||
);
|
||||
};
|
||||
|
||||
run().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,171 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const vm = require("vm");
|
||||
const assert = require("assert");
|
||||
|
||||
const rootDir = path.resolve(__dirname, "..", "..");
|
||||
|
||||
const loadModule = (relativePath, injected = {}) => {
|
||||
const filePath = path.join(rootDir, relativePath);
|
||||
let source = fs.readFileSync(filePath, "utf8");
|
||||
|
||||
source = source.replace(/import[\s\S]*?from\s+"[^"]+";\n?/g, "");
|
||||
source = source.replace(
|
||||
/export default async function\s+(\w+)\s*\(/,
|
||||
"async function $1("
|
||||
);
|
||||
source = source.replace(/export const\s+/g, "const ");
|
||||
source = source.replace(
|
||||
/export default\s+(\w+);/g,
|
||||
"module.exports.default = $1;"
|
||||
);
|
||||
source +=
|
||||
'\nif (typeof ApiProxy !== "undefined" && !module.exports.default) module.exports.default = ApiProxy;\n';
|
||||
|
||||
const context = {
|
||||
module: { exports: {} },
|
||||
exports: {},
|
||||
require,
|
||||
process,
|
||||
console: { log: () => {}, error: () => {} },
|
||||
...injected
|
||||
};
|
||||
|
||||
vm.runInNewContext(source, context, { filename: filePath });
|
||||
return context.module.exports;
|
||||
};
|
||||
|
||||
const createNextConnectMock = () => {
|
||||
const router = {
|
||||
handler: null,
|
||||
use: () => {},
|
||||
get(fn) {
|
||||
this.handler = fn;
|
||||
}
|
||||
};
|
||||
return () => router;
|
||||
};
|
||||
|
||||
const createRes = () => {
|
||||
const state = { statusCode: null, jsonBody: undefined };
|
||||
return {
|
||||
state,
|
||||
status(code) {
|
||||
state.statusCode = code;
|
||||
return this;
|
||||
},
|
||||
json(payload) {
|
||||
state.jsonBody = payload;
|
||||
return payload;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const tests = [];
|
||||
const test = (name, fn) => tests.push({ name, fn });
|
||||
|
||||
test("getbloblist rejects missing hash with 400", async () => {
|
||||
const calls = [];
|
||||
const mod = loadModule("pages/api/file/getbloblist.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
getBlobs: async (...args) => {
|
||||
calls.push(args);
|
||||
return [];
|
||||
},
|
||||
getRepsFilesBlobs: async () => [],
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { container: "c1", casefolderID: "case-1" } };
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(calls.length, 0);
|
||||
});
|
||||
|
||||
test("deleteblob rejects missing blobname with 400", async () => {
|
||||
const calls = [];
|
||||
const mod = loadModule("pages/api/file/deleteblob.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
deleteBlob: async (...args) => {
|
||||
calls.push(args);
|
||||
return true;
|
||||
},
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: { container: "c1", casefolderID: "case-1", hash: "expected" }
|
||||
};
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(calls.length, 0);
|
||||
});
|
||||
|
||||
test("deleteawaitingsubmissionfromblob rejects invalid hash with 400", async () => {
|
||||
const calls = [];
|
||||
const mod = loadModule(
|
||||
"pages/api/file/deleteawaitingsubmissionfromblob.js",
|
||||
{
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
deleteBlob: async (...args) => {
|
||||
calls.push(args);
|
||||
return true;
|
||||
},
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
}
|
||||
);
|
||||
|
||||
const req = {
|
||||
query: {
|
||||
container: "c1",
|
||||
casefolderID: "case-1",
|
||||
blobname: "f.pdf",
|
||||
hash: "wrong"
|
||||
}
|
||||
};
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(calls.length, 0);
|
||||
});
|
||||
|
||||
test("getbloblist valid hash returns 200", async () => {
|
||||
const mod = loadModule("pages/api/file/getbloblist.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
getBlobs: async () => ["f1"],
|
||||
getRepsFilesBlobs: async () => ["rf1"],
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: { container: "c1", casefolderID: "case-1", hash: "expected" }
|
||||
};
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 200);
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(res.state.jsonBody)), {
|
||||
value: [["f1"]]
|
||||
});
|
||||
});
|
||||
|
||||
const run = async () => {
|
||||
let passed = 0;
|
||||
for (const t of tests) {
|
||||
await t.fn();
|
||||
passed += 1;
|
||||
}
|
||||
console.log(
|
||||
`Phase 11 behavioural tests passed (${passed}/${tests.length}).`
|
||||
);
|
||||
};
|
||||
|
||||
run().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,169 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const vm = require("vm");
|
||||
const assert = require("assert");
|
||||
|
||||
const rootDir = path.resolve(__dirname, "..", "..");
|
||||
|
||||
const loadModule = (relativePath, injected = {}) => {
|
||||
const filePath = path.join(rootDir, relativePath);
|
||||
let source = fs.readFileSync(filePath, "utf8");
|
||||
|
||||
source = source.replace(/import[\s\S]*?from\s+"[^"]+";\n?/g, "");
|
||||
source = source.replace(
|
||||
/export default async function\s+(\w+)\s*\(/,
|
||||
"async function $1("
|
||||
);
|
||||
source = source.replace(/export const\s+/g, "const ");
|
||||
source = source.replace(
|
||||
/export default\s+(\w+);/g,
|
||||
"module.exports.default = $1;"
|
||||
);
|
||||
source +=
|
||||
'\nif (typeof ApiProxy !== "undefined" && !module.exports.default) module.exports.default = ApiProxy;\n';
|
||||
|
||||
const context = {
|
||||
module: { exports: {} },
|
||||
exports: {},
|
||||
require,
|
||||
process,
|
||||
console: { log: () => {}, error: () => {} },
|
||||
port: 3000,
|
||||
...injected
|
||||
};
|
||||
|
||||
vm.runInNewContext(source, context, { filename: filePath });
|
||||
return context.module.exports;
|
||||
};
|
||||
|
||||
const createNextConnectMock = () => {
|
||||
const router = {
|
||||
handler: null,
|
||||
use: () => {},
|
||||
get(fn) {
|
||||
this.handler = fn;
|
||||
}
|
||||
};
|
||||
return () => router;
|
||||
};
|
||||
|
||||
const createRes = () => {
|
||||
const state = {
|
||||
statusCode: null,
|
||||
jsonBody: undefined,
|
||||
sentBody: undefined,
|
||||
headers: {}
|
||||
};
|
||||
return {
|
||||
state,
|
||||
status(code) {
|
||||
state.statusCode = code;
|
||||
return this;
|
||||
},
|
||||
json(payload) {
|
||||
state.jsonBody = payload;
|
||||
return payload;
|
||||
},
|
||||
send(payload) {
|
||||
state.sentBody = payload;
|
||||
return payload;
|
||||
},
|
||||
setHeader(name, value) {
|
||||
state.headers[name] = value;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const tests = [];
|
||||
const test = (name, fn) => tests.push({ name, fn });
|
||||
|
||||
test("downloadblob rejects missing hash with 400", async () => {
|
||||
const calls = [];
|
||||
const mod = loadModule("pages/api/file/downloadblob.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
downloadFile: async (...args) => {
|
||||
calls.push(args);
|
||||
return Buffer.from("x");
|
||||
},
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: { container: "c1", casefolderID: "case-1", blobname: "f.pdf" }
|
||||
};
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(calls.length, 0);
|
||||
});
|
||||
|
||||
test("downloadblob valid hash returns 200", async () => {
|
||||
const mod = loadModule("pages/api/file/downloadblob.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
downloadFile: async () => Buffer.from("file"),
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: {
|
||||
container: "c1",
|
||||
casefolderID: "case-1",
|
||||
blobname: "f.pdf",
|
||||
hash: "expected"
|
||||
}
|
||||
};
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 200);
|
||||
});
|
||||
|
||||
test("getbloblistproxy rejects missing container with 400", async () => {
|
||||
const mod = loadModule("pages/api/file/getbloblistproxy.js", {
|
||||
getToken: async () => ({ access_token: "t" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeaders: () => ({}),
|
||||
axios: { get: async () => ({ data: { ok: true } }) },
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { casefolderID: "case-1" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
});
|
||||
|
||||
test("getawaitingsubmissionfromblobproxy rejects missing container with 400", async () => {
|
||||
const mod = loadModule(
|
||||
"pages/api/file/getawaitingsubmissionfromblobproxy.js",
|
||||
{
|
||||
getToken: async () => ({ access_token: "t" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeaders: () => ({}),
|
||||
axios: { get: async () => ({ data: { ok: true } }) },
|
||||
consoleLogger: () => {}
|
||||
}
|
||||
);
|
||||
|
||||
const req = { query: {} };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
});
|
||||
|
||||
const run = async () => {
|
||||
let passed = 0;
|
||||
for (const t of tests) {
|
||||
await t.fn();
|
||||
passed += 1;
|
||||
}
|
||||
console.log(
|
||||
`Phase 12 behavioural tests passed (${passed}/${tests.length}).`
|
||||
);
|
||||
};
|
||||
|
||||
run().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,197 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const vm = require("vm");
|
||||
const assert = require("assert");
|
||||
|
||||
const rootDir = path.resolve(__dirname, "..", "..");
|
||||
|
||||
const loadModule = (relativePath, injected = {}) => {
|
||||
const filePath = path.join(rootDir, relativePath);
|
||||
let source = fs.readFileSync(filePath, "utf8");
|
||||
|
||||
source = source.replace(/import[\s\S]*?from\s+"[^"]+";\n?/g, "");
|
||||
source = source.replace(
|
||||
/export default async function\s+(\w+)\s*\(/,
|
||||
"async function $1("
|
||||
);
|
||||
source = source.replace(/export const\s+/g, "const ");
|
||||
source = source.replace(
|
||||
/export default\s+(\w+);/g,
|
||||
"module.exports.default = $1;"
|
||||
);
|
||||
source +=
|
||||
'\nif (typeof ApiProxy !== "undefined" && !module.exports.default) module.exports.default = ApiProxy;\n';
|
||||
|
||||
const context = {
|
||||
module: { exports: {} },
|
||||
exports: {},
|
||||
require,
|
||||
process,
|
||||
console: { log: () => {}, error: () => {} },
|
||||
...injected
|
||||
};
|
||||
|
||||
vm.runInNewContext(source, context, { filename: filePath });
|
||||
return context.module.exports;
|
||||
};
|
||||
|
||||
const createNextConnectMock = () => {
|
||||
const router = {
|
||||
handler: null,
|
||||
use: () => {},
|
||||
get(fn) {
|
||||
this.handler = fn;
|
||||
}
|
||||
};
|
||||
return () => router;
|
||||
};
|
||||
|
||||
const createRes = () => {
|
||||
const state = { statusCode: null, jsonBody: undefined };
|
||||
return {
|
||||
state,
|
||||
status(code) {
|
||||
state.statusCode = code;
|
||||
return this;
|
||||
},
|
||||
json(payload) {
|
||||
state.jsonBody = payload;
|
||||
return payload;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const tests = [];
|
||||
const test = (name, fn) => tests.push({ name, fn });
|
||||
|
||||
test("deleteblobcase rejects missing hash with 400", async () => {
|
||||
const calls = [];
|
||||
const mod = loadModule("pages/api/file/deleteblobcase.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
deleteBlobCase: async (...args) => {
|
||||
calls.push(args);
|
||||
return true;
|
||||
},
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { container: "c1", casefolderID: "case-1" } };
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(calls.length, 0);
|
||||
});
|
||||
|
||||
test("deleteblobrep rejects missing hash with 400", async () => {
|
||||
const calls = [];
|
||||
const mod = loadModule("pages/api/file/deleteblobrep.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
deleteBlobRep: async (...args) => {
|
||||
calls.push(args);
|
||||
return true;
|
||||
},
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: { container: "c1", casefolderID: "case-1", repfile: "r.pdf" }
|
||||
};
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(calls.length, 0);
|
||||
});
|
||||
|
||||
test("createcaseinvolvement_api rejects missing required body values with 400", async () => {
|
||||
const mod = loadModule("pages/api/file/createcaseinvolvement_api.js", {
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
axios: async () => ({ data: { ok: true } }),
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { body: {} };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
});
|
||||
|
||||
test("createrepinvolvement_api rejects missing required body values with 400", async () => {
|
||||
const mod = loadModule("pages/api/file/createrepinvolvement_api.js", {
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
axios: async () => ({ data: { ok: true } }),
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { body: {} };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
});
|
||||
|
||||
test("deleteblobcase valid hash returns 200", async () => {
|
||||
const mod = loadModule("pages/api/file/deleteblobcase.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
deleteBlobCase: async () => ({ ok: true }),
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: { container: "c1", casefolderID: "case-1", hash: "expected" }
|
||||
};
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 200);
|
||||
});
|
||||
|
||||
test("createcaseinvolvement_api with valid body returns 200", async () => {
|
||||
const mod = loadModule("pages/api/file/createcaseinvolvement_api.js", {
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
CryptoJS: {
|
||||
HmacSHA256: () => ({ toString: () => "signed" }),
|
||||
enc: { Hex: { parse: () => "" } }
|
||||
},
|
||||
axios: async () => ({ data: { ok: true } }),
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { body: { contactid: "c1", incidentid: "i1" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 200);
|
||||
});
|
||||
|
||||
test("createrepinvolvement_api with valid body returns 200", async () => {
|
||||
const mod = loadModule("pages/api/file/createrepinvolvement_api.js", {
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
CryptoJS: {
|
||||
HmacSHA256: () => ({ toString: () => "signed" }),
|
||||
enc: { Hex: { parse: () => "" } }
|
||||
},
|
||||
axios: async () => ({ data: { ok: true } }),
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { body: { contactid: "c1", incidentid: "i1" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
assert.strictEqual(res.state.statusCode, 200);
|
||||
});
|
||||
|
||||
const run = async () => {
|
||||
let passed = 0;
|
||||
for (const t of tests) {
|
||||
await t.fn();
|
||||
passed += 1;
|
||||
}
|
||||
console.log(
|
||||
`Phase 13 behavioural tests passed (${passed}/${tests.length}).`
|
||||
);
|
||||
};
|
||||
|
||||
run().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,164 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const vm = require("vm");
|
||||
const assert = require("assert");
|
||||
|
||||
const rootDir = path.resolve(__dirname, "..", "..");
|
||||
|
||||
const loadModule = (relativePath, injected = {}) => {
|
||||
const filePath = path.join(rootDir, relativePath);
|
||||
let source = fs.readFileSync(filePath, "utf8");
|
||||
|
||||
source = source.replace(/import[\s\S]*?from\s+"[^"]+";\n?/g, "");
|
||||
source = source.replace(
|
||||
/export default async function\s+(\w+)\s*\(/,
|
||||
"async function $1("
|
||||
);
|
||||
source = source.replace(/export const\s+/g, "const ");
|
||||
source = source.replace(
|
||||
/export default\s+(\w+);/g,
|
||||
"module.exports.default = $1;"
|
||||
);
|
||||
source +=
|
||||
'\nif (typeof ApiProxy !== "undefined" && !module.exports.default) module.exports.default = ApiProxy;\n';
|
||||
|
||||
const context = {
|
||||
module: { exports: {} },
|
||||
exports: {},
|
||||
require,
|
||||
process,
|
||||
console: { log: () => {}, error: () => {} },
|
||||
...injected
|
||||
};
|
||||
|
||||
vm.runInNewContext(source, context, { filename: filePath });
|
||||
return context.module.exports;
|
||||
};
|
||||
|
||||
const createNextConnectMock = () => {
|
||||
const router = {
|
||||
handler: null,
|
||||
use: () => {},
|
||||
get(fn) {
|
||||
this.handler = fn;
|
||||
}
|
||||
};
|
||||
return () => router;
|
||||
};
|
||||
|
||||
const createRes = () => {
|
||||
const state = { statusCode: null, jsonBody: undefined };
|
||||
return {
|
||||
state,
|
||||
status(code) {
|
||||
state.statusCode = code;
|
||||
return this;
|
||||
},
|
||||
json(payload) {
|
||||
state.jsonBody = payload;
|
||||
return payload;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const tests = [];
|
||||
const test = (name, fn) => tests.push({ name, fn });
|
||||
|
||||
test("gethash_api rejects missing path with 400", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/gethash_api.js", {
|
||||
hashAPIPath: () => "?hash=expected",
|
||||
getSession: async () => ({ user: { id: "u1" } }),
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = { query: {} };
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
});
|
||||
|
||||
test("gethash_api rejects non-api path with 400", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/gethash_api.js", {
|
||||
hashAPIPath: () => "?hash=expected",
|
||||
getSession: async () => ({ user: { id: "u1" } }),
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { path: "/not-api/path" } };
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
});
|
||||
|
||||
test("gethash_api returns hash for valid api path", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/gethash_api.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
getSession: async () => ({ user: { id: "u1" } }),
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { path: "/api/file/upload" } };
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 200);
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(res.state.jsonBody)), {
|
||||
hash: "&hash=expected"
|
||||
});
|
||||
});
|
||||
|
||||
test("gethash_api returns hash for allow-listed getportallogin path", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/gethash_api.js", {
|
||||
hashAPIPath: () => "&hash=login",
|
||||
getSession: async () => ({ user: { id: "u1" } }),
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: { path: "/api/endpoint/getportallogin_api?emailAddress=a@b.com" }
|
||||
};
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 200);
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(res.state.jsonBody)), {
|
||||
hash: "&hash=login"
|
||||
});
|
||||
});
|
||||
|
||||
test("gethash_api rejects unauthenticated requests with 401", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/gethash_api.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
getSession: async () => null,
|
||||
nextConnect: createNextConnectMock(),
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { path: "/api/file/upload" } };
|
||||
const res = createRes();
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 401);
|
||||
});
|
||||
|
||||
const run = async () => {
|
||||
let passed = 0;
|
||||
for (const t of tests) {
|
||||
await t.fn();
|
||||
passed += 1;
|
||||
}
|
||||
console.log(
|
||||
`Phase 14 behavioural tests passed (${passed}/${tests.length}).`
|
||||
);
|
||||
};
|
||||
|
||||
run().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -208,31 +208,34 @@ test("portal/deleteMyRepresentations logs and returns undefined on failure", asy
|
||||
test("account/getPortalLogin appends hash and returns res.data", async () => {
|
||||
const axios = createAxiosMock();
|
||||
const logger = createLoggerMock();
|
||||
const hashCalls = [];
|
||||
const hashAPIPath = (queryPath) => {
|
||||
hashCalls.push(queryPath);
|
||||
return "&hash=login123";
|
||||
};
|
||||
const signCalls = [];
|
||||
|
||||
axios.getHandler = async () => ({ data: { value: [{ id: "user-1" }] } });
|
||||
axios.getHandler = async (url) => {
|
||||
if (url.startsWith("/api/endpoint/gethash_api?path=")) {
|
||||
signCalls.push(url);
|
||||
return { data: { hash: "&hash=login123" } };
|
||||
}
|
||||
|
||||
return { data: { value: [{ id: "user-1" }] } };
|
||||
};
|
||||
|
||||
const account = loadServiceModule("accountDirectService.js", {
|
||||
axios,
|
||||
BASE_URL: "http://example.local",
|
||||
consoleLogger: logger.consoleLogger,
|
||||
hashAPIPath
|
||||
hashAPIPath: () => "&hash=fallback"
|
||||
});
|
||||
|
||||
const result = await account.getPortalLogin("person@example.com");
|
||||
|
||||
assert.deepStrictEqual(normalize(result), { value: [{ id: "user-1" }] });
|
||||
assert.strictEqual(hashCalls.length, 1);
|
||||
assert.strictEqual(signCalls.length, 1);
|
||||
assert.strictEqual(
|
||||
hashCalls[0],
|
||||
"/api/endpoint/getportallogin_api?emailAddress=person@example.com"
|
||||
signCalls[0],
|
||||
"/api/endpoint/gethash_api?path=%2Fapi%2Fendpoint%2Fgetportallogin_api%3FemailAddress%3Dperson%40example.com"
|
||||
);
|
||||
assert.strictEqual(
|
||||
axios.calls[0].url,
|
||||
axios.calls[1].url,
|
||||
"http://example.local/api/endpoint/getportallogin_api?emailAddress=person@example.com&hash=login123"
|
||||
);
|
||||
});
|
||||
@@ -242,7 +245,13 @@ test("account/getPortalLogin returns JSON stringified error on failure", async (
|
||||
const logger = createLoggerMock();
|
||||
const error = createAxiosError(500, "Broken");
|
||||
|
||||
axios.getHandler = async () => Promise.reject(error);
|
||||
axios.getHandler = async (url) => {
|
||||
if (url.startsWith("/api/endpoint/gethash_api?path=")) {
|
||||
return { data: { hash: "&hash=err" } };
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
};
|
||||
|
||||
const account = loadServiceModule("accountDirectService.js", {
|
||||
axios,
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const vm = require("vm");
|
||||
const assert = require("assert");
|
||||
|
||||
const rootDir = path.resolve(__dirname, "..", "..");
|
||||
|
||||
const loadModule = (relativePath, injected = {}) => {
|
||||
const filePath = path.join(rootDir, relativePath);
|
||||
let source = fs.readFileSync(filePath, "utf8");
|
||||
|
||||
source = source.replace(/import[\s\S]*?from\s+"[^"]+";\n?/g, "");
|
||||
source = source.replace(
|
||||
/export default async function\s+(\w+)\s*\(/,
|
||||
"async function $1("
|
||||
);
|
||||
source = source.replace(/export const\s+/g, "const ");
|
||||
source = source.replace(
|
||||
/export default\s+(\w+);/g,
|
||||
"module.exports.default = $1;"
|
||||
);
|
||||
|
||||
source +=
|
||||
'\nif (typeof ApiProxy !== "undefined" && !module.exports.default) module.exports.default = ApiProxy;\n';
|
||||
|
||||
const context = {
|
||||
module: { exports: {} },
|
||||
exports: {},
|
||||
require,
|
||||
process,
|
||||
console: {
|
||||
log: () => {},
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
error: () => {}
|
||||
},
|
||||
...injected
|
||||
};
|
||||
|
||||
vm.runInNewContext(source, context, { filename: filePath });
|
||||
return context.module.exports;
|
||||
};
|
||||
|
||||
const createNextConnectMock = () => {
|
||||
const router = {
|
||||
handler: null,
|
||||
use: () => {},
|
||||
get(fn) {
|
||||
this.handler = fn;
|
||||
},
|
||||
post(fn) {
|
||||
this.handler = fn;
|
||||
}
|
||||
};
|
||||
|
||||
return () => router;
|
||||
};
|
||||
|
||||
const createRes = () => {
|
||||
const state = {
|
||||
statusCode: null,
|
||||
jsonBody: undefined
|
||||
};
|
||||
|
||||
return {
|
||||
state,
|
||||
status(code) {
|
||||
state.statusCode = code;
|
||||
return this;
|
||||
},
|
||||
json(payload) {
|
||||
state.jsonBody = payload;
|
||||
return payload;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const tests = [];
|
||||
const test = (name, fn) => tests.push({ name, fn });
|
||||
|
||||
test("createrepcompletemessage_api rejects missing hash with 400", async () => {
|
||||
const calls = [];
|
||||
const nextConnect = createNextConnectMock();
|
||||
|
||||
const mod = loadModule("pages/api/file/createrepcompletemessage_api.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
consoleLogger: () => {},
|
||||
createRepCompleteMessage: async (...args) => {
|
||||
calls.push(args);
|
||||
return { ok: true };
|
||||
},
|
||||
nextConnect,
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: {
|
||||
container: "c1",
|
||||
tempcaseref: "temp-1",
|
||||
repid: "rep-1"
|
||||
}
|
||||
};
|
||||
const res = createRes();
|
||||
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(calls.length, 0);
|
||||
});
|
||||
|
||||
test("upload rejects missing hash with 400", async () => {
|
||||
const blobCalls = [];
|
||||
const nextConnect = createNextConnectMock();
|
||||
|
||||
const mod = loadModule("pages/api/file/upload.js", {
|
||||
hashAPIPath: () => "?hash=expected",
|
||||
createBlob: async (...args) => {
|
||||
blobCalls.push(args);
|
||||
return { ok: true };
|
||||
},
|
||||
createRepBlob: async (...args) => {
|
||||
blobCalls.push(args);
|
||||
return { ok: true };
|
||||
},
|
||||
uploadFile: async () => {},
|
||||
nextConnect,
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: {},
|
||||
body: {
|
||||
appealData: {},
|
||||
containerID: ["c1"],
|
||||
casefolderID: ["case-1"]
|
||||
},
|
||||
files: {}
|
||||
};
|
||||
const res = createRes();
|
||||
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(blobCalls.length, 0);
|
||||
});
|
||||
|
||||
test("uploadsinglefile rejects invalid hash with 400", async () => {
|
||||
const uploadCalls = [];
|
||||
const nextConnect = createNextConnectMock();
|
||||
|
||||
const mod = loadModule("pages/api/file/uploadsinglefile.js", {
|
||||
hashAPIPath: () => "?hash=expected",
|
||||
uploadSingleFile: async (...args) => {
|
||||
uploadCalls.push(args);
|
||||
return { ok: true };
|
||||
},
|
||||
consoleLogger: () => {},
|
||||
fileTypeFromBuffer: async () => ({ mime: "application/pdf" }),
|
||||
fs: { readFileSync: () => Buffer.from("file") },
|
||||
path: { basename: (value) => value },
|
||||
nextConnect,
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: { hash: "wrong" },
|
||||
body: { containerID: ["c1"], casefolderID: ["case-1"] },
|
||||
files: {}
|
||||
};
|
||||
const res = createRes();
|
||||
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(uploadCalls.length, 0);
|
||||
});
|
||||
|
||||
test("setupcontainer rejects missing ident with 400", async () => {
|
||||
const createCalls = [];
|
||||
const nextConnect = createNextConnectMock();
|
||||
|
||||
const mod = loadModule("pages/api/file/setupcontainer.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
createContainer: async (...args) => {
|
||||
createCalls.push(args);
|
||||
return { ok: true };
|
||||
},
|
||||
createContainerSas: async () => {},
|
||||
getContainers: async () => {},
|
||||
getBlobs: async () => {},
|
||||
uploadFile: async () => {},
|
||||
consoleLogger: () => {},
|
||||
nextConnect,
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { hash: "expected" } };
|
||||
const res = createRes();
|
||||
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(createCalls.length, 0);
|
||||
});
|
||||
|
||||
test("setupcontainer rejects invalid hash with 400", async () => {
|
||||
const createCalls = [];
|
||||
const nextConnect = createNextConnectMock();
|
||||
|
||||
const mod = loadModule("pages/api/file/setupcontainer.js", {
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
createContainer: async (...args) => {
|
||||
createCalls.push(args);
|
||||
return { ok: true };
|
||||
},
|
||||
createContainerSas: async () => {},
|
||||
getContainers: async () => {},
|
||||
getBlobs: async () => {},
|
||||
uploadFile: async () => {},
|
||||
consoleLogger: () => {},
|
||||
nextConnect,
|
||||
middleware: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { ident: "container-1", hash: "wrong" } };
|
||||
const res = createRes();
|
||||
|
||||
await mod.default.handler(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(createCalls.length, 0);
|
||||
});
|
||||
|
||||
const run = async () => {
|
||||
let passed = 0;
|
||||
|
||||
for (const currentTest of tests) {
|
||||
await currentTest.fn();
|
||||
passed += 1;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Phase 9 behavioural tests passed (${passed}/${tests.length}).`
|
||||
);
|
||||
};
|
||||
|
||||
run().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user