diff --git a/scanners/web-endpoint-checks/.env.example b/scanners/web-endpoint-checks/.env.example index 4699b15..9609ee4 100644 --- a/scanners/web-endpoint-checks/.env.example +++ b/scanners/web-endpoint-checks/.env.example @@ -1,2 +1,2 @@ NATS_URL=localhost:4222 -API_URL=localhost:4000 +GRAPHQL_URL=http://127.0.0.1:4000/graphql diff --git a/scanners/web-endpoint-checks/index.js b/scanners/web-endpoint-checks/index.js index d08aa43..9bfc662 100644 --- a/scanners/web-endpoint-checks/index.js +++ b/scanners/web-endpoint-checks/index.js @@ -1,24 +1,21 @@ -import { connect, JSONCodec} from 'nats' -import { Database } from "arangojs"; -import { GraphQLClient } from 'graphql-request' -import { getPages} from './src/get-url-slugs.js' +import { connect, JSONCodec } from 'nats' +import { GraphQLClient, gql } from 'graphql-request' +import { getPages } from './src/get-url-slugs.js' import { isWebEndpointType } from './src/check-endpoint-type.js' import { evaluateAccessibility } from './src/accessibility-checks.js' import puppeteer from 'puppeteer'; import 'dotenv-safe/config.js' -const { - NATS_URL, - API_URL, - } = process.env; - -const NATS_SUB_STREAM="EventsScanner" +const { + NATS_URL, + GRAPHQL_URL, + NATS_SUB_STREAM, +} = process.env; + -// API connection -const graphQLClient = new GraphQLClient(API_URL); // NATs connection -const nc = await connect({ servers: NATS_URL,}) +const nc = await connect({ servers: NATS_URL, }) const jc = JSONCodec() const sub = nc.subscribe(NATS_SUB_STREAM) @@ -27,50 +24,78 @@ console.log('🚀 Connected to NATS server - listening on ...', sub.subject, "ch process.on('SIGTERM', () => process.exit(0)) process.on('SIGINT', () => process.exit(0)) -;(async () => { + ; (async () => { + + const browser = await puppeteer.launch({ + executablePath: '/usr/bin/google-chrome', + args: ['--no-sandbox', '--disable-setuid-sandbox'], + headless: "new", + }); - const browser = await puppeteer.launch({ - args: ['--no-sandbox', '--disable-setuid-sandbox'], - headless: 'new' - }); - - for await (const message of sub) { - const webEventPayload = await jc.decode(message.data) - console.log(webEventPayload) - const { webEndpoints } = webEventPayload - - console.log(webEndpoints) + for await (const message of sub) { + const webEventPayload = await jc.decode(message.data) + console.log(webEventPayload) + const { endpoint } = webEventPayload - for (const webEndpoint of webEndpoints) { const pageInstance = await browser.newPage(); await pageInstance.setBypassCSP(true); - if (await isWebEndpointType(webEndpoint, pageInstance)) { //filtering for only web endpoints - const pages = await getPages(webEndpoint, pageInstance, browser); + if (await isWebEndpointType(endpoint, pageInstance)) { //filtering for only web endpoints + const pages = await getPages(endpoint, pageInstance, browser); const webEndpointAxeResults = {} //form response - for (const pageToEvaluate of pages) { console.log('Evaluating page: ', pageToEvaluate) const axeReport = await evaluateAccessibility(pageToEvaluate, pageInstance, browser) - - if (!webEndpointAxeResults[webEndpoint]) { - webEndpointAxeResults[webEndpoint] = {}; - } - webEndpointAxeResults[webEndpoint][pageToEvaluate] = axeReport; + for (let i = 0; i < axeReport.length; i++) { + const camelize = s => s.replace(/-./g, x => x[1].toUpperCase()) + const violation = axeReport[i]; + const violationKey = Object.keys(violation)[0]; + const violationValue = violation[violationKey]; + const violationKeyCamelCase = camelize(violationKey); + if (!webEndpointAxeResults[pageToEvaluate]) { + webEndpointAxeResults[pageToEvaluate] = {} + } + webEndpointAxeResults[pageToEvaluate][violationKeyCamelCase] = { + checkPasses: violationValue.checkPasses, + metadata: violationValue.metadata, + } + } } - // SAVE to ArangoDB through API - // const upsertService = await upsertClonedGitHubScanIntoDatabase(productName, sourceCodeRepository, results, graphQLClient) - - console.log(JSON.stringify(webEndpointAxeResults, null, 2)) - // console.log(webEndpointAxeResults) + const accessibilityPages = Object.keys(webEndpointAxeResults).map(page => { + return { + url: page, + areaAlt: webEndpointAxeResults[page].areaAlt, + ariaBrailleEquivalent: webEndpointAxeResults[page].ariaBrailleEquivalent, + ariaCommandName: webEndpointAxeResults[page].ariaCommandName, + ariaHiddenFocus: webEndpointAxeResults[page].ariaHiddenFocus, + ariaInputField: webEndpointAxeResults[page].ariaInputField, + ariaMeterName: webEndpointAxeResults[page].ariaMeterName, + // ...webEndpointAxeResults[page], + } + }) + const mutation = gql` + mutation { + webEndpoint( + endpoint: { + url: "${endpoint}" + kind: "Web" + accessibility: ${JSON.stringify(accessibilityPages, null, 4).replace(/"([^"]+)":/g, '$1:')} + } + ) + } + `; + // API connection + const graphQLClient = new GraphQLClient(GRAPHQL_URL); + // Write mutation to GraphQL API + const mutationResponse = await graphQLClient.request(mutation); + console.info("wrote mutation to GraphQL API with response", mutationResponse); await pageInstance.close() } } - } - await browser.close() + await browser.close() -})(); + })(); await nc.closed(); \ No newline at end of file