502 lines
22 KiB
JavaScript
502 lines
22 KiB
JavaScript
|
"use strict";
|
||
|
exports.id = 519;
|
||
|
exports.ids = [519];
|
||
|
exports.modules = {
|
||
|
|
||
|
/***/ 41519:
|
||
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
||
|
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||
|
exports.addIacDriftAnalytics = exports.performanceAnalyticsObject = exports.addIacAnalytics = void 0;
|
||
|
const types_1 = __webpack_require__(94820);
|
||
|
const analytics = __webpack_require__(82744);
|
||
|
const file_utils_1 = __webpack_require__(45281);
|
||
|
const driftctl_1 = __webpack_require__(3659);
|
||
|
function addIacAnalytics(formattedResults, opts) {
|
||
|
let totalIssuesCount = 0;
|
||
|
const customRulesIdsFoundInIssues = {};
|
||
|
let issuesFromCustomRulesCount = 0;
|
||
|
const projectTypeAnalytics = {};
|
||
|
const packageManagers = Array();
|
||
|
formattedResults.forEach((res) => {
|
||
|
var _a;
|
||
|
totalIssuesCount =
|
||
|
(totalIssuesCount || 0) + res.result.cloudConfigResults.length;
|
||
|
const projectType = res.packageManager;
|
||
|
packageManagers.push(projectType);
|
||
|
projectTypeAnalytics[projectType] = (_a = projectTypeAnalytics[projectType]) !== null && _a !== void 0 ? _a : {
|
||
|
count: 0,
|
||
|
};
|
||
|
projectTypeAnalytics[projectType]['count']++;
|
||
|
res.result.cloudConfigResults.forEach((policy) => {
|
||
|
projectTypeAnalytics[projectType][policy.severity] =
|
||
|
(projectTypeAnalytics[projectType][policy.severity] || 0) + 1;
|
||
|
if (policy.isGeneratedByCustomRule) {
|
||
|
issuesFromCustomRulesCount++;
|
||
|
customRulesIdsFoundInIssues[policy.publicId] = true;
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
const uniqueCustomRulesCount = Object.keys(customRulesIdsFoundInIssues).length;
|
||
|
analytics.add('packageManager', Array.from(new Set(packageManagers)));
|
||
|
analytics.add('iac-issues-count', totalIssuesCount);
|
||
|
analytics.add('iac-ignored-issues-count', opts.ignoredIssuesCount);
|
||
|
analytics.add('iac-type', projectTypeAnalytics);
|
||
|
analytics.add('iac-metrics', exports.performanceAnalyticsObject);
|
||
|
analytics.add('iac-test-count', formattedResults.length); // TODO: remove this once we all analytics use iac-files-count
|
||
|
analytics.add('iac-files-count', formattedResults.length);
|
||
|
analytics.add('iac-local-custom-rules', opts.rulesOrigin === types_1.RulesOrigin.Local);
|
||
|
analytics.add('iac-remote-custom-rules', opts.rulesOrigin === types_1.RulesOrigin.Remote);
|
||
|
analytics.add('iac-custom-rules-issues-count', issuesFromCustomRulesCount);
|
||
|
analytics.add('iac-custom-rules-checksum', file_utils_1.computeCustomRulesBundleChecksum());
|
||
|
analytics.add('iac-custom-rules-coverage-count', uniqueCustomRulesCount);
|
||
|
}
|
||
|
exports.addIacAnalytics = addIacAnalytics;
|
||
|
exports.performanceAnalyticsObject = {
|
||
|
[types_1.PerformanceAnalyticsKey.InitLocalCache]: null,
|
||
|
[types_1.PerformanceAnalyticsKey.FileLoading]: null,
|
||
|
[types_1.PerformanceAnalyticsKey.FileParsing]: null,
|
||
|
[types_1.PerformanceAnalyticsKey.FileScanning]: null,
|
||
|
[types_1.PerformanceAnalyticsKey.OrgSettings]: null,
|
||
|
[types_1.PerformanceAnalyticsKey.CustomSeverities]: null,
|
||
|
[types_1.PerformanceAnalyticsKey.ResultFormatting]: null,
|
||
|
[types_1.PerformanceAnalyticsKey.UsageTracking]: null,
|
||
|
[types_1.PerformanceAnalyticsKey.CacheCleanup]: null,
|
||
|
[types_1.PerformanceAnalyticsKey.Total]: null,
|
||
|
};
|
||
|
function addIacDriftAnalytics(analysis, options) {
|
||
|
analytics.add('iac-drift-coverage', analysis.coverage);
|
||
|
analytics.add('iac-drift-total-resources', analysis.summary.total_resources);
|
||
|
analytics.add('iac-drift-total-unmanaged', analysis.summary.total_unmanaged);
|
||
|
analytics.add('iac-drift-total-managed', analysis.summary.total_managed);
|
||
|
analytics.add('iac-drift-total-missing', analysis.summary.total_missing);
|
||
|
analytics.add('iac-drift-total-changed', analysis.summary.total_changed);
|
||
|
analytics.add('iac-drift-iac-source-count', analysis.summary.total_iac_source_count);
|
||
|
analytics.add('iac-drift-provider-name', analysis.provider_name);
|
||
|
analytics.add('iac-drift-provider-version', analysis.provider_version);
|
||
|
analytics.add('iac-drift-version', driftctl_1.driftctlVersion);
|
||
|
analytics.add('iac-drift-scan-duration', analysis.scan_duration);
|
||
|
let scope = 'all';
|
||
|
if (options['only-managed']) {
|
||
|
scope = 'managed';
|
||
|
}
|
||
|
else if (options['only-unmanaged']) {
|
||
|
scope = 'unmanaged';
|
||
|
}
|
||
|
analytics.add('iac-drift-scan-scope', scope);
|
||
|
}
|
||
|
exports.addIacDriftAnalytics = addIacDriftAnalytics;
|
||
|
|
||
|
|
||
|
/***/ }),
|
||
|
|
||
|
/***/ 45281:
|
||
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
||
|
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||
|
exports.makeFileAndDirectoryGenerator = exports.computeCustomRulesBundleChecksum = exports.isValidBundle = exports.extractBundle = exports.createIacDir = void 0;
|
||
|
const fs = __webpack_require__(35747);
|
||
|
const tar = __webpack_require__(97998);
|
||
|
const path = __webpack_require__(85622);
|
||
|
const crypto = __webpack_require__(76417);
|
||
|
const local_cache_1 = __webpack_require__(50089);
|
||
|
const oci_pull_1 = __webpack_require__(166);
|
||
|
const fs_1 = __webpack_require__(35747);
|
||
|
const path_1 = __webpack_require__(85622);
|
||
|
function hashData(s) {
|
||
|
const hashedData = crypto
|
||
|
.createHash('sha1')
|
||
|
.update(s)
|
||
|
.digest('hex');
|
||
|
return hashedData;
|
||
|
}
|
||
|
function createIacDir() {
|
||
|
// this path will be able to be customised by the user in the future
|
||
|
const iacPath = path.join(local_cache_1.LOCAL_POLICY_ENGINE_DIR);
|
||
|
try {
|
||
|
if (!fs.existsSync(iacPath)) {
|
||
|
fs.mkdirSync(iacPath, '700');
|
||
|
}
|
||
|
fs.accessSync(iacPath, fs.constants.W_OK);
|
||
|
}
|
||
|
catch {
|
||
|
throw new local_cache_1.FailedToInitLocalCacheError();
|
||
|
}
|
||
|
}
|
||
|
exports.createIacDir = createIacDir;
|
||
|
function extractBundle(response) {
|
||
|
return new Promise((resolve, reject) => {
|
||
|
response
|
||
|
.on('error', reject)
|
||
|
.pipe(tar.x({
|
||
|
C: path.join(local_cache_1.LOCAL_POLICY_ENGINE_DIR),
|
||
|
}))
|
||
|
.on('finish', resolve)
|
||
|
.on('error', reject);
|
||
|
});
|
||
|
}
|
||
|
exports.extractBundle = extractBundle;
|
||
|
function isValidBundle(wasmPath, dataPath) {
|
||
|
try {
|
||
|
// verify that the correct files were generated, since this is user input
|
||
|
return !(!fs.existsSync(wasmPath) || !fs.existsSync(dataPath));
|
||
|
}
|
||
|
catch {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
exports.isValidBundle = isValidBundle;
|
||
|
function computeCustomRulesBundleChecksum() {
|
||
|
try {
|
||
|
const customRulesPolicyWasmPath = path.join(local_cache_1.LOCAL_POLICY_ENGINE_DIR, oci_pull_1.CUSTOM_RULES_TARBALL);
|
||
|
// if bundle is not configured we don't want to include the checksum
|
||
|
if (!fs.existsSync(customRulesPolicyWasmPath)) {
|
||
|
return;
|
||
|
}
|
||
|
const policyWasm = fs.readFileSync(customRulesPolicyWasmPath, 'utf8');
|
||
|
return hashData(policyWasm);
|
||
|
}
|
||
|
catch (err) {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
exports.computeCustomRulesBundleChecksum = computeCustomRulesBundleChecksum;
|
||
|
/**
|
||
|
* makeFileAndDirectoryGenerator is a generator function that helps walking the directory and file structure of this pathToScan
|
||
|
* @param root
|
||
|
* @param maxDepth? - An optional `maxDepth` argument can be provided to limit how deep in the file tree the search will go.
|
||
|
* @returns {Generator<object>} - a generator which yields an object with directories or paths for the path to scan
|
||
|
*/
|
||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||
|
function* makeFileAndDirectoryGenerator(root = '.', maxDepth) {
|
||
|
function* generatorHelper(pathToScan, currentDepth) {
|
||
|
{
|
||
|
yield { directory: pathToScan };
|
||
|
}
|
||
|
if (maxDepth !== currentDepth) {
|
||
|
for (const dirent of fs_1.readdirSync(pathToScan, { withFileTypes: true })) {
|
||
|
if (dirent.isDirectory() &&
|
||
|
fs.readdirSync(path_1.join(pathToScan, dirent.name)).length !== 0) {
|
||
|
yield* generatorHelper(path_1.join(pathToScan, dirent.name), currentDepth + 1);
|
||
|
}
|
||
|
else if (dirent.isFile()) {
|
||
|
yield {
|
||
|
file: {
|
||
|
dir: pathToScan,
|
||
|
fileName: path_1.join(pathToScan, dirent.name),
|
||
|
},
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
yield* generatorHelper(root, 0);
|
||
|
}
|
||
|
exports.makeFileAndDirectoryGenerator = makeFileAndDirectoryGenerator;
|
||
|
|
||
|
|
||
|
/***/ }),
|
||
|
|
||
|
/***/ 50089:
|
||
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
||
|
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||
|
exports.InvalidCustomRulesPath = exports.InvalidCustomRules = exports.FailedToExtractCustomRulesError = exports.FailedToDownloadRulesError = exports.FailedToInitLocalCacheError = exports.cleanLocalCache = exports.initLocalCache = exports.getLocalCachePath = exports.assertNever = exports.CUSTOM_POLICY_ENGINE_WASM_PATH = exports.LOCAL_POLICY_ENGINE_DIR = void 0;
|
||
|
const path = __webpack_require__(85622);
|
||
|
const fs = __webpack_require__(35747);
|
||
|
const types_1 = __webpack_require__(94820);
|
||
|
const rimraf = __webpack_require__(50984);
|
||
|
const file_utils_1 = __webpack_require__(45281);
|
||
|
const Debug = __webpack_require__(15158);
|
||
|
const errors_1 = __webpack_require__(55191);
|
||
|
const analytics = __webpack_require__(82744);
|
||
|
const error_utils_1 = __webpack_require__(36401);
|
||
|
const config_1 = __webpack_require__(25425);
|
||
|
const request_1 = __webpack_require__(1552);
|
||
|
const debug = Debug('iac-local-cache');
|
||
|
exports.LOCAL_POLICY_ENGINE_DIR = '.iac-data';
|
||
|
const KUBERNETES_POLICY_ENGINE_WASM_PATH = path.join(exports.LOCAL_POLICY_ENGINE_DIR, 'k8s_policy.wasm');
|
||
|
const KUBERNETES_POLICY_ENGINE_DATA_PATH = path.join(exports.LOCAL_POLICY_ENGINE_DIR, 'k8s_data.json');
|
||
|
const TERRAFORM_POLICY_ENGINE_WASM_PATH = path.join(exports.LOCAL_POLICY_ENGINE_DIR, 'tf_policy.wasm');
|
||
|
const TERRAFORM_POLICY_ENGINE_DATA_PATH = path.join(exports.LOCAL_POLICY_ENGINE_DIR, 'tf_data.json');
|
||
|
const CLOUDFORMATION_POLICY_ENGINE_WASM_PATH = path.join(exports.LOCAL_POLICY_ENGINE_DIR, 'cloudformation_policy.wasm');
|
||
|
const CLOUDFORMATION_POLICY_ENGINE_DATA_PATH = path.join(exports.LOCAL_POLICY_ENGINE_DIR, 'cloudformation_data.json');
|
||
|
const ARM_POLICY_ENGINE_WASM_PATH = path.join(exports.LOCAL_POLICY_ENGINE_DIR, 'arm_policy.wasm');
|
||
|
const ARM_POLICY_ENGINE_DATA_PATH = path.join(exports.LOCAL_POLICY_ENGINE_DIR, 'arm_data.json');
|
||
|
// NOTE: The filenames used for the custom policy bundles match those output
|
||
|
// by the `opa` CLI tool, which is why they are very generic.
|
||
|
exports.CUSTOM_POLICY_ENGINE_WASM_PATH = path.join(exports.LOCAL_POLICY_ENGINE_DIR, 'policy.wasm');
|
||
|
const CUSTOM_POLICY_ENGINE_DATA_PATH = path.join(exports.LOCAL_POLICY_ENGINE_DIR, 'data.json');
|
||
|
function assertNever(value) {
|
||
|
throw new Error(`Unhandled discriminated union member: ${JSON.stringify(value)}`);
|
||
|
}
|
||
|
exports.assertNever = assertNever;
|
||
|
function getLocalCachePath(engineType) {
|
||
|
switch (engineType) {
|
||
|
case types_1.EngineType.Kubernetes:
|
||
|
return [
|
||
|
`${process.cwd()}/${KUBERNETES_POLICY_ENGINE_WASM_PATH}`,
|
||
|
`${process.cwd()}/${KUBERNETES_POLICY_ENGINE_DATA_PATH}`,
|
||
|
];
|
||
|
case types_1.EngineType.Terraform:
|
||
|
return [
|
||
|
`${process.cwd()}/${TERRAFORM_POLICY_ENGINE_WASM_PATH}`,
|
||
|
`${process.cwd()}/${TERRAFORM_POLICY_ENGINE_DATA_PATH}`,
|
||
|
];
|
||
|
case types_1.EngineType.CloudFormation:
|
||
|
return [
|
||
|
`${process.cwd()}/${CLOUDFORMATION_POLICY_ENGINE_WASM_PATH}`,
|
||
|
`${process.cwd()}/${CLOUDFORMATION_POLICY_ENGINE_DATA_PATH}`,
|
||
|
];
|
||
|
case types_1.EngineType.ARM:
|
||
|
return [
|
||
|
`${process.cwd()}/${ARM_POLICY_ENGINE_WASM_PATH}`,
|
||
|
`${process.cwd()}/${ARM_POLICY_ENGINE_DATA_PATH}`,
|
||
|
];
|
||
|
case types_1.EngineType.Custom:
|
||
|
return [
|
||
|
`${process.cwd()}/${exports.CUSTOM_POLICY_ENGINE_WASM_PATH}`,
|
||
|
`${process.cwd()}/${CUSTOM_POLICY_ENGINE_DATA_PATH}`,
|
||
|
];
|
||
|
default:
|
||
|
assertNever(engineType);
|
||
|
}
|
||
|
}
|
||
|
exports.getLocalCachePath = getLocalCachePath;
|
||
|
async function initLocalCache({ customRulesPath, } = {}) {
|
||
|
try {
|
||
|
file_utils_1.createIacDir();
|
||
|
}
|
||
|
catch (e) {
|
||
|
throw new FailedToInitLocalCacheError();
|
||
|
}
|
||
|
// Attempt to extract the custom rules from the path provided.
|
||
|
if (customRulesPath) {
|
||
|
if (!fs.existsSync(customRulesPath)) {
|
||
|
throw new InvalidCustomRulesPath(customRulesPath);
|
||
|
}
|
||
|
try {
|
||
|
const response = fs.createReadStream(customRulesPath);
|
||
|
await file_utils_1.extractBundle(response);
|
||
|
}
|
||
|
catch (e) {
|
||
|
throw new FailedToExtractCustomRulesError(customRulesPath);
|
||
|
}
|
||
|
if (!file_utils_1.isValidBundle(exports.CUSTOM_POLICY_ENGINE_WASM_PATH, CUSTOM_POLICY_ENGINE_DATA_PATH)) {
|
||
|
throw new InvalidCustomRules(customRulesPath);
|
||
|
}
|
||
|
}
|
||
|
// IAC_BUNDLE_PATH is a developer setting that is not useful to most users. It
|
||
|
// is not a replacement for custom rules.
|
||
|
if (config_1.default.IAC_BUNDLE_PATH) {
|
||
|
const stream = fs.createReadStream(config_1.default.IAC_BUNDLE_PATH);
|
||
|
await file_utils_1.extractBundle(stream);
|
||
|
return;
|
||
|
}
|
||
|
// We extract the Snyk rules after the custom rules to ensure our files
|
||
|
// always overwrite whatever might be there.
|
||
|
try {
|
||
|
const BUNDLE_URL = 'https://static.snyk.io/cli/wasm/bundle.tar.gz';
|
||
|
const response = await request_1.streamRequest({
|
||
|
method: 'get',
|
||
|
url: BUNDLE_URL,
|
||
|
body: null,
|
||
|
headers: {},
|
||
|
});
|
||
|
await file_utils_1.extractBundle(response);
|
||
|
}
|
||
|
catch (e) {
|
||
|
throw new FailedToDownloadRulesError();
|
||
|
}
|
||
|
}
|
||
|
exports.initLocalCache = initLocalCache;
|
||
|
function cleanLocalCache() {
|
||
|
// path to delete is hardcoded for now
|
||
|
const iacPath = path.join(`${process.cwd()}`, exports.LOCAL_POLICY_ENGINE_DIR);
|
||
|
try {
|
||
|
// when we support Node version >= 12.10.0 , we can replace rimraf
|
||
|
// with the native fs.rmdirSync(path, {recursive: true})
|
||
|
rimraf.sync(iacPath);
|
||
|
}
|
||
|
catch (e) {
|
||
|
const err = new FailedToCleanLocalCacheError();
|
||
|
analytics.add('error-code', err.code);
|
||
|
debug('The local cache directory could not be deleted');
|
||
|
}
|
||
|
}
|
||
|
exports.cleanLocalCache = cleanLocalCache;
|
||
|
class FailedToInitLocalCacheError extends errors_1.CustomError {
|
||
|
constructor(message) {
|
||
|
super(message || 'Failed to initialize local cache');
|
||
|
this.code = types_1.IaCErrorCodes.FailedToInitLocalCacheError;
|
||
|
this.strCode = error_utils_1.getErrorStringCode(this.code);
|
||
|
this.userMessage =
|
||
|
'We were unable to create a local directory to store the test assets, please ensure that the current working directory is writable';
|
||
|
}
|
||
|
}
|
||
|
exports.FailedToInitLocalCacheError = FailedToInitLocalCacheError;
|
||
|
class FailedToDownloadRulesError extends errors_1.CustomError {
|
||
|
constructor(message) {
|
||
|
super(message || 'Failed to download policies');
|
||
|
this.code = types_1.IaCErrorCodes.FailedToDownloadRulesError;
|
||
|
this.strCode = error_utils_1.getErrorStringCode(this.code);
|
||
|
this.userMessage =
|
||
|
'We were unable to download the security rules, please ensure the network can access https://static.snyk.io';
|
||
|
}
|
||
|
}
|
||
|
exports.FailedToDownloadRulesError = FailedToDownloadRulesError;
|
||
|
class FailedToExtractCustomRulesError extends errors_1.CustomError {
|
||
|
constructor(path, message) {
|
||
|
super(message || 'Failed to download policies');
|
||
|
this.code = types_1.IaCErrorCodes.FailedToExtractCustomRulesError;
|
||
|
this.strCode = error_utils_1.getErrorStringCode(this.code);
|
||
|
this.userMessage = `We were unable to extract the rules provided at: ${path}. The provided bundle may be corrupted or invalid. Please ensure it was generated using the 'snyk-iac-rules' SDK`;
|
||
|
}
|
||
|
}
|
||
|
exports.FailedToExtractCustomRulesError = FailedToExtractCustomRulesError;
|
||
|
class InvalidCustomRules extends errors_1.CustomError {
|
||
|
constructor(path, message) {
|
||
|
super(message || 'Invalid custom rules bundle');
|
||
|
this.code = types_1.IaCErrorCodes.InvalidCustomRules;
|
||
|
this.strCode = error_utils_1.getErrorStringCode(this.code);
|
||
|
this.userMessage = `We were unable to extract the rules provided at: ${path}. The provided bundle does not match the required structure. Please ensure it was generated using the 'snyk-iac-rules' SDK`;
|
||
|
}
|
||
|
}
|
||
|
exports.InvalidCustomRules = InvalidCustomRules;
|
||
|
class InvalidCustomRulesPath extends errors_1.CustomError {
|
||
|
constructor(path, message) {
|
||
|
super(message || 'Invalid path to custom rules bundle');
|
||
|
this.code = types_1.IaCErrorCodes.InvalidCustomRulesPath;
|
||
|
this.strCode = error_utils_1.getErrorStringCode(this.code);
|
||
|
this.userMessage = `We were unable to extract the rules provided at: ${path}. The bundle at the provided path does not exist`;
|
||
|
}
|
||
|
}
|
||
|
exports.InvalidCustomRulesPath = InvalidCustomRulesPath;
|
||
|
class FailedToCleanLocalCacheError extends errors_1.CustomError {
|
||
|
constructor(message) {
|
||
|
super(message || 'Failed to clean local cache');
|
||
|
this.code = types_1.IaCErrorCodes.FailedToCleanLocalCacheError;
|
||
|
this.strCode = error_utils_1.getErrorStringCode(this.code);
|
||
|
this.userMessage = ''; // Not a user facing error.
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/***/ }),
|
||
|
|
||
|
/***/ 166:
|
||
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
||
|
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||
|
exports.UnsupportedEntitlementPullError = exports.InvalidRemoteRegistryURLError = exports.InvalidManifestSchemaVersionError = exports.FailedToBuildOCIArtifactError = exports.pull = exports.extractOCIRegistryURLComponents = exports.CUSTOM_RULES_TARBALL = void 0;
|
||
|
const fs_1 = __webpack_require__(35747);
|
||
|
const path = __webpack_require__(85622);
|
||
|
const types_1 = __webpack_require__(94820);
|
||
|
const errors_1 = __webpack_require__(55191);
|
||
|
const error_utils_1 = __webpack_require__(36401);
|
||
|
const local_cache_1 = __webpack_require__(50089);
|
||
|
const Debug = __webpack_require__(15158);
|
||
|
const file_utils_1 = __webpack_require__(45281);
|
||
|
const debug = Debug('iac-oci-pull');
|
||
|
exports.CUSTOM_RULES_TARBALL = 'custom-bundle.tar.gz';
|
||
|
function extractOCIRegistryURLComponents(OCIRegistryURL) {
|
||
|
try {
|
||
|
const urlWithoutProtocol = OCIRegistryURL.includes('://')
|
||
|
? OCIRegistryURL.split('://')[1]
|
||
|
: OCIRegistryURL;
|
||
|
const firstSlashIdx = urlWithoutProtocol.indexOf('/');
|
||
|
const [registryHost, repoWithTag] = [
|
||
|
urlWithoutProtocol.substring(0, firstSlashIdx),
|
||
|
urlWithoutProtocol.substring(firstSlashIdx + 1),
|
||
|
];
|
||
|
const [repo, tag = 'latest'] = repoWithTag.split(':');
|
||
|
if (firstSlashIdx === -1 || !registryHost || !repoWithTag || !repo) {
|
||
|
throw new InvalidRemoteRegistryURLError(OCIRegistryURL);
|
||
|
}
|
||
|
return { registryBase: registryHost, repo, tag };
|
||
|
}
|
||
|
catch {
|
||
|
throw new InvalidRemoteRegistryURLError(OCIRegistryURL);
|
||
|
}
|
||
|
}
|
||
|
exports.extractOCIRegistryURLComponents = extractOCIRegistryURLComponents;
|
||
|
/**
|
||
|
* Downloads an OCI Artifact from a remote OCI Registry and writes it to the
|
||
|
* disk. The artifact here is a custom rules bundle stored in a remote registry.
|
||
|
* In order to do that, it calls an external docker registry v2 client to get
|
||
|
* the manifests, the layers and then builds the artifact. Example:
|
||
|
* https://github.com/opencontainers/image-spec/blob/main/manifest.md#example-image-manifest
|
||
|
*
|
||
|
* @param registry The client for accessing an OCI registry.
|
||
|
* @param repository The name of an OCI repository.
|
||
|
* @param tag The tag of an image in an OCI repository.
|
||
|
**/
|
||
|
async function pull(registry, repository, tag) {
|
||
|
const { schemaVersion, layers } = await registry.getManifest(repository, tag);
|
||
|
if (schemaVersion !== 2) {
|
||
|
throw new InvalidManifestSchemaVersionError(schemaVersion.toString());
|
||
|
}
|
||
|
// We assume that we will always have an artifact of a single layer
|
||
|
if (layers.length > 1) {
|
||
|
debug('There were more than one layers found in the OCI Artifact.');
|
||
|
}
|
||
|
const { blob } = await registry.getLayer(repository, layers[0].digest);
|
||
|
try {
|
||
|
const downloadPath = path.join(local_cache_1.LOCAL_POLICY_ENGINE_DIR, exports.CUSTOM_RULES_TARBALL);
|
||
|
file_utils_1.createIacDir();
|
||
|
await fs_1.promises.writeFile(downloadPath, blob);
|
||
|
return downloadPath;
|
||
|
}
|
||
|
catch (err) {
|
||
|
throw new FailedToBuildOCIArtifactError();
|
||
|
}
|
||
|
}
|
||
|
exports.pull = pull;
|
||
|
class FailedToBuildOCIArtifactError extends errors_1.CustomError {
|
||
|
constructor(message) {
|
||
|
super(message || 'Could not build OCI Artifact');
|
||
|
this.code = types_1.IaCErrorCodes.FailedToBuildOCIArtifactError;
|
||
|
this.strCode = error_utils_1.getErrorStringCode(this.code);
|
||
|
this.userMessage =
|
||
|
'We were unable to build the remote OCI Artifact locally, please ensure that the local directory is writeable.';
|
||
|
}
|
||
|
}
|
||
|
exports.FailedToBuildOCIArtifactError = FailedToBuildOCIArtifactError;
|
||
|
class InvalidManifestSchemaVersionError extends errors_1.CustomError {
|
||
|
constructor(message) {
|
||
|
super(message || 'Invalid manifest schema version');
|
||
|
this.code = types_1.IaCErrorCodes.InvalidRemoteRegistryURLError;
|
||
|
this.strCode = error_utils_1.getErrorStringCode(this.code);
|
||
|
this.userMessage = `Invalid manifest schema version: ${message}. We currently support Image Manifest Version 2, Schema 2`;
|
||
|
}
|
||
|
}
|
||
|
exports.InvalidManifestSchemaVersionError = InvalidManifestSchemaVersionError;
|
||
|
class InvalidRemoteRegistryURLError extends errors_1.CustomError {
|
||
|
constructor(url) {
|
||
|
super('Invalid URL for Remote Registry');
|
||
|
this.code = types_1.IaCErrorCodes.InvalidRemoteRegistryURLError;
|
||
|
this.strCode = error_utils_1.getErrorStringCode(this.code);
|
||
|
this.userMessage = `The provided remote registry URL${url ? `: "${url}"` : ''} is invalid. Please check it again.`;
|
||
|
}
|
||
|
}
|
||
|
exports.InvalidRemoteRegistryURLError = InvalidRemoteRegistryURLError;
|
||
|
class UnsupportedEntitlementPullError extends errors_1.CustomError {
|
||
|
constructor(entitlement) {
|
||
|
super(`OCI Pull not supported - Missing the ${entitlement} entitlement`);
|
||
|
this.code = types_1.IaCErrorCodes.UnsupportedEntitlementPullError;
|
||
|
this.strCode = error_utils_1.getErrorStringCode(this.code);
|
||
|
this.userMessage = `The custom rules feature is currently not supported for this org. To enable it, please contact snyk support.`;
|
||
|
}
|
||
|
}
|
||
|
exports.UnsupportedEntitlementPullError = UnsupportedEntitlementPullError;
|
||
|
|
||
|
|
||
|
/***/ })
|
||
|
|
||
|
};
|
||
|
;
|
||
|
//# sourceMappingURL=519.index.js.map
|