Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/combine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ const combineRun = async (details: Data, deviceToScan: string) => {
consoleLogger.info(`Suppressed Crawlee ps-tree locale error: ${err.message}`);
return;
}
// Suppress stale Playwright in-process connection errors that fire asynchronously
// after the browser is closed in writeSummaryPdf. The deferred IPC message arrives
// via setImmediate after the browser instance has already been disposed.
if (err.message?.includes('was not bound in the connection')) {
consoleLogger.info(`Suppressed Playwright post-close connection error: ${err.message}`);
return;
}
throw err;
};
process.on('uncaughtException', psTreeHandler);
Expand Down
12 changes: 12 additions & 0 deletions src/constants/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1497,6 +1497,18 @@ export const getBrowserToRun = (
* after checkingUrl and unable to utilise same cookie for scan
* */
export const getClonedProfilesWithRandomToken = (browser: string, randomToken: string): string => {
// In Docker, redirect browser temp files away from /tmp to avoid ENOSPC.
// Keep the path short — Chrome creates Unix sockets inside TMPDIR-based paths,
// and socket paths are limited to 107 bytes on Linux.
if (fs.existsSync('/.dockerenv')) {
const baseDir = getDefaultChromiumDataDir();
if (baseDir) {
const scanTmpDir = path.join(baseDir, 'tmp');
fs.mkdirSync(scanTmpDir, { recursive: true });
process.env.TMPDIR = scanTmpDir;
}
}

if (browser === BrowserTypes.CHROME) {
return cloneChromeProfiles(randomToken);
}
Expand Down
14 changes: 13 additions & 1 deletion src/generateHtmlReport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,18 @@ export const generateHtmlReport = async (
const scanData = JSON.parse(await fs.readFile(scanDataJsonPath, 'utf8'));
const scanItemsAll = JSON.parse(await fs.readFile(scanItemsJsonPath, 'utf8'));

// Disk space: passed may be absent from scanItems.json (excluded to reduce disk usage).
// Provide an empty-category fallback so convertItemsToReferences does not crash.
// To revert (when passed is restored in scanItems.json), remove this block.
if (!scanItemsAll.passed) {
scanItemsAll.passed = {
description: itemTypeDescription.passed,
totalItems: 0,
totalRuleIssues: 0,
rules: [],
};
}

// Build the lighter scanItems payload used by the HTML report.
const lightScanItemsPayload = convertItemsToReferences({
items: scanItemsAll,
Expand All @@ -141,7 +153,7 @@ export const generateHtmlReport = async (
mustFix: ensureCategory(mustFix, 'mustFix'),
goodToFix: ensureCategory(goodToFix, 'goodToFix'),
needsReview: ensureCategory(needsReview, 'needsReview'),
passed: ensureCategory(scanItemsAll.passed || {}, 'passed'),
passed: ensureCategory(scanItemsAll.passed, 'passed'),
};

const pagesScanned = Array.isArray(scanData.pagesScanned) ? scanData.pagesScanned : [];
Expand Down
6 changes: 6 additions & 0 deletions src/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ export const errorsTxtPath = path.join(basePath, `${uuid}.txt`);

const consoleLogger = createLogger({
silent: !(process.env.RUNNING_FROM_PH_GUI || process.env.OOBEE_VERBOSE),
// exitOnError: false — Winston logs uncaught exceptions but does not call process.exit().
// Process lifecycle is controlled by psTreeHandler in combine.ts, which suppresses known
// benign errors (e.g. Playwright post-close connection errors) and rethrows real ones.
exitOnError: false,
format: combine(timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), logFormat),
transports: [
new transports.Console({ level: 'info' }),
Expand All @@ -54,6 +58,8 @@ const consoleLogger = createLogger({
// Also used in common functions to not link internal information
// if running from mass scanner, log out errors in console
const silentLogger = createLogger({
// exitOnError: false — see consoleLogger comment above.
exitOnError: false,
format: combine(timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), logFormat),
transports: [
new transports.File({
Expand Down
51 changes: 36 additions & 15 deletions src/mergeAxeResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,11 @@ const writeSummaryPdf = async (
browser: string,
_userDataDirectory: string,
) => {
// Flush stale browser temp files before launching PDF browser
if (process.env.TMPDIR) {
fs.emptyDirSync(process.env.TMPDIR);
}

const renderPdfWithBrowser = async (browserToUse: string) => {
let browserInstance;
let context;
Expand Down Expand Up @@ -525,26 +530,40 @@ const pushResults = async (pageResults, allIssues, isCustomFlow, itemsStore: Ite
metadata,
itemsCount: items.length,
};
await itemsStore.appendPageItems(category, rule, {
url,
pageTitle,
items,
pageIndex,
pageImagePath,
metadata,
});
// Disk space: skip storing passed items in itemsStore.
// To revert, remove the `if` guard and use the original call directly:
// await itemsStore.appendPageItems(category, rule, {
// url, pageTitle, items, pageIndex, pageImagePath, metadata,
// });
if (category !== 'passed') {
await itemsStore.appendPageItems(category, rule, {
url,
pageTitle,
items,
pageIndex,
pageImagePath,
metadata,
});
}
} else if (!(url in currRuleFromAllIssues.pagesAffected)) {
currRuleFromAllIssues.pagesAffected[url] = {
pageTitle,
itemsCount: items.length,
...(filePath && { filePath }),
};
await itemsStore.appendPageItems(category, rule, {
url,
pageTitle,
items,
...(filePath && { filePath }),
});
// Disk space: skip storing passed items in itemsStore.
// To revert, remove the `if` guard and use the original call directly:
// await itemsStore.appendPageItems(category, rule, {
// url, pageTitle, items, ...(filePath && { filePath }),
// });
if (category !== 'passed') {
await itemsStore.appendPageItems(category, rule, {
url,
pageTitle,
items,
...(filePath && { filePath }),
});
}
}
}
}
Expand Down Expand Up @@ -924,7 +943,9 @@ const generateArtifacts = async (
populateScanPagesDetail(allIssues);

// Build htmlGroups in a second pass from disk-backed items
for (const category of ['mustFix', 'goodToFix', 'needsReview', 'passed'] as const) {
// Disk space: 'passed' removed from this loop (no items stored in itemsStore for passed).
// To revert, restore: ['mustFix', 'goodToFix', 'needsReview', 'passed']
for (const category of ['mustFix', 'goodToFix', 'needsReview'] as const) {
for (const rule of allIssues.items[category].rules) {
for await (const entry of itemsStore.readRuleItems(category, rule.rule)) {
buildHtmlGroups(rule, entry.items, entry.url);
Expand Down
7 changes: 6 additions & 1 deletion src/mergeAxeResults/jsonArtifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,14 @@ const writeJsonAndBase64Files = async (
const { items, ...rest } = allIssues;
const { jsonFilePath: scanDataJsonFilePath, base64FilePath: scanDataBase64FilePath } =
await writeJsonFileAndCompressedJsonFile(rest, storagePath, 'scanData');
// Disk space: passed items excluded from scanItems.json to reduce disk usage.
// Passed counts are still in scanData.json and the embedded report payload (scanItems-light).
// To revert, remove the destructure line and restore the original argument:
// { oobeeAppVersion: allIssues.oobeeAppVersion, ...items }
const { passed: _passedItems, ...itemsWithoutPassed } = items;
const { jsonFilePath: scanItemsJsonFilePath, base64FilePath: scanItemsBase64FilePath } =
await writeJsonFileAndCompressedJsonFile(
{ oobeeAppVersion: allIssues.oobeeAppVersion, ...items },
{ oobeeAppVersion: allIssues.oobeeAppVersion, ...itemsWithoutPassed },
storagePath,
'scanItems',
itemsStore,
Expand Down
6 changes: 6 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,12 @@ export const cleanUp = async (randomToken?: string, isError: boolean = false): P
consoleLogger.warn(`Unable to force remove userDataDirectory: ${error.message}`);
}

if (process.env.TMPDIR) try {
fs.rmSync(process.env.TMPDIR, { recursive: true, force: true });
} catch (error) {
consoleLogger.warn(`Unable to force remove browser tmp dir: ${error.message}`);
}

if (randomToken !== undefined) {
const storagePath = getStoragePath(randomToken);

Expand Down