@jrpool/kilotest 35.0.1 → 35.1.0
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/SERVICE.md +6 -0
- package/ai0BalanceForm/index.js +2 -2
- package/diagnoses/index.js +1 -1
- package/index.js +34 -18
- package/package.json +1 -1
- package/reannotate/index.js +1 -1
- package/reportHideForm/index.js +1 -1
- package/reportIssue/index.js +1 -1
- package/reportIssues/index.js +1 -1
- package/reportUnhideForm/index.js +1 -1
- package/reportsExpungeForm/index.js +1 -1
- package/reportsPruneForm/index.js +1 -1
- package/reportsRewindForm/index.js +1 -1
- package/researchAgent.js +1 -1
- package/style.css +1 -1
- package/targets/index.js +0 -1
- package/testOrder/index.js +1 -1
- package/testRec/index.js +1 -1
- package/tutorial/index.js +2 -2
- package/util.js +1 -1
- package/wcagRenew/index.js +3 -3
package/SERVICE.md
CHANGED
|
@@ -20,6 +20,8 @@ Any other application `xyz` can be installed at `/opt/jpdev/xyz` on the server.
|
|
|
20
20
|
|
|
21
21
|
## Process management
|
|
22
22
|
|
|
23
|
+
### Process manager
|
|
24
|
+
|
|
23
25
|
Kilotest is managed with [PM2](https://pm2.keymetrics.io) on the server (not on the local development host). The PM2 configuration is specified in the repository as `pm2.config.js`:
|
|
24
26
|
|
|
25
27
|
```javascript
|
|
@@ -49,6 +51,10 @@ pm2 restart kilotest --time --update-env
|
|
|
49
51
|
pm2 save
|
|
50
52
|
```
|
|
51
53
|
|
|
54
|
+
The management of the PM2 logs is [documented by PM2](https://pm2.keymetrics.io/docs/usage/log-management/).
|
|
55
|
+
|
|
56
|
+
### Process tuning
|
|
57
|
+
|
|
52
58
|
The server configuration has been tuned for improved performance. The file edited for this purpose is `/etc/default/zramswap`:
|
|
53
59
|
|
|
54
60
|
```properties
|
package/ai0BalanceForm/index.js
CHANGED
|
@@ -47,7 +47,7 @@ exports.answer = async (_, search) => {
|
|
|
47
47
|
// Report the error.
|
|
48
48
|
return {
|
|
49
49
|
status: 'error',
|
|
50
|
-
|
|
50
|
+
message: 'Invalid authorization code'
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -60,7 +60,7 @@ exports.answer = async (_, search) => {
|
|
|
60
60
|
oldBalance = `$${balanceData.balance} is the`;
|
|
61
61
|
}
|
|
62
62
|
// If the balance file does not exist or is invalid:
|
|
63
|
-
catch
|
|
63
|
+
catch {
|
|
64
64
|
oldBalance = 'There is no';
|
|
65
65
|
}
|
|
66
66
|
}
|
package/diagnoses/index.js
CHANGED
package/index.js
CHANGED
|
@@ -80,7 +80,8 @@ const AI_MODEL0_OUTPUT_PRICE = Number(process.env.AI_MODEL0_OUTPUT_PRICE);
|
|
|
80
80
|
|
|
81
81
|
// Serves or sends an error message.
|
|
82
82
|
const serveError = async (error, response, isHumanUser = true) => {
|
|
83
|
-
|
|
83
|
+
const errorLines = Object.entries(error).map(pair => `${pair[0]}: ${pair[1]}`);
|
|
84
|
+
console.log(errorLines.join('\n') || 'ERROR');
|
|
84
85
|
if (! response.writableEnded) {
|
|
85
86
|
response.statusCode = 400;
|
|
86
87
|
// If the request is from a human user:
|
|
@@ -128,7 +129,7 @@ const checkBalancesForAlerts = async report => {
|
|
|
128
129
|
// Get the recorded AI service 0 balance.
|
|
129
130
|
balanceJSON = await fs.readFile(balancePath, 'utf8');
|
|
130
131
|
}
|
|
131
|
-
catch
|
|
132
|
+
catch {
|
|
132
133
|
console.error('ERROR: AI service 0 balance file missing');
|
|
133
134
|
}
|
|
134
135
|
// If the variables required for an AI service 0 balance alert are defined:
|
|
@@ -169,6 +170,21 @@ const checkBalancesForAlerts = async report => {
|
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
172
|
};
|
|
173
|
+
// Creates an error object about a suspicious request.
|
|
174
|
+
const getAbuseError = (request, reason) => {
|
|
175
|
+
const {method, url, headers} = request;
|
|
176
|
+
const ip = headers['x-forwarded-for'] || request.socket.remoteAddress || 'unknown';
|
|
177
|
+
return {
|
|
178
|
+
message: 'Invalid request',
|
|
179
|
+
reason,
|
|
180
|
+
'IP address': ip,
|
|
181
|
+
method,
|
|
182
|
+
URL: url,
|
|
183
|
+
'user agent': headers['user-agent'] || 'none',
|
|
184
|
+
referer: headers.referer || 'none',
|
|
185
|
+
time: new Date().toISOString()
|
|
186
|
+
};
|
|
187
|
+
};
|
|
172
188
|
// Handles a request.
|
|
173
189
|
const requestHandler = async (request, response) => {
|
|
174
190
|
// Sets response headers.
|
|
@@ -260,17 +276,17 @@ const requestHandler = async (request, response) => {
|
|
|
260
276
|
// If the report exists and is hidden:
|
|
261
277
|
if (reportHidden === true) {
|
|
262
278
|
console.log(`ERROR: Hidden report ${timeStamp}-${jobID} requested`);
|
|
263
|
-
// Report this.
|
|
279
|
+
// Report this as suspected abuse.
|
|
264
280
|
await serveError(
|
|
265
|
-
|
|
281
|
+
getAbuseError(request, `Requested report ${timeStamp}-${jobID} not available`),
|
|
266
282
|
response,
|
|
267
283
|
true
|
|
268
284
|
);
|
|
269
285
|
}
|
|
270
|
-
// Otherwise, if
|
|
286
|
+
// Otherwise, if the report does not exist or another error occurred:
|
|
271
287
|
else if (typeof reportHidden === 'string') {
|
|
272
|
-
// Report
|
|
273
|
-
await serveError(
|
|
288
|
+
// Report this as suspected abuse.
|
|
289
|
+
await serveError(getAbuseError(request, reportHidden), response, true);
|
|
274
290
|
}
|
|
275
291
|
// Otherwise, i.e. if the report log is valid and not hidden:
|
|
276
292
|
else {
|
|
@@ -314,14 +330,14 @@ const requestHandler = async (request, response) => {
|
|
|
314
330
|
}
|
|
315
331
|
// Otherwise, i.e. if they are invalid:
|
|
316
332
|
else {
|
|
317
|
-
// Report the error.
|
|
318
|
-
await serveError(
|
|
333
|
+
// Report the error as suspected abuse.
|
|
334
|
+
await serveError(getAbuseError(request, answerData.message), response, true);
|
|
319
335
|
}
|
|
320
336
|
}
|
|
321
337
|
// Otherwise, i.e. if the answer cannot be generated:
|
|
322
338
|
else {
|
|
323
|
-
// Report the error.
|
|
324
|
-
await serveError(
|
|
339
|
+
// Report the error as suspected abuse.
|
|
340
|
+
await serveError(getAbuseError(request, 'Request for nonexistent page'), response, true);
|
|
325
341
|
}
|
|
326
342
|
}
|
|
327
343
|
// Otherwise, if it is for an API service:
|
|
@@ -377,7 +393,7 @@ const requestHandler = async (request, response) => {
|
|
|
377
393
|
setHeaders(mimeTypes[ext] || 'application/octet-stream', null, 'low');
|
|
378
394
|
response.end(img);
|
|
379
395
|
}
|
|
380
|
-
catch
|
|
396
|
+
catch {
|
|
381
397
|
await serveError({message: 'ERROR: Image not found'}, response, true);
|
|
382
398
|
}
|
|
383
399
|
}
|
|
@@ -439,7 +455,7 @@ const requestHandler = async (request, response) => {
|
|
|
439
455
|
// Otherwise, i.e. if they are invalid:
|
|
440
456
|
else {
|
|
441
457
|
// Report the error.
|
|
442
|
-
await serveError({message: answerData.
|
|
458
|
+
await serveError({message: answerData.message}, response, true);
|
|
443
459
|
}
|
|
444
460
|
}
|
|
445
461
|
// Otherwise, i.e. if the request is invalid:
|
|
@@ -473,7 +489,7 @@ const requestHandler = async (request, response) => {
|
|
|
473
489
|
// Otherwise, i.e. if they are invalid:
|
|
474
490
|
else {
|
|
475
491
|
// Report the error.
|
|
476
|
-
await serveError({message: answerData.
|
|
492
|
+
await serveError({message: answerData.message}, response, true);
|
|
477
493
|
}
|
|
478
494
|
}
|
|
479
495
|
}
|
|
@@ -506,7 +522,7 @@ const requestHandler = async (request, response) => {
|
|
|
506
522
|
// Otherwise, i.e. if they are invalid:
|
|
507
523
|
else {
|
|
508
524
|
// Report the error.
|
|
509
|
-
await serveError({message: answerData.
|
|
525
|
+
await serveError({message: answerData.message}, response, true);
|
|
510
526
|
}
|
|
511
527
|
}
|
|
512
528
|
// Otherwise, i.e. if it is a rejection:
|
|
@@ -547,7 +563,7 @@ const requestHandler = async (request, response) => {
|
|
|
547
563
|
// Otherwise, i.e. if they are invalid:
|
|
548
564
|
else {
|
|
549
565
|
// Report the error.
|
|
550
|
-
await serveError({message: answerData.
|
|
566
|
+
await serveError({message: answerData.message}, response, true);
|
|
551
567
|
}
|
|
552
568
|
}
|
|
553
569
|
// Otherwise, if it is a WCAG map renewal:
|
|
@@ -566,7 +582,7 @@ const requestHandler = async (request, response) => {
|
|
|
566
582
|
// Otherwise, i.e. if they are invalid:
|
|
567
583
|
else {
|
|
568
584
|
// Report the error.
|
|
569
|
-
await serveError({message: answerData.
|
|
585
|
+
await serveError({message: answerData.message}, response, true);
|
|
570
586
|
}
|
|
571
587
|
}
|
|
572
588
|
// Otherwise, if it is a request from an agent:
|
|
@@ -753,7 +769,7 @@ const requestHandler = async (request, response) => {
|
|
|
753
769
|
}
|
|
754
770
|
else {
|
|
755
771
|
response.statusCode = 400;
|
|
756
|
-
response.end(JSON.stringify({status: 'error', message: answerData.
|
|
772
|
+
response.end(JSON.stringify({status: 'error', message: answerData.message}));
|
|
757
773
|
}
|
|
758
774
|
}
|
|
759
775
|
// Otherwise, i.e. if it is any other POST request:
|
package/package.json
CHANGED
package/reannotate/index.js
CHANGED
package/reportHideForm/index.js
CHANGED
package/reportIssue/index.js
CHANGED
package/reportIssues/index.js
CHANGED
package/researchAgent.js
CHANGED
package/style.css
CHANGED
package/targets/index.js
CHANGED
package/testOrder/index.js
CHANGED
package/testRec/index.js
CHANGED
|
@@ -17,7 +17,7 @@ exports.answer = async (what, url, why) => {
|
|
|
17
17
|
// Return an answer reporting this.
|
|
18
18
|
return {
|
|
19
19
|
status: 'error',
|
|
20
|
-
|
|
20
|
+
message: `Page is already ${status}`
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
// Otherwise, i.e. if it is recommendable, process the recommendation.
|
package/tutorial/index.js
CHANGED
|
@@ -33,11 +33,11 @@ exports.answer = async () => {
|
|
|
33
33
|
// Sanitizes and saves a tutorial comment to comments.json.
|
|
34
34
|
exports.saveComment = async content => {
|
|
35
35
|
if (!content || typeof content !== 'string') {
|
|
36
|
-
return {status: 'error',
|
|
36
|
+
return {status: 'error', message: 'No content provided'};
|
|
37
37
|
}
|
|
38
38
|
const sanitized = sanitize(content);
|
|
39
39
|
if (!sanitized) {
|
|
40
|
-
return {status: 'error',
|
|
40
|
+
return {status: 'error', message: 'Comment is empty after sanitization'};
|
|
41
41
|
}
|
|
42
42
|
let comments = [];
|
|
43
43
|
try {
|
package/util.js
CHANGED
|
@@ -679,7 +679,7 @@ exports.processRec = async (testType, dirName, what, url, why) => {
|
|
|
679
679
|
}
|
|
680
680
|
return {
|
|
681
681
|
status: 'error',
|
|
682
|
-
|
|
682
|
+
message: 'Invalid recommendation'
|
|
683
683
|
};
|
|
684
684
|
};
|
|
685
685
|
// Gets the WCAG Understanding link for a numeric WCAG standard identifier.
|
package/wcagRenew/index.js
CHANGED
|
@@ -50,21 +50,21 @@ exports.answer = async authCode => {
|
|
|
50
50
|
// Report this.
|
|
51
51
|
return {
|
|
52
52
|
status: 'error',
|
|
53
|
-
|
|
53
|
+
message: 'No entries found in WCAG map source'
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
else {
|
|
58
58
|
return {
|
|
59
59
|
status: 'error',
|
|
60
|
-
|
|
60
|
+
message: 'WCAG map source not retrieved'
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
else {
|
|
65
65
|
return {
|
|
66
66
|
status: 'error',
|
|
67
|
-
|
|
67
|
+
message: 'Authorization code invalid'
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
70
|
};
|