UNPKG

apigeelint

Version:

Node module and tool to lint a bundle for an Apigee API Proxy or sharedflow.

209 lines (196 loc) 7.45 kB
/* Copyright © 2019-2020,2024,2026 Google LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ const lintUtil = require("../lintUtil.js"), xpath = require("xpath"), ruleId = lintUtil.getRuleId(), debug = require("debug")("apigeelint:" + ruleId); const plugin = { ruleId, name: "Check MessageLogging / CloudLogging hygiene", message: "In the MessageLogging policy, the CloudLogging element should use correct hygiene.", fatal: false, severity: 1, // 1=warning, 2=error nodeType: "Policy", enabled: true, }; const onPolicy = function (policy, cb) { let flagged = false; if (policy.getType() === "MessageLogging") { debug(`found policy ${policy.getName()}`); const clElements = xpath.select( "/MessageLogging/CloudLogging", policy.getElement(), ); try { if (clElements && clElements[0]) { debug(`found ${clElements.length} CloudLogging element(s)`); if (clElements[1]) { flagged = true; policy.addMessage({ plugin, message: "Policy has more than one CloudLogging element.", severity: 2, // 1=warning, 2=error line: clElements[1].lineNumber, column: clElements[1].columnNumber, }); } // now check the zeroth element const requiredChildren = ["LogName", "Message"]; const optionalChildren = ["Labels", "ResourceType"]; const validChildren = requiredChildren.concat(optionalChildren); const found = {}; const children = xpath.select(`*`, clElements[0]); children.forEach((child) => { if (validChildren.includes(child.tagName)) { if (found[child.tagName]) { flagged = true; policy.addMessage({ plugin, message: `Found more than one CloudLogging/${child.tagName} element.`, severity: 2, // 1=warning, 2=error line: child.lineNumber, column: child.columnNumber, }); } else { found[child.tagName] = 1; } } else { flagged = true; policy.addMessage({ plugin, message: `Unsupported element <${child.tagName}> inside CloudLogging.`, severity: 2, // 1=warning, 2=error line: child.lineNumber, column: child.columnNumber, }); } }); requiredChildren.forEach((requiredElementName) => { if (!found[requiredElementName]) { flagged = true; policy.addMessage({ plugin, message: `Policy is missing a required Element: CloudLogging/${requiredElementName} element.`, severity: 2, // 1=warning, 2=error line: clElements[0].lineNumber, column: clElements[0].columnNumber, }); } }); if (found.ResourceType) { const rtypeElt = xpath.select(`ResourceType`, clElements[0])[0]; const textValue = rtypeElt.childNodes && rtypeElt.childNodes[0] && rtypeElt.childNodes[0].nodeValue; debug(`rtypeElt textValue '${textValue}'`); if (!textValue || !textValue.trim()) { flagged = true; policy.addMessage({ plugin, message: `ResourceType element is present but empty. Remove it or specify 'global'.`, severity: 1, // 1=warning, 2=error line: rtypeElt.lineNumber, column: rtypeElt.columnNumber, }); } else if (textValue != "global") { flagged = true; policy.addMessage({ plugin, message: `The value '${textValue}' should not be used here. ResourceType should be 'global'`, severity: 1, // 1=warning, 2=error line: rtypeElt.lineNumber, column: rtypeElt.columnNumber, }); } } if (found.Labels) { // do some checks here const labelsElt = xpath.select(`Labels`, clElements[0])[0]; // the only allowed child of Labels is Label, and that should have just Key + Value const labelsChildren = xpath.select(`*`, labelsElt); labelsChildren.forEach((labelsChild) => { if (labelsChild.tagName != "Label") { flagged = true; policy.addMessage({ plugin, message: `Unsupported element '${labelsChild.tagName}'`, severity: 2, // 1=warning, 2=error line: labelsChild.lineNumber, column: labelsChild.columnNumber, }); } else { // check each child const validLabelChildren = ["Key", "Value"]; const found = {}; xpath.select(`*`, labelsChild).forEach((labelChild) => { if (!validLabelChildren.includes(labelChild.tagName)) { flagged = true; policy.addMessage({ plugin, message: `Unsupported element '${labelChild.tagName}'`, severity: 2, // 1=warning, 2=error line: labelChild.lineNumber, column: labelChild.columnNumber, }); } else { if (found[labelChild.tagName]) { flagged = true; policy.addMessage({ plugin, message: `Found more than one CloudLogging/${labelChild.tagName} element.`, severity: 2, // 1=warning, 2=error line: labelChild.lineNumber, column: labelChild.columnNumber, }); } else { found[labelChild.tagName] = 1; } } }); validLabelChildren.forEach((requiredElementName) => { if (!found[requiredElementName]) { flagged = true; policy.addMessage({ plugin, message: `Label is missing a required Element: ${requiredElementName}.`, severity: 2, // 1=warning, 2=error line: labelsChild.lineNumber, column: labelsChild.columnNumber, }); } }); } }); } } /* c8 ignore start */ } catch (e1) { flagged = true; policy.addMessage({ plugin, message: "Exception while examining CloudLogging element: " + e1.message, }); } /* c8 ignore stop */ } if (typeof cb == "function") { cb(null, flagged); } }; module.exports = { plugin, onPolicy, };