@govtechsg/oobee 0.10.93 → 0.10.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +20 -0
- package/dist/cli.js +3 -2
- package/dist/combine.js +10 -3
- package/dist/constants/common.js +131 -52
- package/dist/crawlers/commonCrawlerFunc.js +11 -2
- package/dist/crawlers/crawlDomain.js +4 -6
- package/dist/crawlers/crawlSitemap.js +14 -2
- package/dist/crawlers/custom/utils.js +22 -9
- package/dist/crawlers/guards/urlGuard.js +19 -1
- package/dist/generateHtmlReport.js +12 -1
- package/dist/logs.js +6 -0
- package/dist/mergeAxeResults/jsonArtifacts.js +6 -1
- package/dist/mergeAxeResults.js +41 -15
- package/dist/static/ejs/partials/components/allIssues/CategoryBadges.ejs +3 -0
- package/dist/static/ejs/partials/components/allIssues/IssuesTable.ejs +3 -3
- package/dist/static/ejs/partials/components/header/aboutScanModal/AboutScanModal.ejs +1 -1
- package/dist/static/ejs/partials/components/header/aboutScanModal/ScanConfiguration.ejs +3 -3
- package/dist/static/ejs/partials/components/header/aboutScanModal/ScanDetails.ejs +34 -27
- package/dist/static/ejs/partials/components/ruleModal/ruleOffcanvas.ejs +1 -0
- package/dist/static/ejs/partials/components/scannedPagesSegmentedTabs.ejs +7 -0
- package/dist/static/ejs/partials/components/wcagCoverageDetails.ejs +5 -5
- package/dist/static/ejs/partials/scripts/header/aboutScanModal/AboutScanModal.ejs +3 -3
- package/dist/static/ejs/partials/scripts/prioritiseIssues/PrioritiseIssues.ejs +21 -19
- package/dist/static/ejs/partials/scripts/ruleModal/pageAccordionBuilder.ejs +39 -8
- package/dist/static/ejs/partials/scripts/scannedPagesSegmentedTabs.ejs +11 -5
- package/dist/static/ejs/partials/scripts/screenshotLightbox.ejs +49 -31
- package/dist/static/ejs/partials/styles/header/SiteInfo.ejs +1 -1
- package/dist/static/ejs/partials/styles/header/aboutScanModal/ScanDetails.ejs +36 -16
- package/dist/static/ejs/partials/styles/prioritiseIssues/PrioritiseIssues.ejs +22 -1
- package/dist/static/ejs/partials/styles/styles.ejs +1 -1
- package/dist/static/ejs/partials/styles/wcagCompliance/WcagGaugeBar.ejs +6 -0
- package/dist/static/ejs/partials/styles/wcagCompliance.ejs +5 -4
- package/dist/static/ejs/partials/styles/wcagCoverageDetails.ejs +6 -1
- package/dist/utils.js +7 -0
- package/oobee-client-scanner.js +2 -2
- package/package.json +1 -1
- package/src/cli.ts +3 -2
- package/src/combine.ts +10 -2
- package/src/constants/common.ts +125 -36
- package/src/crawlers/commonCrawlerFunc.ts +11 -2
- package/src/crawlers/crawlDomain.ts +4 -5
- package/src/crawlers/crawlSitemap.ts +19 -2
- package/src/crawlers/custom/utils.ts +26 -13
- package/src/crawlers/guards/urlGuard.ts +18 -1
- package/src/generateHtmlReport.ts +13 -1
- package/src/logs.ts +6 -0
- package/src/mergeAxeResults/jsonArtifacts.ts +6 -1
- package/src/mergeAxeResults.ts +41 -15
- package/src/static/ejs/partials/components/allIssues/CategoryBadges.ejs +3 -0
- package/src/static/ejs/partials/components/allIssues/IssuesTable.ejs +3 -3
- package/src/static/ejs/partials/components/header/aboutScanModal/AboutScanModal.ejs +1 -1
- package/src/static/ejs/partials/components/header/aboutScanModal/ScanConfiguration.ejs +3 -3
- package/src/static/ejs/partials/components/header/aboutScanModal/ScanDetails.ejs +34 -27
- package/src/static/ejs/partials/components/ruleModal/ruleOffcanvas.ejs +1 -0
- package/src/static/ejs/partials/components/scannedPagesSegmentedTabs.ejs +7 -0
- package/src/static/ejs/partials/components/wcagCoverageDetails.ejs +5 -5
- package/src/static/ejs/partials/scripts/header/aboutScanModal/AboutScanModal.ejs +3 -3
- package/src/static/ejs/partials/scripts/prioritiseIssues/PrioritiseIssues.ejs +21 -19
- package/src/static/ejs/partials/scripts/ruleModal/pageAccordionBuilder.ejs +39 -8
- package/src/static/ejs/partials/scripts/scannedPagesSegmentedTabs.ejs +11 -5
- package/src/static/ejs/partials/scripts/screenshotLightbox.ejs +49 -31
- package/src/static/ejs/partials/styles/header/SiteInfo.ejs +1 -1
- package/src/static/ejs/partials/styles/header/aboutScanModal/ScanDetails.ejs +36 -16
- package/src/static/ejs/partials/styles/prioritiseIssues/PrioritiseIssues.ejs +22 -1
- package/src/static/ejs/partials/styles/styles.ejs +1 -1
- package/src/static/ejs/partials/styles/wcagCompliance/WcagGaugeBar.ejs +6 -0
- package/src/static/ejs/partials/styles/wcagCompliance.ejs +5 -4
- package/src/static/ejs/partials/styles/wcagCoverageDetails.ejs +6 -1
- package/src/utils.ts +6 -0
- package/testStaticJSScanner.html +1 -1
- /package/{7339fae5-e8ed-4b50-af13-317847620dbf.txt → fb5db217-5ab7-4120-b33b-71fa69b454d0.txt} +0 -0
|
@@ -6,18 +6,32 @@
|
|
|
6
6
|
const lightboxContent = document.getElementsByClassName('lightbox-content')[0];
|
|
7
7
|
const lightboxImg = document.getElementById('lightbox-image');
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
// Handle dynamically inserted custom-flow screenshots (about scan modal content is rendered later)
|
|
10
|
+
document.addEventListener(
|
|
11
|
+
'error',
|
|
12
|
+
event => {
|
|
13
|
+
const target = event.target;
|
|
14
|
+
if (target && target.classList && target.classList.contains('custom-flow-screenshot')) {
|
|
15
|
+
target.onerror = null;
|
|
16
|
+
target.remove();
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
true,
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
document.addEventListener('click', event => {
|
|
23
|
+
const screenshot = event.target.closest('.custom-flow-screenshot');
|
|
24
|
+
if (!screenshot) return;
|
|
25
|
+
|
|
26
|
+
event.preventDefault();
|
|
27
|
+
|
|
28
|
+
const container = screenshot.closest('.custom-flow-screenshot-container');
|
|
29
|
+
const link = container ? container.querySelector('.display-url-container a') : null;
|
|
30
|
+
|
|
31
|
+
const pageTitle = link?.textContent?.trim() || screenshot.getAttribute('alt') || 'Screenshot';
|
|
32
|
+
const pageUrl = link?.href || '';
|
|
33
|
+
|
|
34
|
+
openLightbox(screenshot.src, pageTitle, pageUrl);
|
|
21
35
|
});
|
|
22
36
|
|
|
23
37
|
lightbox.addEventListener('click', event => {
|
|
@@ -31,8 +45,9 @@
|
|
|
31
45
|
});
|
|
32
46
|
|
|
33
47
|
const offcanvasElem = document.getElementsByClassName('offcanvas')[0];
|
|
48
|
+
let offcanvasItem = null;
|
|
34
49
|
if (offcanvasElem) {
|
|
35
|
-
|
|
50
|
+
offcanvasItem = new bootstrap.Offcanvas(offcanvasElem);
|
|
36
51
|
offcanvasItem._config.keyboard = false; // Disable default keyboard handling
|
|
37
52
|
}
|
|
38
53
|
|
|
@@ -43,27 +58,30 @@
|
|
|
43
58
|
pagesScannedModalItem._config.keyboard = false;
|
|
44
59
|
}
|
|
45
60
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
// Use capture phase so lightbox handles Escape before Bootstrap modal/offcanvas handlers.
|
|
62
|
+
document.addEventListener(
|
|
63
|
+
'keydown',
|
|
64
|
+
event => {
|
|
65
|
+
if (event.key !== 'Escape') return;
|
|
66
|
+
|
|
67
|
+
if (lightbox.style.display === 'block') {
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
event.stopPropagation();
|
|
70
|
+
event.stopImmediatePropagation();
|
|
71
|
+
closeLightbox();
|
|
72
|
+
return;
|
|
55
73
|
}
|
|
56
74
|
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
event.preventDefault(); // Prevent default bootstrap behaviour
|
|
60
|
-
closeLightbox();
|
|
61
|
-
} else {
|
|
62
|
-
pagesScannedModalItem.hide();
|
|
63
|
-
}
|
|
75
|
+
if (offcanvasItem && offcanvasItem._isShown) {
|
|
76
|
+
offcanvasItem.hide();
|
|
64
77
|
}
|
|
65
|
-
|
|
66
|
-
|
|
78
|
+
|
|
79
|
+
if (pagesScannedModalItem && pagesScannedModalItem._isShown) {
|
|
80
|
+
pagesScannedModalItem.hide();
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
true,
|
|
84
|
+
);
|
|
67
85
|
|
|
68
86
|
function openLightbox(imgSrc, pageTitle, pageUrl) {
|
|
69
87
|
lightbox.style.display = 'block';
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
word-break: break-word;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
#
|
|
7
|
-
|
|
6
|
+
#aboutScanModalLabel {
|
|
7
|
+
margin-bottom: 1rem;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
#scan-about ul {
|
|
10
|
+
#scan-about > ul {
|
|
11
11
|
padding-left: 0;
|
|
12
|
+
padding-top: 0;
|
|
13
|
+
padding-bottom: 1rem;
|
|
14
|
+
margin-top: 0;
|
|
15
|
+
margin-bottom: 0;
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
#scan-about li {
|
|
@@ -38,21 +42,28 @@
|
|
|
38
42
|
margin-bottom: 0.3rem;
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
.advanced-group {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
#scan-about li.advanced-group {
|
|
46
|
+
align-items: flex-start;
|
|
47
|
+
margin-bottom: 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#scan-about li.advanced-group > .advanced-group-content {
|
|
51
|
+
min-width: 0;
|
|
52
|
+
flex: 1;
|
|
45
53
|
}
|
|
46
54
|
|
|
47
|
-
.advanced-group
|
|
48
|
-
|
|
49
|
-
list-style:
|
|
50
|
-
margin-left:
|
|
55
|
+
#scan-about li.advanced-group > .advanced-group-content > ul.advanced-sublist {
|
|
56
|
+
list-style: disc;
|
|
57
|
+
list-style-position: outside;
|
|
58
|
+
margin-left: 8px;
|
|
59
|
+
margin-top: 0.5rem;
|
|
60
|
+
padding-left: 12px;
|
|
61
|
+
text-indent: -2px;
|
|
51
62
|
}
|
|
52
63
|
|
|
53
|
-
.advanced-group
|
|
54
|
-
.advanced-group + ul li {
|
|
64
|
+
#scan-about li.advanced-group > .advanced-group-content > ul.advanced-sublist li {
|
|
55
65
|
margin: 0;
|
|
66
|
+
list-style-position: outside !important;
|
|
56
67
|
}
|
|
57
68
|
|
|
58
69
|
.advanced-sublist-li {
|
|
@@ -85,10 +96,14 @@
|
|
|
85
96
|
|
|
86
97
|
.about-scan-toggle .about-us-type-of-scan-text {
|
|
87
98
|
color: var(--a11y-majorelle-blue) !important;
|
|
88
|
-
display: inline
|
|
89
|
-
text-decoration:
|
|
99
|
+
display: inline;
|
|
100
|
+
text-decoration: underline;
|
|
90
101
|
cursor: pointer;
|
|
91
102
|
}
|
|
103
|
+
|
|
104
|
+
#pagesScannedModalToggleTxt {
|
|
105
|
+
color: var(--a11y-majorelle-blue) !important;
|
|
106
|
+
}
|
|
92
107
|
.about-scan-toggle:hover .about-us-type-of-scan-text,
|
|
93
108
|
.about-scan-toggle .about-us-type-of-scan-text:focus-visible {
|
|
94
109
|
text-decoration: underline;
|
|
@@ -112,9 +127,14 @@
|
|
|
112
127
|
line-height: 1.2;
|
|
113
128
|
}
|
|
114
129
|
|
|
130
|
+
.about-scan-divider-item {
|
|
131
|
+
display: block !important;
|
|
132
|
+
margin-bottom: 2rem !important;
|
|
133
|
+
}
|
|
134
|
+
|
|
115
135
|
.about-scan-link-text {
|
|
116
136
|
color: var(--a11y-majorelle-blue);
|
|
117
|
-
text-decoration:
|
|
137
|
+
text-decoration: underline;
|
|
118
138
|
cursor: pointer;
|
|
119
139
|
}
|
|
120
140
|
|
|
@@ -120,15 +120,36 @@
|
|
|
120
120
|
|
|
121
121
|
.priority-issue-item {
|
|
122
122
|
padding: 0.75rem;
|
|
123
|
-
cursor: pointer;
|
|
124
123
|
position: relative;
|
|
125
124
|
padding-left: 1.5rem;
|
|
125
|
+
display: flex;
|
|
126
|
+
align-items: flex-start;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.priority-issue-action {
|
|
130
|
+
appearance: none;
|
|
131
|
+
border: 0;
|
|
132
|
+
background: transparent;
|
|
133
|
+
width: 100%;
|
|
134
|
+
padding: 0;
|
|
135
|
+
margin: 0;
|
|
136
|
+
display: flex;
|
|
137
|
+
text-align: left;
|
|
138
|
+
cursor: pointer;
|
|
139
|
+
color: inherit;
|
|
140
|
+
line-height: 1.5;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.priority-issue-action > .w-90 {
|
|
144
|
+
width: 100% !important;
|
|
126
145
|
}
|
|
127
146
|
|
|
128
147
|
.priority-issue-item::before {
|
|
129
148
|
counter-increment: issue-counter;
|
|
130
149
|
content: counter(issue-counter) '.';
|
|
131
150
|
line-height: 1.5;
|
|
151
|
+
margin-right: 0.5rem;
|
|
152
|
+
flex-shrink: 0;
|
|
132
153
|
}
|
|
133
154
|
|
|
134
155
|
.priority-issue-item:hover:not(.active) {
|
|
@@ -39,6 +39,11 @@
|
|
|
39
39
|
.gauge-number {
|
|
40
40
|
font-weight: 700;
|
|
41
41
|
font-size: 16px;
|
|
42
|
+
color: var(--dark-charcoal, #1f1f1f);
|
|
43
|
+
background-color: var(--true-white, #fff);
|
|
44
|
+
display: inline-block;
|
|
45
|
+
padding: 2px 8px;
|
|
46
|
+
border-radius: 999px;
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
.gauge-caption {
|
|
@@ -54,6 +59,7 @@
|
|
|
54
59
|
|
|
55
60
|
.gauge-value-number {
|
|
56
61
|
font-size: 24px;
|
|
62
|
+
color: var(--dark-charcoal, #1f1f1f);
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
.gauge-value-number.perfect-score {
|
|
@@ -12,9 +12,14 @@
|
|
|
12
12
|
gap: 10px 18px;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
#wcagCoverage .wcag-criteria-heading {
|
|
16
|
+
font-size: 1.25rem;
|
|
17
|
+
line-height: 1.2;
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
#wcagCoverage .wcag-grid a {
|
|
16
21
|
color: var(--a11y-majorelle-blue, #5735DF);
|
|
17
|
-
text-decoration:
|
|
22
|
+
text-decoration: underline;
|
|
18
23
|
}
|
|
19
24
|
#wcagCoverage .wcag-grid a:hover,
|
|
20
25
|
#wcagCoverage .wcag-grid a:focus-visible {
|
package/dist/utils.js
CHANGED
|
@@ -345,6 +345,13 @@ export const cleanUp = async (randomToken, isError = false) => {
|
|
|
345
345
|
catch (error) {
|
|
346
346
|
consoleLogger.warn(`Unable to force remove userDataDirectory: ${error.message}`);
|
|
347
347
|
}
|
|
348
|
+
if (process.env.TMPDIR && fs.existsSync('/.dockerenv'))
|
|
349
|
+
try {
|
|
350
|
+
fs.rmSync(process.env.TMPDIR, { recursive: true, force: true });
|
|
351
|
+
}
|
|
352
|
+
catch (error) {
|
|
353
|
+
consoleLogger.warn(`Unable to force remove browser tmp dir: ${error.message}`);
|
|
354
|
+
}
|
|
348
355
|
if (randomToken !== undefined) {
|
|
349
356
|
const storagePath = getStoragePath(randomToken);
|
|
350
357
|
try {
|
package/oobee-client-scanner.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* DO NOT EDIT MANUALLY. Re-generate with: node dist/generateOobeeClientScanner.js
|
|
4
4
|
*
|
|
5
5
|
* Embedded at generation time:
|
|
6
|
-
* App version : 0.10.
|
|
6
|
+
* App version : 0.10.95
|
|
7
7
|
* Sentry DSN : (from OOBEE_SENTRY_DSN env var or constants.ts default)
|
|
8
8
|
* Sentry SDK : @sentry/browser 10.58.0 (loaded from CDN at runtime)
|
|
9
9
|
*
|
|
@@ -34883,7 +34883,7 @@
|
|
|
34883
34883
|
// ── Sentry browser telemetry (Sentry JS SDK, loaded from CDN) ────────────
|
|
34884
34884
|
|
|
34885
34885
|
var _oobeeSentryDsn = "https://3b8c7ee46b06f33815a1301b6713ebc3@o4509047624761344.ingest.us.sentry.io/4509327783559168";
|
|
34886
|
-
var _oobeeAppVersion = "0.10.
|
|
34886
|
+
var _oobeeAppVersion = "0.10.95";
|
|
34887
34887
|
var _oobeeSentryVersion = "10.58.0";
|
|
34888
34888
|
var _oobeeSentryInitialized = false;
|
|
34889
34889
|
var _oobeeSentryLoadPromise = null;
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -264,9 +264,10 @@ const scanInit = async (argvs: Answers): Promise<string> => {
|
|
|
264
264
|
consoleLogger.info(`Connectivity Check HTTP Response Code: ${res.httpStatus}`);
|
|
265
265
|
|
|
266
266
|
if (res.status === statuses.success.code) {
|
|
267
|
-
//
|
|
268
|
-
//
|
|
267
|
+
// Keep browser-resolved URL as entryUrl for downstream scan metadata/events
|
|
268
|
+
// on non-custom scans.
|
|
269
269
|
if (data.type !== ScannerTypes.CUSTOM) {
|
|
270
|
+
data.entryUrl = res.url;
|
|
270
271
|
data.url = res.url;
|
|
271
272
|
}
|
|
272
273
|
if (process.env.OOBEE_VALIDATE_URL) {
|
package/src/combine.ts
CHANGED
|
@@ -45,6 +45,7 @@ const combineRun = async (details: Data, deviceToScan: string) => {
|
|
|
45
45
|
const {
|
|
46
46
|
type,
|
|
47
47
|
url,
|
|
48
|
+
entryUrl,
|
|
48
49
|
nameEmail,
|
|
49
50
|
randomToken,
|
|
50
51
|
deviceChosen,
|
|
@@ -88,6 +89,13 @@ const combineRun = async (details: Data, deviceToScan: string) => {
|
|
|
88
89
|
consoleLogger.info(`Suppressed Crawlee ps-tree locale error: ${err.message}`);
|
|
89
90
|
return;
|
|
90
91
|
}
|
|
92
|
+
// Suppress stale Playwright in-process connection errors that fire asynchronously
|
|
93
|
+
// after the browser is closed in writeSummaryPdf. The deferred IPC message arrives
|
|
94
|
+
// via setImmediate after the browser instance has already been disposed.
|
|
95
|
+
if (err.message?.includes('was not bound in the connection')) {
|
|
96
|
+
consoleLogger.info(`Suppressed Playwright post-close connection error: ${err.message}`);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
91
99
|
throw err;
|
|
92
100
|
};
|
|
93
101
|
process.on('uncaughtException', psTreeHandler);
|
|
@@ -104,8 +112,8 @@ const combineRun = async (details: Data, deviceToScan: string) => {
|
|
|
104
112
|
|
|
105
113
|
// remove basic-auth credentials from URL
|
|
106
114
|
const finalUrl = !(type === ScannerTypes.SITEMAP || type === ScannerTypes.LOCALFILE)
|
|
107
|
-
? new URL(
|
|
108
|
-
: new URL(pathToFileURL(
|
|
115
|
+
? new URL(entryUrl)
|
|
116
|
+
: new URL(pathToFileURL(entryUrl));
|
|
109
117
|
|
|
110
118
|
// Use the string version of finalUrl to reduce logic at submitForm
|
|
111
119
|
const finalUrlString = finalUrl.toString();
|