Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add Kubernetes configs detection logic
- Loading branch information
Showing
4 changed files
with
162 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
//TODO(orka): take out into a new lib | ||
import * as YAML from 'js-yaml'; | ||
import * as debugLib from 'debug'; | ||
import { | ||
IllegalCloudConfigFileError, | ||
NotSupportedCloudConfigFileError, | ||
} from './../errors'; | ||
|
||
const debug = debugLib('snyk-detect'); | ||
|
||
const mandatoryKeysForSupportedK8sKinds = { | ||
deployment: ['apiVersion', 'metadata', 'spec'], | ||
pod: ['apiVersion', 'metadata', 'spec'], | ||
service: ['apiVersion', 'metadata', 'spec'], | ||
podsecuritypolicy: ['apiVersion', 'metadata', 'spec'], | ||
networkpolicy: ['apiVersion', 'metadata', 'spec'], | ||
}; | ||
|
||
function getFileType(filePath: string): string { | ||
const filePathSplit = filePath.split('.'); | ||
return filePathSplit[filePathSplit.length - 1].toLowerCase(); | ||
} | ||
|
||
function parseYamlOrJson(fileContent: string, filePath: string): any { | ||
const fileType = getFileType(filePath); | ||
switch (fileType) { | ||
case 'yaml': | ||
case 'yml': | ||
try { | ||
return YAML.safeLoadAll(fileContent); | ||
} catch (e) { | ||
debug('Failed to parse cloud config as a YAML'); | ||
} | ||
break; | ||
case 'json': | ||
try { | ||
const objectsArr: any[] = []; | ||
objectsArr.push(JSON.parse(fileContent)); | ||
return objectsArr; | ||
} catch (e) { | ||
debug('Failed to parse cloud config as a JSON'); | ||
} | ||
break; | ||
default: | ||
debug(`Unsupported cloud config file type (${fileType})`); | ||
} | ||
return undefined; | ||
} | ||
|
||
// This function validates that there is at least one valid doc with a k8s object kind. | ||
// A valid k8s object has a kind key (.kind) from the keys of `mandatoryKeysForSupportedK8sKinds` | ||
// and all of the keys from `mandatoryKeysForSupportedK8sKinds[kind]`. | ||
// If there is a doc with a supported kind, but invalid, we should fail | ||
// The function return true if the yaml is a valid k8s one, or false otherwise | ||
export function validateK8sFile( | ||
fileContent: string, | ||
filePath: string, | ||
root: string, | ||
) { | ||
const k8sObjects: any[] = parseYamlOrJson(fileContent, filePath); | ||
if (!k8sObjects) { | ||
throw IllegalCloudConfigFileError([root]); | ||
} | ||
|
||
let numOfSupportedKeyDocs = 0; | ||
for (let i = 0; i < k8sObjects.length; i++) { | ||
const k8sObject = k8sObjects[i]; | ||
if (!k8sObject || !k8sObject.kind) { | ||
continue; | ||
} | ||
|
||
const kind = k8sObject.kind.toLowerCase(); | ||
if (!Object.keys(mandatoryKeysForSupportedK8sKinds).includes(kind)) { | ||
continue; | ||
} | ||
|
||
numOfSupportedKeyDocs++; | ||
|
||
for (let i = 0; i < mandatoryKeysForSupportedK8sKinds[kind].length; i++) { | ||
const key = mandatoryKeysForSupportedK8sKinds[kind][i]; | ||
if (!k8sObject[key]) { | ||
debug(`Missing key (${key}) from supported k8s object kind (${kind})`); | ||
throw IllegalCloudConfigFileError([root]); | ||
} | ||
} | ||
} | ||
|
||
if (numOfSupportedKeyDocs === 0) { | ||
throw NotSupportedCloudConfigFileError([root]); | ||
} | ||
|
||
debug(`k8s config found (${filePath})`); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import chalk from 'chalk'; | ||
import { CustomError } from './custom-error'; | ||
|
||
export function NotSupportedCloudConfigFileError(atLocations: string[]) { | ||
const locationsStr = atLocations.join(', '); | ||
const errorMsg = | ||
'Not supported Cloud Config target files in ' + | ||
locationsStr + | ||
'.\nPlease see our documentation for supported languages and ' + | ||
'target files: ' + | ||
chalk.underline( | ||
'https://support.snyk.io/hc/en-us/articles/360000911957-Language-support', | ||
) + | ||
' and make sure you are in the right directory.'; | ||
|
||
const error = new CustomError(errorMsg); | ||
error.code = 422; | ||
error.userMessage = errorMsg; | ||
return error; | ||
} | ||
|
||
export function IllegalCloudConfigFileError( | ||
atLocations: string[], | ||
): CustomError { | ||
const locationsStr = atLocations.join(', '); | ||
const errorMsg = | ||
'Illegal Cloud Config target file ' + | ||
locationsStr + | ||
'.\nPlease see our documentation for supported languages and ' + | ||
'target files: ' + | ||
chalk.underline( | ||
'https://support.snyk.io/hc/en-us/articles/360000911957-Language-support', | ||
) + | ||
' and make sure you are in the right directory.'; | ||
|
||
const error = new CustomError(errorMsg); | ||
error.code = 422; | ||
error.userMessage = errorMsg; | ||
return error; | ||
} |