@apistudio/apim-cli
Version:
CLI for API Management Products
527 lines (526 loc) • 24.5 kB
JavaScript
import { AppConstants } from '../constants/app.constants.js';
import yaml from 'js-yaml';
import { UpperCaseKinds } from '../model/interface.js';
import { KindEnums } from '@apic/api-model/common/StudioEnums.js';
import { LogWrapper } from './log-wrapper.js';
/**
* AssetValidator class is responsible to check the basic structure validations for the asset yamls of studio.
*/
export class AssetValidator {
validateAssets(genObj) {
const kind = genObj.kind.toUpperCase();
if (!UpperCaseKinds.includes(kind)) {
LogWrapper.logError('0255', `Unidentified kind: ${genObj.kind}`);
return false;
}
LogWrapper.logInfo('0256', `${genObj.kind}`);
switch (kind) {
case KindEnums.API.toUpperCase():
return this.validateApi(genObj);
case KindEnums.PolicySequence.toUpperCase():
return this.validatePolicySequence(genObj);
case KindEnums.GlobalPolicy.toUpperCase():
return this.validateGlobalPolicy(genObj);
case KindEnums.Scope.toUpperCase():
return this.validateScope(genObj);
case KindEnums.Transport.toUpperCase():
return this.validateTransport(genObj);
case KindEnums.Route.toUpperCase():
return this.validateRoute(genObj);
case KindEnums.SetContextVariable.toUpperCase():
return this.validateSetContextVariable(genObj);
case KindEnums.IdentifyAndAuthorize.toUpperCase():
return this.validateIdentifyAndAuthorize(genObj);
case KindEnums.DataMasking.toUpperCase():
return this.validateDataMasking(genObj);
case KindEnums.WebMethodsISService.toUpperCase():
return this.validateWebMethodsISService(genObj);
case KindEnums.OutboundAlias.toUpperCase():
return this.validateOutboundAlias(genObj);
case KindEnums.OutboundAnonymous.toUpperCase():
return true;
case KindEnums.OutboundBasicAuth.toUpperCase():
return this.validateOutboundBasicAuth(genObj);
case KindEnums.OutboundIncomingJWT.toUpperCase():
return true;
case KindEnums.OutboundKerberosAuth.toUpperCase():
return this.validateOutboundKerberosAuth(genObj);
case KindEnums.OutboundNTLMAuth.toUpperCase():
return this.validateOutboundNTLMAuth(genObj);
case KindEnums.OutboundOAuth2.toUpperCase():
return this.validateOutboundOAuth2(genObj);
case KindEnums.AuthorizeUser.toUpperCase():
return this.validateAuthorizeUser(genObj);
case KindEnums.InboundBulkHead.toUpperCase():
return this.validateInboundBulkHead(genObj);
case KindEnums.InboundMessaging.toUpperCase():
return this.validateInboundMessaging(genObj);
case KindEnums.MessageConfig.toUpperCase():
return this.validateMessageConfig(genObj);
case KindEnums.Tuple.toUpperCase():
return this.validateTuple(genObj);
case KindEnums.CustomHttpHeader.toUpperCase():
return this.validateCustomHttpHeader(genObj);
case KindEnums.SetMediaType.toUpperCase():
return this.validateSetMediaType(genObj);
case KindEnums.Plan.toUpperCase():
return this.validatePlan(genObj);
case KindEnums.Package.toUpperCase():
return this.validatePackage(genObj);
case KindEnums.RequestLimit.toUpperCase():
return this.validateRequestLimit(genObj);
// case KindEnums.Test.toUpperCase():
// return true;
// case KindEnums.HTTPEndpoint.toUpperCase():
// return true;
// case KindEnums.Environment.toUpperCase():
// return true;
default:
LogWrapper.logWarn('0255', `Unimplemented kind: ${kind}`);
return true; // This to be updated to false once all the kinds are incorporated in studio application.
}
}
validateApi(genObj) {
const specObj = JSON.stringify(genObj.spec);
const apiSpec = yaml.load(specObj);
let valid = true;
const policySequence = AppConstants.POLICY_SEQ;
if (apiSpec?.['api-spec'] == null || apiSpec?.[policySequence] == null) {
LogWrapper.logDebug('0003', 'kind API must have api specification some policies');
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateTuple(genObj) {
const specObj = JSON.stringify(genObj.spec);
const tupleSpec = yaml.load(specObj);
let valid = true;
if (tupleSpec?.['value'] == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validatePolicySequence(genObj) {
const specObj = JSON.stringify(genObj.spec);
const policySequenceSpec = yaml.load(specObj);
let valid = true;
// if (policySequenceSpec?.routing == null || policySequenceSpec?.transport == null) {
// LogWrapper.logError('0257', `${genObj.kind}`);
// valid = false;
// }
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateGlobalPolicy(genObj) {
const specObj = JSON.stringify(genObj.spec);
const policySpec = yaml.load(specObj);
let valid = true;
const policySequence = AppConstants.POLICY_SEQ;
if (policySpec?.[policySequence] == null && policySpec?.['filter-attributes'] == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateScope(genObj) {
const specObj = JSON.stringify(genObj.spec);
const scopeSpec = yaml.load(specObj);
let valid = true;
if (scopeSpec?.resources == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
LogWrapper.logDebug('0003', 'Scope must have atleast one resource');
valid = false;
}
else {
for (const resource of scopeSpec.resources) {
if (resource.path == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
LogWrapper.logDebug('0003', 'Resource has no path defined.');
valid = false;
}
}
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateTransport(genObj) {
const specObj = JSON.stringify(genObj.spec);
const tranSpec = yaml.load(specObj);
let valid = true;
if (tranSpec?.protocol == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateSetMediaType(genObj) {
const specObj = JSON.stringify(genObj.spec);
const tranSpec = yaml.load(specObj);
let valid = true;
if (tranSpec?.defaultContentType == null || tranSpec?.defaultAcceptHeader == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validatePlan(genObj) {
const specObj = JSON.stringify(genObj.spec);
const planSpec = yaml.load(specObj);
let valid = true;
if (planSpec?.qos == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validatePackage(genObj) {
const specObj = JSON.stringify(genObj.spec);
const packageSpec = yaml.load(specObj);
let valid = true;
if (packageSpec?.apis == null || packageSpec?.plans == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateRequestLimit(genObj) {
const specObj = JSON.stringify(genObj.spec);
const requestLimitSpec = yaml.load(specObj);
let valid = true;
if (requestLimitSpec?.maxRequest == null || requestLimitSpec?.interval == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateRoute(genObj) {
const specObj = JSON.stringify(genObj.spec);
const routeSpec = yaml.load(specObj);
let valid = true;
const invalidEndpoints = Object.keys(routeSpec ?? {}).filter(key => !AppConstants.ALLOWED_ENDPOINTS.includes(key));
if (routeSpec == null || invalidEndpoints.length > 0) {
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateCustomHttpHeader(genObj) {
const specObj = JSON.stringify(genObj.spec);
const headerSpec = yaml.load(specObj);
let valid = true;
if (headerSpec?.property == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
LogWrapper.logDebug('0003', 'CustomHttpHeader must have atleast one property');
valid = false;
}
else {
for (const prop of headerSpec.property) {
if (prop.key == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
LogWrapper.logDebug('0003', 'Property has no key defined.');
valid = false;
}
if (prop.value == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
LogWrapper.logDebug('0003', 'Property has no value defined.');
valid = false;
}
}
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateSetContextVariable(genObj) {
const specObj = JSON.stringify(genObj.spec);
const setContextVariableSpec = yaml.load(specObj);
let valid = true;
if (setContextVariableSpec.condition == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} must have atleast one condition`);
valid = false;
}
else if (setContextVariableSpec.variable !== undefined) {
for (const variable of setContextVariableSpec.variable) {
if (variable.name == null) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} Context variable must have a name`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
}
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateIdentifyAndAuthorize(genObj) {
const specObj = JSON.stringify(genObj.spec);
const IAMSpec = yaml.load(specObj);
if (IAMSpec.identificationType === undefined) {
LogWrapper.logError('0257', `${genObj.kind}`);
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} must have 'identificationType' specified.`);
return false;
}
if (IAMSpec.identificationType === null) {
LogWrapper.logError('0257', `${genObj.kind}`);
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} must have at least one of 'or' or 'and' specified under identificationType.`);
return false;
}
const hasOr = IAMSpec.identificationType.or;
const hasAnd = IAMSpec.identificationType.and;
if (hasOr !== undefined && hasAnd !== undefined) {
LogWrapper.logError('0257', `${genObj.kind}`);
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} cannot have both 'or' and 'and' specified under identificationType.`);
return false;
}
if (hasOr !== undefined) {
if (hasOr === null) {
LogWrapper.logError('0257', `${genObj.kind}`);
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} 'or' under identificationType must have at least one key-value pair.`);
return false;
}
}
if (hasAnd !== undefined) {
if (hasAnd === null) {
LogWrapper.logError('0257', `${genObj.kind}`);
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} 'and' under identificationType must have at least one key-value pair.`);
return false;
}
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return true;
}
validateDataMasking(genObj) {
const specObj = JSON.stringify(genObj.spec);
const DataMaskingSpec = yaml.load(specObj);
let valid = true;
if (DataMaskingSpec.transformations == null) {
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateWebMethodsISService(genObj) {
const specObj = JSON.stringify(genObj.spec);
const WebMethodsISServiceSpec = yaml.load(specObj);
let valid = true;
if (WebMethodsISServiceSpec.services !== undefined) {
for (const service of WebMethodsISServiceSpec.services) {
if (service.name == null) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} Service must have a name`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
}
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateOutboundAlias(genObj) {
const specObj = JSON.stringify(genObj.spec);
const OutboundAliasSpec = yaml.load(specObj);
let valid = true;
return valid;
}
validateOutboundBasicAuth(genObj) {
const specObj = JSON.stringify(genObj.spec);
const OutboundBasicAuthSpec = yaml.load(specObj);
let valid = true;
if (OutboundBasicAuthSpec.use_incoming_credentials === undefined && OutboundBasicAuthSpec.use_custom_credentials === undefined) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} must have useIncomingCredentials or useCustomCredentials`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
else if (OutboundBasicAuthSpec.use_custom_credentials !== null) {
if (OutboundBasicAuthSpec.use_custom_credentials?.username === null || OutboundBasicAuthSpec.use_custom_credentials?.password === null) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} useCustomCredentials must have username and password`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
}
return valid;
}
validateOutboundKerberosAuth(genObj) {
const specObj = JSON.stringify(genObj.spec);
const OutboundKerberosAuthSpec = yaml.load(specObj);
let valid = true;
if (OutboundKerberosAuthSpec.use_incoming_http_credentials !== undefined) {
valid = valid && this.validateKerberosUseIncomingHttpCredentials(OutboundKerberosAuthSpec, genObj);
}
else if (OutboundKerberosAuthSpec.use_delegate_incoming_credentials !== undefined) {
valid = valid && this.validateKerberosUseDelegateIncomingCredentials(OutboundKerberosAuthSpec, genObj);
}
else if (OutboundKerberosAuthSpec.use_custom_credentials !== undefined) {
valid = valid && this.validateKerberosUseCustomCredentials(OutboundKerberosAuthSpec, genObj);
}
return valid;
}
getNoOfKerberosAuthMethods(OutboundKerberosAuthSpec) {
let count = 0;
if (OutboundKerberosAuthSpec.use_incoming_http_credentials !== undefined) {
count += 1;
}
if (OutboundKerberosAuthSpec.use_custom_credentials !== undefined) {
count += 1;
}
if (OutboundKerberosAuthSpec.use_delegate_incoming_credentials !== undefined) {
count += 1;
}
if (OutboundKerberosAuthSpec.use_incoming_kerbose_credentials !== undefined) {
count += 1;
}
return count;
}
validateKerberosUseCustomCredentials(OutboundKerberosAuthSpec, genObj) {
if (OutboundKerberosAuthSpec.use_custom_credentials.client_principal === null ||
OutboundKerberosAuthSpec.use_custom_credentials.client_password === null ||
OutboundKerberosAuthSpec.use_custom_credentials.service_principal === null ||
OutboundKerberosAuthSpec.use_custom_credentials.service_principal_nameform === null) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} useCustomCredentials must have clientPrincipal, clientPassword
servicePrincipal and servicePrincipalNameFrom`);
LogWrapper.logError('0257', `${genObj.kind}`);
return false;
}
return true;
}
validateKerberosUseDelegateIncomingCredentials(OutboundKerberosAuthSpec, genObj) {
if (OutboundKerberosAuthSpec.use_delegate_incoming_credentials.client_principal === null ||
OutboundKerberosAuthSpec.use_delegate_incoming_credentials.client_password === null ||
OutboundKerberosAuthSpec.use_delegate_incoming_credentials.service_principal === null ||
OutboundKerberosAuthSpec.use_delegate_incoming_credentials.service_principal_nameform === null) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} useDelegateIncomingCredentials must have clientPrincipal, clientPassword
servicePrincipal and servicePrincipalNameFrom`);
LogWrapper.logError('0257', `${genObj.kind}`);
return false;
}
return true;
}
validateKerberosUseIncomingHttpCredentials(OutboundKerberosAuthSpec, genObj) {
if (OutboundKerberosAuthSpec.use_incoming_http_credentials.service_principal === null ||
OutboundKerberosAuthSpec.use_incoming_http_credentials.service_principal_nameform === null) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} useIncomingHttpCredentials must have
servicePrincipal and servicePrincipalNameFrom`);
LogWrapper.logError('0257', `${genObj.kind}`);
return false;
}
return true;
}
validateOutboundNTLMAuth(genObj) {
const specObj = JSON.stringify(genObj.spec);
const OutboundNTLMAuthSpec = yaml.load(specObj);
let valid = true;
if (OutboundNTLMAuthSpec.use_custom_credentials === undefined &&
OutboundNTLMAuthSpec.use_incoming_http_credentials === undefined &&
OutboundNTLMAuthSpec.use_transparent_auth === undefined) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} must have useIncomingHttpCredentials or useCustomCredentials or useTransparentAuth`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
return valid;
}
validateOutboundOAuth2(genObj) {
const specObj = JSON.stringify(genObj.spec);
const OutboundOAuth2Spec = yaml.load(specObj);
let valid = true;
if (OutboundOAuth2Spec.use_incoming_oauth_token === undefined && OutboundOAuth2Spec.use_custom_credentials === undefined) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} must have useIncomingOauthToken or useCustomCredentials`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
else if (OutboundOAuth2Spec.use_custom_credentials !== null) {
if (OutboundOAuth2Spec.use_custom_credentials?.token === null) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} useCustomCredentials must have OAuth Token defined`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
}
return valid;
}
validateAuthorizeUser(genObj) {
const specObj = JSON.stringify(genObj.spec);
const AuthorizeUserSpec = yaml.load(specObj);
let valid = true;
if (AuthorizeUserSpec.users === undefined && AuthorizeUserSpec.teams === undefined && AuthorizeUserSpec.groups === undefined) {
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateInboundBulkHead(genObj) {
const specObj = JSON.stringify(genObj.spec);
const InboundBulkHeadSpec = yaml.load(specObj);
let valid = true;
if (InboundBulkHeadSpec.maxConcurrentCalls == null) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} must have maxConcurrentCalls defined`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
if (InboundBulkHeadSpec.enableBulkheadForCallbacks !== null) {
if (InboundBulkHeadSpec.enableBulkheadForCallbacks?.maxConcurrentCallbacks === null) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} enableBulkheadForCallbacks must have maxConcurrentCallbacks defined`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
}
if (InboundBulkHeadSpec.retryAfterResponseHeader !== null) {
if (InboundBulkHeadSpec.retryAfterResponseHeader?.retryAfterValue === null) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} retryAfterResponseHeader must have retryAfterValue defined`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateInboundMessaging(genObj) {
const specObj = JSON.stringify(genObj.spec);
const InboundMessagingSpec = yaml.load(specObj);
let valid = true;
if (InboundMessagingSpec.alias === undefined) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} must have connection alias defined`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
if (InboundMessagingSpec.source === null) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} must have source defined`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
else {
for (const source of InboundMessagingSpec.source) {
if (source.name == null || source.resource == null || source.type == null) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} Source must have a name, type and resource`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
}
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
validateMessageConfig(genObj) {
const specObj = JSON.stringify(genObj.spec);
const MessageConfigSpec = yaml.load(specObj);
let valid = true;
if (MessageConfigSpec.connectionAlias == null || MessageConfigSpec.destination.name == null ||
MessageConfigSpec.destination.type == null || MessageConfigSpec.deliveryMode == null || MessageConfigSpec.replyTo.type == null ||
MessageConfigSpec.ttl == null || MessageConfigSpec.timeToWait == null) {
LogWrapper.logDebug('0003', `Kind: ${genObj.kind} must have connection Alias, destination name, destination type, replyTo type, ttl, timeToWait and deliveryMode`);
LogWrapper.logError('0257', `${genObj.kind}`);
valid = false;
}
LogWrapper.logInfo('0258', `${genObj.kind}`);
return valid;
}
}