@jrpool/kilotest 37.1.0 → 38.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/{reportList/api.js → api/reportList.js} +36 -28
- package/api/reportSummary.js +181 -0
- package/diagnoses/index.js +39 -5
- package/docs/decisions/001-api-design.md +2 -2
- package/index.js +26 -26
- package/issues/index.js +31 -10
- package/llms-full.txt +15 -15
- package/llms.txt +2 -2
- package/mcp.js +25 -19
- package/openapi.yaml +125 -70
- package/package.json +1 -1
- package/reannotate/index.js +10 -2
- package/reannotateForm/index.js +19 -4
- package/reportHideForm/index.js +20 -1
- package/reportIssue/api.js +28 -9
- package/reportIssue/index.js +39 -7
- package/reportIssues/index.js +26 -14
- package/reportIssues/util.js +27 -8
- package/reportUnhideForm/index.js +20 -2
- package/reportsExpungeForm/index.js +9 -1
- package/reportsPruneForm/index.js +11 -1
- package/reportsRewindForm/index.js +9 -1
- package/researchAgent.js +38 -29
- package/retestRec/index.js +11 -2
- package/retestRecForm/index.js +5 -0
- package/target/api.js +46 -35
- package/targets/index.js +20 -1
- package/testRecForm/api.js +2 -2
- package/util.js +63 -48
- package/reportIssues/api.js +0 -129
package/reportIssue/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
index.js
|
|
3
|
-
Answers the
|
|
3
|
+
Answers the reportIssue question.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// IMPORTS
|
|
@@ -25,10 +25,26 @@ const path = require('path');
|
|
|
25
25
|
|
|
26
26
|
// Adds parameters to a query for the answer page.
|
|
27
27
|
const populateQuery = async (issueID, timeStamp, jobID, query) => {
|
|
28
|
-
//
|
|
29
|
-
query.issue = issues[issueID].summary;
|
|
28
|
+
// Get descriptions of the page facts.
|
|
30
29
|
const pageDataStrings = await getPageDataStrings(timeStamp, jobID);
|
|
31
|
-
|
|
30
|
+
// If this failed:
|
|
31
|
+
if (pageDataStrings.error) {
|
|
32
|
+
// Populate the query with the reason.
|
|
33
|
+
query.error = pageDataStrings.error;
|
|
34
|
+
// Stop populating the query.
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Otherwise, i.e. if it succeeded, add the issue summary to the query.
|
|
38
|
+
query.issue = issues[issueID]?.summary;
|
|
39
|
+
// If adding the issue summary failed:
|
|
40
|
+
if (! query.issue) {
|
|
41
|
+
// Populate the query with the reason.
|
|
42
|
+
query.error = 'Issue not found';
|
|
43
|
+
// Stop populating the query.
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const {testInfo, url, urlLink, what} = pageDataStrings;
|
|
47
|
+
// Add page facts to the query.
|
|
32
48
|
query.target = what;
|
|
33
49
|
query.urlLink = urlLink;
|
|
34
50
|
query.testInfo = testInfo;
|
|
@@ -44,6 +60,14 @@ const populateQuery = async (issueID, timeStamp, jobID, query) => {
|
|
|
44
60
|
// Get the report.
|
|
45
61
|
const report = await getReport(timeStamp, jobID);
|
|
46
62
|
const {acts, catalog} = report;
|
|
63
|
+
// If this failed:
|
|
64
|
+
if (report.error) {
|
|
65
|
+
// Populate the query with the reason.
|
|
66
|
+
query.error = report.error;
|
|
67
|
+
// Stop populating the query.
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// Otherwise, i.e. if it succeeded, get the test acts of the report.
|
|
47
71
|
const testActs = acts.filter(act => act.type === 'test');
|
|
48
72
|
// For each test act:
|
|
49
73
|
testActs.forEach(act => {
|
|
@@ -159,7 +183,15 @@ exports.answer = async pageArgs => {
|
|
|
159
183
|
const query = {};
|
|
160
184
|
// Create a query to replace the placeholders.
|
|
161
185
|
await populateQuery(issueID, timeStamp, jobID, query);
|
|
162
|
-
// If
|
|
186
|
+
// If this failed:
|
|
187
|
+
if (query.error) {
|
|
188
|
+
// Return the error.
|
|
189
|
+
return {
|
|
190
|
+
status: 'error',
|
|
191
|
+
message: query.error
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
// Otherwise, if it succeeded and the report facts were obtained:
|
|
163
195
|
if (query.testInfo) {
|
|
164
196
|
// Get the template.
|
|
165
197
|
let answerPage = await fs.readFile(path.join(__dirname, 'index.html'), 'utf8');
|
|
@@ -173,9 +205,9 @@ exports.answer = async pageArgs => {
|
|
|
173
205
|
answerPage
|
|
174
206
|
};
|
|
175
207
|
}
|
|
176
|
-
// Otherwise, report this.
|
|
208
|
+
// Otherwise, i.e. if the report facts were not obtained, report this.
|
|
177
209
|
return {
|
|
178
210
|
status: 'error',
|
|
179
|
-
message: '
|
|
211
|
+
message: 'Report facts not obtained'
|
|
180
212
|
};
|
|
181
213
|
};
|
package/reportIssues/index.js
CHANGED
|
@@ -24,20 +24,24 @@ const populateQuery = async (timeStamp, jobID, query) => {
|
|
|
24
24
|
// Get data on the target and its issues according to the report.
|
|
25
25
|
const data = await getData(timeStamp, jobID);
|
|
26
26
|
const {pageData, issuesData} = data;
|
|
27
|
-
// If
|
|
28
|
-
if (
|
|
29
|
-
//
|
|
30
|
-
|
|
27
|
+
// If this failed:
|
|
28
|
+
if (data.error) {
|
|
29
|
+
// Populate the query with the reason.
|
|
30
|
+
query.error = data.error;
|
|
31
|
+
// Stop populating the query.
|
|
32
|
+
return;
|
|
31
33
|
}
|
|
32
|
-
// Otherwise, if
|
|
33
|
-
if (typeof issuesData === 'string') {
|
|
34
|
-
// Return this.
|
|
35
|
-
return issuesData;
|
|
36
|
-
}
|
|
37
|
-
// Otherwise, get fact descriptions for the target.
|
|
34
|
+
// Otherwise, i.e. if it succeeded, get fact descriptions for the target.
|
|
38
35
|
const pageInfo = await getPageDataStrings(timeStamp, jobID, pageData);
|
|
39
|
-
const {
|
|
40
|
-
//
|
|
36
|
+
const {testInfo, urlLink, what} = pageInfo;
|
|
37
|
+
// If this failed:
|
|
38
|
+
if (pageInfo.error) {
|
|
39
|
+
// Populate the query with the reason.
|
|
40
|
+
query.error = pageInfo.error;
|
|
41
|
+
// Stop populating the query.
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Otherwise, i.e. if it succeeded, add target data to the query.
|
|
41
45
|
query.target = what;
|
|
42
46
|
query.urlLink = urlLink;
|
|
43
47
|
query.testInfo = testInfo;
|
|
@@ -154,7 +158,15 @@ exports.answer = async pageArgs => {
|
|
|
154
158
|
const query = {};
|
|
155
159
|
// Create a query to replace the placeholders.
|
|
156
160
|
await populateQuery(timeStamp, jobID, query);
|
|
157
|
-
// If
|
|
161
|
+
// If this failed:
|
|
162
|
+
if (query.error) {
|
|
163
|
+
// Return the error.
|
|
164
|
+
return {
|
|
165
|
+
status: 'error',
|
|
166
|
+
message: query.error
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
// Otherwise, if it succeeded and the report facts were obtained:
|
|
158
170
|
if (query.testInfo) {
|
|
159
171
|
// Get the template.
|
|
160
172
|
let answerPage = await fs.readFile(path.join(__dirname, 'index.html'), 'utf8');
|
|
@@ -171,6 +183,6 @@ exports.answer = async pageArgs => {
|
|
|
171
183
|
// Otherwise, i.e. if they were not obtained, report this.
|
|
172
184
|
return {
|
|
173
185
|
status: 'error',
|
|
174
|
-
message: 'Report
|
|
186
|
+
message: 'Report facts not obtained'
|
|
175
187
|
};
|
|
176
188
|
};
|
package/reportIssues/util.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// IMPORTS
|
|
7
7
|
|
|
8
8
|
const {
|
|
9
|
-
getPageData, getReport, getToolsData, getToolList, isValidReport, objectSort
|
|
9
|
+
getPageData, getReport, getToolsData, getToolList, isHidden, isValidReport, objectSort
|
|
10
10
|
} = require('../util');
|
|
11
11
|
const issuesClassification = require('testilo/procs/score/tic').issues;
|
|
12
12
|
|
|
@@ -16,7 +16,12 @@ const issuesClassification = require('testilo/procs/score/tic').issues;
|
|
|
16
16
|
const getIssuesData = async (timeStamp, jobID) => {
|
|
17
17
|
// Get the report.
|
|
18
18
|
const report = await getReport(timeStamp, jobID);
|
|
19
|
-
|
|
19
|
+
const reportIsHidden = await isHidden(timeStamp, jobID);
|
|
20
|
+
// If it exists and is hidden:
|
|
21
|
+
if (reportIsHidden) {
|
|
22
|
+
return {error: 'Report is not available'}
|
|
23
|
+
}
|
|
24
|
+
// Otherwise, if it exists and is valid:
|
|
20
25
|
if (isValidReport(report)) {
|
|
21
26
|
// Initialize the temporary data.
|
|
22
27
|
const temp = {
|
|
@@ -110,10 +115,24 @@ const getIssuesData = async (timeStamp, jobID) => {
|
|
|
110
115
|
// Return the data.
|
|
111
116
|
return final;
|
|
112
117
|
}
|
|
113
|
-
// Otherwise, i.e. if it is invalid, return this.
|
|
114
|
-
return
|
|
118
|
+
// Otherwise, i.e. if it is invalid or does not exist, return this.
|
|
119
|
+
return {error: 'Report missing or invalid.'};
|
|
120
|
+
};
|
|
121
|
+
// Get page and issues data from a report.
|
|
122
|
+
exports.getData = async (timeStamp, jobID) => {
|
|
123
|
+
const pageData = await getPageData(timeStamp, jobID);
|
|
124
|
+
const issuesData = await getIssuesData(timeStamp, jobID);
|
|
125
|
+
const pageError = pageData.error || '';
|
|
126
|
+
const issuesError = issuesData.error || '';
|
|
127
|
+
const errors = [pageError, issuesError].filter(Boolean).join('; ');
|
|
128
|
+
// If the data of either type are missing or invalid:
|
|
129
|
+
if (errors) {
|
|
130
|
+
// Return this.
|
|
131
|
+
return {error: errors};
|
|
132
|
+
}
|
|
133
|
+
// Otherwise, return the data.
|
|
134
|
+
return {
|
|
135
|
+
pageData,
|
|
136
|
+
issuesData
|
|
137
|
+
};
|
|
115
138
|
};
|
|
116
|
-
exports.getData = async (timeStamp, jobID) => ({
|
|
117
|
-
pageData: await getPageData(timeStamp, jobID),
|
|
118
|
-
issuesData: await getIssuesData(timeStamp, jobID)
|
|
119
|
-
});
|
|
@@ -22,7 +22,15 @@ exports.answer = async (_, search) => {
|
|
|
22
22
|
if (authCode === process.env.AUTH_CODE) {
|
|
23
23
|
// Get the log of the report.
|
|
24
24
|
const log = await getLog(... jobName.split('-'));
|
|
25
|
-
//
|
|
25
|
+
// If this failed:
|
|
26
|
+
if (log.error) {
|
|
27
|
+
// Return why.
|
|
28
|
+
return {
|
|
29
|
+
status: 'error',
|
|
30
|
+
message: log.error
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Otherwise, i.e. if it succeeded, reverse the hiddenness property of the log.
|
|
26
34
|
log.hidden = false;
|
|
27
35
|
// Save the updated log.
|
|
28
36
|
await fs.writeFile(path.join(logsPath, `${jobName}.json`), getJSON(log));
|
|
@@ -37,13 +45,23 @@ exports.answer = async (_, search) => {
|
|
|
37
45
|
}
|
|
38
46
|
}
|
|
39
47
|
const reportFileNames = await fs.readdir(reportsPath);
|
|
48
|
+
// Initialize an array of report specifications.
|
|
40
49
|
const reportSpecs = [];
|
|
41
50
|
// For each report:
|
|
42
51
|
for (const reportFileName of reportFileNames) {
|
|
43
52
|
const [timeStamp, jobID] = reportFileName.slice(0, -5).split('-');
|
|
44
53
|
// Get its log.
|
|
45
54
|
const log = await getLog(timeStamp, jobID);
|
|
46
|
-
const {what, hidden} = log;
|
|
55
|
+
const {error, what, hidden} = log;
|
|
56
|
+
// If this failed:
|
|
57
|
+
if (error) {
|
|
58
|
+
// Return why.
|
|
59
|
+
return {
|
|
60
|
+
status: 'error',
|
|
61
|
+
message: error
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Otherwise, i.e. if it succeeded, add the report to the array.
|
|
47
65
|
reportSpecs.push({
|
|
48
66
|
what,
|
|
49
67
|
timeStamp,
|
|
@@ -44,7 +44,15 @@ exports.answer = async (_, search) => {
|
|
|
44
44
|
const [timeStamp, jobID] = reportName.slice(0, -5).split('-');
|
|
45
45
|
// Get a summary of it.
|
|
46
46
|
const reportSummary = await getReportData(timeStamp, jobID);
|
|
47
|
-
const {issueCount, preventedToolCount, url} = reportSummary;
|
|
47
|
+
const {error, issueCount, preventedToolCount, url} = reportSummary;
|
|
48
|
+
// If this failed:
|
|
49
|
+
if (error) {
|
|
50
|
+
// Return why.
|
|
51
|
+
return {
|
|
52
|
+
status: 'error',
|
|
53
|
+
message: error
|
|
54
|
+
}
|
|
55
|
+
}
|
|
48
56
|
reportSpecs.push({
|
|
49
57
|
timeStamp,
|
|
50
58
|
jobID,
|
|
@@ -38,13 +38,23 @@ exports.answer = async (_, search) => {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
const reportNames = await fs.readdir(reportsPath);
|
|
41
|
+
// Initialize an array of report summaries.
|
|
41
42
|
const reportSpecs = [];
|
|
42
43
|
// For each report:
|
|
43
44
|
for (const reportName of reportNames) {
|
|
44
45
|
const [timeStamp, jobID] = reportName.slice(0, -5).split('-');
|
|
45
46
|
// Get a summary of it.
|
|
46
47
|
const reportSummary = await getReportData(timeStamp, jobID);
|
|
47
|
-
const {issueCount, preventedToolCount, url} = reportSummary;
|
|
48
|
+
const {error, issueCount, preventedToolCount, url} = reportSummary;
|
|
49
|
+
// If this failed:
|
|
50
|
+
if (error) {
|
|
51
|
+
// Return why.
|
|
52
|
+
return {
|
|
53
|
+
status: 'error',
|
|
54
|
+
message: error
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Otherwise, i.e. if it succeeded, add the summary to the array.
|
|
48
58
|
reportSpecs.push({
|
|
49
59
|
timeStamp,
|
|
50
60
|
jobID,
|
|
@@ -44,7 +44,15 @@ exports.answer = async (_, search) => {
|
|
|
44
44
|
const [timeStamp, jobID] = reportName.slice(0, -5).split('-');
|
|
45
45
|
// Get a summary of it.
|
|
46
46
|
const reportSummary = await getReportData(timeStamp, jobID);
|
|
47
|
-
const {issueCount, preventedToolCount, url} = reportSummary;
|
|
47
|
+
const {error, issueCount, preventedToolCount, url} = reportSummary;
|
|
48
|
+
// If this failed:
|
|
49
|
+
if (error) {
|
|
50
|
+
// Return why.
|
|
51
|
+
return {
|
|
52
|
+
status: 'error',
|
|
53
|
+
message: error
|
|
54
|
+
}
|
|
55
|
+
}
|
|
48
56
|
reportSpecs.push({
|
|
49
57
|
timeStamp,
|
|
50
58
|
jobID,
|
package/researchAgent.js
CHANGED
|
@@ -80,11 +80,10 @@ const getRequestOptions = (path, method = 'GET') => ({
|
|
|
80
80
|
}
|
|
81
81
|
});
|
|
82
82
|
// Submits a request, returns the response content, and increments the results.
|
|
83
|
-
const submitRequest = async (
|
|
83
|
+
const submitRequest = async (path, method, body = null) => new Promise(resolve => {
|
|
84
84
|
console.log(`Making ${scheme} ${method} request on port ${port} to ${host}${path}`);
|
|
85
85
|
client.request(getRequestOptions(path, method), async response => {
|
|
86
86
|
const responseContent = await getContent(response);
|
|
87
|
-
results.push(responseContent.error ? 'bad' : 'good');
|
|
88
87
|
resolve(responseContent);
|
|
89
88
|
})
|
|
90
89
|
.on('error', error => {
|
|
@@ -104,26 +103,25 @@ const requestService = async () => {
|
|
|
104
103
|
let jobID;
|
|
105
104
|
let description;
|
|
106
105
|
let url;
|
|
107
|
-
|
|
108
|
-
console.log('======================\nRequest 1: Summarize nonexistent reports');
|
|
106
|
+
console.log('======================\nRequest: Summarize nonexistent reports');
|
|
109
107
|
method = 'POST';
|
|
110
108
|
path = '/api/target';
|
|
111
|
-
content = await submitRequest(
|
|
112
|
-
|
|
109
|
+
content = await submitRequest(path, method, {
|
|
110
|
+
description: 'oesntuhaesouht',
|
|
113
111
|
hostname: 'osentuhaoesuht.aoesntuh'
|
|
114
112
|
});
|
|
115
113
|
if (content.error) {
|
|
116
114
|
return;
|
|
117
115
|
}
|
|
118
|
-
console.log('======================\nRequest
|
|
116
|
+
console.log('======================\nRequest: List all available reports');
|
|
119
117
|
method = 'GET';
|
|
120
118
|
path = '/api/reportList';
|
|
121
|
-
content = await submitRequest(
|
|
122
|
-
reports = content?.['
|
|
119
|
+
content = await submitRequest(path, method);
|
|
120
|
+
reports = content?.['response content'] ?? [];
|
|
123
121
|
if (content.error || ! Array.isArray(reports) || ! reports.length) {
|
|
124
122
|
return;
|
|
125
123
|
}
|
|
126
|
-
console.log('======================\nRequest
|
|
124
|
+
console.log('======================\nRequest: Summarize matching reports');
|
|
127
125
|
// Choose one available report at random.
|
|
128
126
|
report = reports[Math.floor(Math.random() * reports.length)];
|
|
129
127
|
({description, URL: url} = report?.['tested web page'] ?? ['', '']);
|
|
@@ -132,61 +130,72 @@ const requestService = async () => {
|
|
|
132
130
|
}
|
|
133
131
|
method = 'POST';
|
|
134
132
|
path = '/api/target';
|
|
135
|
-
content = await submitRequest(
|
|
136
|
-
|
|
133
|
+
content = await submitRequest(path, method, {
|
|
134
|
+
description,
|
|
137
135
|
hostname: new URL(url).hostname ?? ''
|
|
138
136
|
});
|
|
139
137
|
if (content.error) {
|
|
140
138
|
return;
|
|
141
139
|
}
|
|
142
|
-
console.log('======================\nRequest
|
|
140
|
+
console.log('======================\nRequest: Summarize one nonexistent report');
|
|
141
|
+
[timeStamp, jobID] = ['111111T1111', 'abc'];
|
|
142
|
+
method = 'GET';
|
|
143
|
+
path = `/api/reportSummary/${timeStamp}/${jobID}`;
|
|
144
|
+
content = await submitRequest(path, method);
|
|
145
|
+
if (! content.message) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
console.log('======================\nRequest: Summarize one report');
|
|
143
149
|
[timeStamp, jobID] = report.identifier?.split('-') ?? ['', ''];
|
|
144
150
|
if (! (timeStamp && jobID)) {
|
|
145
151
|
return;
|
|
146
152
|
}
|
|
147
153
|
method = 'GET';
|
|
148
|
-
path = `/api/
|
|
149
|
-
content = await submitRequest(
|
|
150
|
-
if (content.
|
|
154
|
+
path = `/api/reportSummary/${timeStamp}/${jobID}`;
|
|
155
|
+
content = await submitRequest(path, method);
|
|
156
|
+
if (content.message || ! content.summary) {
|
|
151
157
|
return;
|
|
152
158
|
}
|
|
153
|
-
console.log('======================\nRequest
|
|
154
|
-
if (content['number of
|
|
159
|
+
console.log('======================\nRequest: Describe one issue from one report');
|
|
160
|
+
if (content['response content']['number of elements reported as violators'] === 0) {
|
|
155
161
|
console.log('reportIssue request cannot be submitted, because no issues were reported');
|
|
156
162
|
}
|
|
157
163
|
else {
|
|
158
164
|
// Get the issue IDs.
|
|
159
165
|
const issueIDs = Object
|
|
160
|
-
.values(content['issues
|
|
161
|
-
.map(
|
|
162
|
-
.flat();
|
|
166
|
+
.values(content['response content']['issues revealed'])
|
|
167
|
+
.map(issue => issue.identifier);
|
|
163
168
|
// Choose one at random.
|
|
164
169
|
const issueID = issueIDs[Math.floor(Math.random() * issueIDs.length)];
|
|
165
170
|
method = 'GET';
|
|
166
171
|
path = `/api/reportIssue/${issueID}/${timeStamp}/${jobID}`;
|
|
167
|
-
content = await submitRequest(
|
|
168
|
-
if (content.
|
|
172
|
+
content = await submitRequest(path, method);
|
|
173
|
+
if (content.message) {
|
|
169
174
|
return;
|
|
170
175
|
}
|
|
171
176
|
}
|
|
172
|
-
console.log('======================\nRequest
|
|
177
|
+
console.log('======================\nRequest: Make a permitted test recommendation');
|
|
173
178
|
method = 'POST';
|
|
174
179
|
path = '/api/testRecForm';
|
|
175
|
-
content = await submitRequest(
|
|
180
|
+
content = await submitRequest(path, method, {
|
|
176
181
|
'description of the web page': 'aoseeou',
|
|
177
182
|
'URL of the web page': 'https://oaaestuh.osneth',
|
|
178
183
|
'reason for testing the web page': 'Just testing'
|
|
179
184
|
});
|
|
180
|
-
if (content.
|
|
185
|
+
if (content.message) {
|
|
181
186
|
return;
|
|
182
187
|
}
|
|
183
|
-
console.log('======================\nRequest
|
|
184
|
-
await submitRequest(
|
|
188
|
+
console.log('======================\nRequest: Make an illicit test recommendation');
|
|
189
|
+
content = await submitRequest(path, method, {
|
|
185
190
|
'description of the web page': description,
|
|
186
191
|
'URL of the web page': url,
|
|
187
192
|
'reason for testing the web page': 'Just testing'
|
|
188
193
|
});
|
|
189
|
-
|
|
194
|
+
if (! content.message) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
console.log('======================\nRequest: Results');
|
|
198
|
+
console.log('All tests succeeded');
|
|
190
199
|
};
|
|
191
200
|
|
|
192
201
|
// EXECUTION
|
package/retestRec/index.js
CHANGED
|
@@ -12,8 +12,17 @@ const {getLog, processRec} = require('../util');
|
|
|
12
12
|
// Records a retest recommendation and returns an acknowledgement page.
|
|
13
13
|
exports.answer = async (pageArgs, why) => {
|
|
14
14
|
const [timeStamp, jobID] = pageArgs.split('/');
|
|
15
|
+
// Get the log of the specified report.
|
|
15
16
|
const log = await getLog(timeStamp, jobID);
|
|
16
|
-
const {url, what} = log;
|
|
17
|
-
//
|
|
17
|
+
const {error, url, what} = log;
|
|
18
|
+
// If this failed:
|
|
19
|
+
if (error) {
|
|
20
|
+
// Return why.
|
|
21
|
+
return {
|
|
22
|
+
status: 'error',
|
|
23
|
+
message: error
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// Otherwise, i.e. if it succeeded, process the recommendation.
|
|
18
27
|
return await processRec('retest', __dirname, what, url, why);
|
|
19
28
|
};
|
package/retestRecForm/index.js
CHANGED
|
@@ -15,6 +15,11 @@ const path = require('path');
|
|
|
15
15
|
exports.answer = async pageArgs => {
|
|
16
16
|
const [timeStamp, jobID] = pageArgs.split('/');
|
|
17
17
|
const log = await getLog(timeStamp, jobID);
|
|
18
|
+
// If this failed:
|
|
19
|
+
if (log.error) {
|
|
20
|
+
// Make the form report the failure.
|
|
21
|
+
log.what = 'The specified page is not available for retesting';
|
|
22
|
+
}
|
|
18
23
|
const query = {
|
|
19
24
|
target: log.what,
|
|
20
25
|
timeStamp,
|
package/target/api.js
CHANGED
|
@@ -21,9 +21,10 @@ const thisHost = process.env.THIS_KILOTEST_HOST;
|
|
|
21
21
|
|
|
22
22
|
// Returns a response to a target request.
|
|
23
23
|
exports.response = async args => {
|
|
24
|
-
const [
|
|
24
|
+
const [description = '', hostname = ''] = args;
|
|
25
25
|
const hostLC = hostname.toLowerCase();
|
|
26
|
-
const whatLC =
|
|
26
|
+
const whatLC = description.toLowerCase();
|
|
27
|
+
// Initialize an array of summaries of matching reports.
|
|
27
28
|
const matchingReports = [];
|
|
28
29
|
// Get the non-hidden logs.
|
|
29
30
|
const targetLogs = await getLogs();
|
|
@@ -42,6 +43,7 @@ exports.response = async args => {
|
|
|
42
43
|
// Get data about its report.
|
|
43
44
|
const data = await getReportData(timeStamp, jobID);
|
|
44
45
|
const {
|
|
46
|
+
error,
|
|
45
47
|
creationDate,
|
|
46
48
|
daysAgo,
|
|
47
49
|
issueCount,
|
|
@@ -53,35 +55,44 @@ exports.response = async args => {
|
|
|
53
55
|
preventedToolNames,
|
|
54
56
|
preventedToolCount
|
|
55
57
|
} = data;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
'
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
58
|
+
// If this failed:
|
|
59
|
+
if (error) {
|
|
60
|
+
// Report why.
|
|
61
|
+
console.error(error);
|
|
62
|
+
}
|
|
63
|
+
// Otherwise, i.e. if it succeeded:
|
|
64
|
+
else {
|
|
65
|
+
// Add a report summary to the array.
|
|
66
|
+
matchingReports.push({
|
|
67
|
+
identifier: jobName,
|
|
68
|
+
'creation date': creationDate,
|
|
69
|
+
'days since the creation date': daysAgo,
|
|
70
|
+
'tested web page': {
|
|
71
|
+
description: reportWhat,
|
|
72
|
+
URL: reportURL
|
|
73
|
+
},
|
|
74
|
+
'whether a later report about the same page exists': !! superseded,
|
|
75
|
+
'rule engines that tried to test the page': {
|
|
76
|
+
number: toolCount,
|
|
77
|
+
names: toolNames
|
|
78
|
+
},
|
|
79
|
+
'rule engines that were unable to test the page': {
|
|
80
|
+
number: preventedToolCount,
|
|
81
|
+
names: preventedToolNames
|
|
82
|
+
},
|
|
83
|
+
'rule engines that reported issues': {
|
|
84
|
+
number: reporterCount,
|
|
85
|
+
names: reporterNames
|
|
86
|
+
},
|
|
87
|
+
'number of issues reported': issueCount,
|
|
88
|
+
'number of HTML elements reported as exhibiting issues': violatorCount,
|
|
89
|
+
'URLs for getting data about the reported issues': {
|
|
90
|
+
'for you': `${thisHost}/api/reportSummary/${timeStamp}/${jobID}`,
|
|
91
|
+
'for humans': `${thisHost}/reportIssues.html/${timeStamp}/${jobID}`
|
|
92
|
+
},
|
|
93
|
+
'URL for getting the full technical report as JSON': `${thisHost}/fullReport.json/${timeStamp}/${jobID}`
|
|
94
|
+
});
|
|
95
|
+
}
|
|
85
96
|
}
|
|
86
97
|
}
|
|
87
98
|
// Get a response.
|
|
@@ -96,12 +107,12 @@ exports.response = async args => {
|
|
|
96
107
|
},
|
|
97
108
|
method: 'POST',
|
|
98
109
|
payload: {
|
|
99
|
-
|
|
100
|
-
|
|
110
|
+
description,
|
|
111
|
+
hostname
|
|
101
112
|
},
|
|
102
113
|
URLs: {
|
|
103
|
-
'
|
|
104
|
-
'
|
|
114
|
+
'for you': `${thisHost}/api/target`,
|
|
115
|
+
'for humans': 'none'
|
|
105
116
|
},
|
|
106
117
|
'closest ancestor request': null
|
|
107
118
|
},
|
package/targets/index.js
CHANGED
|
@@ -80,8 +80,10 @@ const populateQuery = async query => {
|
|
|
80
80
|
for (const targetLog of targetLogs) {
|
|
81
81
|
const {jobName, url, what} = targetLog;
|
|
82
82
|
const [timeStamp, jobID] = jobName.split('-');
|
|
83
|
+
// Get data about its report.
|
|
83
84
|
const reportData = await getReportData(timeStamp, jobID);
|
|
84
85
|
const {
|
|
86
|
+
error,
|
|
85
87
|
issueCount,
|
|
86
88
|
preventedToolCount,
|
|
87
89
|
preventedToolNames,
|
|
@@ -89,6 +91,15 @@ const populateQuery = async query => {
|
|
|
89
91
|
reporterCount,
|
|
90
92
|
violatorCount
|
|
91
93
|
} = reportData;
|
|
94
|
+
// If this failed:
|
|
95
|
+
if (error) {
|
|
96
|
+
console.error(error);
|
|
97
|
+
// Populate the query with the reason.
|
|
98
|
+
query.error = error;
|
|
99
|
+
// Stop populating the query.
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// Otherwise, i.e. if it succeeded, add lines about the report.
|
|
92
103
|
lines.tested.push(`${margin}<details>`);
|
|
93
104
|
const daysAgo = getAgoDays(timeStamp);
|
|
94
105
|
const pageDataStrings = await getPageDataStrings(timeStamp, jobID, {what, url, daysAgo});
|
|
@@ -155,7 +166,15 @@ exports.answer = async () => {
|
|
|
155
166
|
const query = {};
|
|
156
167
|
// Create a query to replace placeholders.
|
|
157
168
|
await populateQuery(query);
|
|
158
|
-
//
|
|
169
|
+
// If the query reports an error:
|
|
170
|
+
if (query.error) {
|
|
171
|
+
// Return it.
|
|
172
|
+
return {
|
|
173
|
+
status: 'error',
|
|
174
|
+
message: query.error
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
// Otherwise, i.e. if it does not report an error, get the template.
|
|
159
178
|
let answerPage = await fs.readFile(path.join(__dirname, 'index.html'), 'utf8');
|
|
160
179
|
// Replace its placeholders.
|
|
161
180
|
Object.keys(query).forEach(param => {
|
package/testRecForm/api.js
CHANGED
|
@@ -41,8 +41,8 @@ exports.response = async (what, url, why) => {
|
|
|
41
41
|
'reason for testing the web page': why
|
|
42
42
|
},
|
|
43
43
|
URLs: {
|
|
44
|
-
'
|
|
45
|
-
'
|
|
44
|
+
'for you': `${thisHost}/api/testRecForm`,
|
|
45
|
+
'for humans': `${thisHost}/testRecForm.html`
|
|
46
46
|
},
|
|
47
47
|
'closest ancestor request': null
|
|
48
48
|
},
|