Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(NA): tool to find plugins circular dependencies between plugins #82867

Merged
merged 91 commits into from
Nov 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
27d24c2
chore(NA): update gitignore to include first changes from moving into…
mistic Sep 23, 2020
6438701
chore(NA): update gitignore
mistic Sep 23, 2020
e3cdba8
Merge branch 'master' into move-into-single-pkg-json
mistic Oct 6, 2020
747bc1b
Merge remote-tracking branch 'upstream/master' into move-into-single-…
mistic Oct 6, 2020
5729728
chore(NA): move all the dependencies into the single package.json and…
mistic Oct 7, 2020
90e8191
chore(NA): fix types problems after the single package json
mistic Oct 7, 2020
9720df7
chore(NA): include code to find the dependencies used across the code
mistic Oct 8, 2020
fb4f4ac
chore(NA): introduce pure lockfile for install dependencies on build
mistic Oct 8, 2020
f61da70
chore(NA): update clean task to not delete anything from xpack node_m…
mistic Oct 8, 2020
a28a805
chore(NA): update gitignore to remove development temporary rules
mistic Oct 8, 2020
ee8f700
chore(NA): update notice file
mistic Oct 8, 2020
e78fb5d
chore(NA): update jest snapshots
mistic Oct 8, 2020
3103aa5
chore(NA): fix whitelisted licenses to include a new specify form of …
mistic Oct 8, 2020
20aa15f
chore(NA): remove check lockfile symlinks from child projects
mistic Oct 8, 2020
c6d9fbe
chore(NA): fix eslint and add missing declared deps on single pkg json
mistic Oct 8, 2020
2eba78c
chore(NA): merge and solve conflicts with master
mistic Oct 8, 2020
ac92015
chore(NA): correctly update notice
mistic Oct 8, 2020
53484ef
chore(NA): fix failing jest test for storyshots.test.tsx
mistic Oct 8, 2020
1181698
chore(NA): fix cypress multi reporter path
mistic Oct 9, 2020
6d7040f
chore(NA): fix Project tests check
mistic Oct 9, 2020
d1b5825
chore(NA): fix problem with logic to detect used dependes on oss build
mistic Oct 9, 2020
940c876
chore(NA): merge and solve conflicts with master
mistic Oct 9, 2020
5cf9afc
chore(NA): include correct x-pack plugins dep discovery
mistic Oct 9, 2020
b0d2b2f
chore(NA): discover entries under dynamic requires on vis_type_timelion
mistic Oct 12, 2020
0f7b24d
chore(NA): merge and solve conflicts with master
mistic Oct 12, 2020
4dfff00
chore(NA): merge and solve conflicts with master
mistic Oct 12, 2020
d697bb1
Merge remote-tracking branch 'upstream/master' into move-into-single-…
mistic Oct 13, 2020
e3fc7a6
chore(NA): remove canvas
mistic Oct 13, 2020
2d991e7
Merge remote-tracking branch 'upstream/master' into move-into-single-…
mistic Oct 13, 2020
e002ca0
chore(NA): merge and solve conflicts with master
mistic Oct 13, 2020
bed74ab
chore(NA): add initial code to find circular deps
mistic Oct 14, 2020
e2b8d13
chore(NA): ground work to integrate the circular deps scripts
mistic Oct 15, 2020
e740159
chore(NA): add correct filtering to find circular dependenices feature
mistic Oct 19, 2020
7b853d2
chore(NA): add ci mode flag into circular deps script
mistic Oct 21, 2020
c84c229
chore(NA): feature complete circular dependencies detect script
mistic Oct 22, 2020
2a7768c
chore(NA): merge and solve conflicts with master
mistic Nov 4, 2020
027a809
chore(NA): merge and solve conflicts with master
mistic Nov 4, 2020
384add7
chore(NA): remove unwanted changes
mistic Nov 4, 2020
29cf5a3
chore(NA): remove unwanted changes on kbn storybook
mistic Nov 4, 2020
dc2405f
chore(NA): hook find circular deps tool into ci
mistic Nov 5, 2020
551fadf
chore(NA): remove previous find plugin circular deps script
mistic Nov 5, 2020
a8b286d
Merge remote-tracking branch 'upstream/master' into find-plugins-circ…
mistic Nov 5, 2020
dc39acf
Merge remote-tracking branch 'upstream/master' into find-plugins-circ…
mistic Nov 5, 2020
60a5ccd
chore(NA): add type for circular dep list
mistic Nov 5, 2020
0cf841a
chore(NA): add type for circular dep list for allowed list
mistic Nov 5, 2020
f49c89c
chore(NA): merge and solve conflicts with master
mistic Nov 6, 2020
cfaa7fe
chore(NA): allow CI to fail check
mistic Nov 6, 2020
f862b4a
chore(NA): update deps allowed list
mistic Nov 6, 2020
4ce4550
Merge branch 'master' into find-plugins-circular-deps
kibanamachine Nov 9, 2020
07e4ef0
Merge branch 'master' into find-plugins-circular-deps
mistic Nov 11, 2020
33e927d
chore(NA): run search circular deps script over examples too
mistic Nov 11, 2020
c3361fb
docs(NA): adds cli description
mistic Nov 11, 2020
65f5021
chore(NA): use plugin search paths to build entries to find circular …
mistic Nov 13, 2020
f4998ca
Merge remote-tracking branch 'upstream/master' into find-plugins-circ…
mistic Nov 13, 2020
878cea9
chore(NA): update allowed list
mistic Nov 13, 2020
02a7913
chore(NA): snapshot update for kbn optimizer test
mistic Nov 13, 2020
11e6c0f
Merge branch 'master' into find-plugins-circular-deps
kibanamachine Nov 13, 2020
a84368a
chore(NA): update dpdm version
mistic Nov 13, 2020
466158c
Merge branch 'find-plugins-circular-deps' of github.com:mistic/kibana…
mistic Nov 13, 2020
6c1f701
Merge branch 'master' into find-plugins-circular-deps
kibanamachine Nov 13, 2020
7a9d6c4
Merge branch 'master' into find-plugins-circular-deps
kibanamachine Nov 15, 2020
70e6644
Merge branch 'master' into find-plugins-circular-deps
kibanamachine Nov 17, 2020
9461676
Merge remote-tracking branch 'upstream/master' into find-plugins-circ…
mistic Nov 17, 2020
0eeca3b
chore(NA): remove thirdParty flag
mistic Nov 18, 2020
2f76ff6
Merge remote-tracking branch 'upstream/master' into find-plugins-circ…
mistic Nov 18, 2020
9e4a247
Merge branch 'master' into find-plugins-circular-deps
kibanamachine Nov 18, 2020
14e72a4
chore(NA): update docs to include info about the new tool
mistic Nov 19, 2020
e3b21ae
docs(NA): update to link PR instead of the issue
mistic Nov 19, 2020
dd7492b
Merge branch 'master' into find-plugins-circular-deps
kibanamachine Nov 19, 2020
095a683
Merge branch 'master' into find-plugins-circular-deps
kibanamachine Nov 19, 2020
9c01f1f
chore(NA): update debug logs to always output allowedList
mistic Nov 22, 2020
1a416f3
Merge branch 'find-plugins-circular-deps' of github.com:mistic/kibana…
mistic Nov 22, 2020
57844a9
Merge remote-tracking branch 'upstream/master' into find-plugins-circ…
mistic Nov 22, 2020
adf6d1d
fix(NA): correctly list found differences number
mistic Nov 22, 2020
30fd620
chore(NA): remove quiet flag
mistic Nov 22, 2020
6e33b21
fix(NA): correctly fail the CI if circular deps are found
mistic Nov 22, 2020
8af5585
chore(NA): complete list of found circular deps
mistic Nov 22, 2020
e638439
Merge remote-tracking branch 'upstream/master' into find-plugins-circ…
mistic Nov 22, 2020
60b5554
Merge branch 'master' into find-plugins-circular-deps
kibanamachine Nov 24, 2020
f353c81
chore(NA): merge and solve conflicts with master
mistic Nov 24, 2020
b9b0e1f
Merge branch 'find-plugins-circular-deps' of github.com:mistic/kibana…
mistic Nov 24, 2020
79d3bad
Merge branch 'master' into find-plugins-circular-deps
mistic Nov 25, 2020
59045ea
chore(NA): used named capturing group into the regex
mistic Nov 25, 2020
8afae77
docs(NA): update typescript best practices docs and styleguide
mistic Nov 25, 2020
6930417
chore(NA): introduce quick filter option flag
mistic Nov 25, 2020
9186f7c
Merge remote-tracking branch 'upstream/master' into find-plugins-circ…
mistic Nov 25, 2020
027ba37
Merge branch 'master' into find-plugins-circular-deps
kibanamachine Nov 25, 2020
7d42882
Merge branch 'master' into find-plugins-circular-deps
kibanamachine Nov 26, 2020
e01b833
Merge remote-tracking branch 'upstream/master' into find-plugins-circ…
mistic Nov 26, 2020
03b269f
Merge branch 'find-plugins-circular-deps' of github.com:mistic/kibana…
mistic Nov 26, 2020
1167306
Merge branch 'master' into find-plugins-circular-deps
kibanamachine Nov 30, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions STYLEGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,24 @@ Do not use setters, they cause more problems than they can solve.

[sideeffect]: http://en.wikipedia.org/wiki/Side_effect_(computer_science)

### Avoid circular dependencies

As part of a future effort to use correct and idempotent build tools we need our code to be
able to be represented as a directed acyclic graph. We must avoid having circular dependencies
both on code and type imports to achieve that. One of the most critical parts is the plugins
code. We've developed a tool to identify plugins with circular dependencies which
has allowed us to build a list of plugins who have circular dependencies
between each other.

When building plugins we should avoid importing from plugins
who are known to have circular dependencies at the moment as well as introducing
new circular dependencies. You can run the same tool we use on our CI locally by
typing `node scripts/find_plugins_with_circular_deps --debug`. It will error out in
case new circular dependencies has been added with your changes
(which will also happen in the CI) as well as print out the current list of
the known circular dependencies which, as mentioned before, should not be imported
by your code until the circular dependencies on these have been solved.

## SASS files

When writing a new component, create a sibling SASS file of the same name and import directly into the **top** of the JS/TS component file. Doing so ensures the styles are never separated or lost on import and allows for better modularization (smaller individual plugin asset footprint).
Expand Down
4 changes: 3 additions & 1 deletion docs/developer/best-practices/typescript.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ More details are available in the https://www.typescriptlang.org/docs/handbook/p
==== Caveats
This architecture imposes several limitations to which we must comply:

- Projects cannot have circular dependencies. Even though the Kibana platform doesn't support circular dependencies between Kibana plugins, TypeScript (and ES6 modules) does allow circular imports between files. So in theory, you may face a problem when migrating to the TS project references and you will have to resolve this circular dependency. https://github.com/elastic/kibana/issues/78162 is going to provide a tool to find such problem places.
- Projects cannot have circular dependencies. Even though the Kibana platform doesn't support circular dependencies between Kibana plugins, TypeScript (and ES6 modules) does allow circular imports between files. So in theory, you may face a problem when migrating to the TS project references and you will have to resolve this circular dependency. We've built a tool that can be used to find such problems. Please read the prerequisites section below to know how to use it.
- A project must emit its type declaration. It's not always possible to generate a type declaration if the compiler cannot infer a type. There are two basic cases:

1. Your plugin exports a type inferring an internal type declared in Kibana codebase. In this case, you'll have to either export an internal type or to declare an exported type explicitly.
Expand All @@ -30,6 +30,8 @@ This architecture imposes several limitations to which we must comply:
Since project refs rely on generated `d.ts` files, the migration order does matter. You can migrate your plugin only when all the plugin dependencies already have migrated. It creates a situation where commonly used plugins (such as `data` or `kibana_react`) have to migrate first.
Run `node scripts/find_plugins_without_ts_refs.js --id your_plugin_id` to get a list of plugins that should be switched to TS project refs to unblock your plugin migration.

Additionally, in order to migrate into project refs, you also need to make sure your plugin doesn't have circular dependencies with other plugins both on code and type imports. We run a job in the CI for each PR trying to find if new circular dependencies are being added which runs our tool with `node scripts/find_plugins_with_circular_deps`. However there are also a couple of circular dependencies already identified and that are in an allowed list to be solved. You also need to make sure your plugin don't rely in any other plugin into that allowed list. For a complete overview of the circular dependencies both found and in the allowed list as well as the complete circular dependencies path please run the following script locally with the debug flag `node scripts/find_plugins_with_circular_deps --debug` .

mistic marked this conversation as resolved.
Show resolved Hide resolved
[discrete]
==== Implementation
- Make sure all the plugins listed as dependencies in *requiredPlugins*, *optionalPlugins* & *requiredBundles* properties of `kibana.json` manifest file have migrated to TS project references.
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,7 @@
"delete-empty": "^2.0.0",
"dependency-check": "^4.1.0",
"diff": "^4.0.1",
"dpdm": "3.5.0",
"ejs": "^3.1.5",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
*/

require('../src/setup_node_env');
require('../src/dev/run_find_plugin_circular_deps');
require('../src/dev/run_find_plugins_with_circular_deps');
7 changes: 5 additions & 2 deletions src/dev/plugin_discovery/find_plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
* under the License.
*/
import Path from 'path';
import { REPO_ROOT } from '@kbn/dev-utils';
import { getPluginSearchPaths } from '@kbn/config';
import { KibanaPlatformPlugin, simpleKibanaPlatformPluginDiscovery } from '@kbn/dev-utils';
import {
KibanaPlatformPlugin,
REPO_ROOT,
simpleKibanaPlatformPluginDiscovery,
} from '@kbn/dev-utils';

export interface SearchOptions {
oss: boolean;
Expand Down
73 changes: 0 additions & 73 deletions src/dev/run_find_plugin_circular_deps.ts

This file was deleted.

214 changes: 214 additions & 0 deletions src/dev/run_find_plugins_with_circular_deps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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
*
* http://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.
*/

import dedent from 'dedent';
import { parseDependencyTree, parseCircular, prettyCircular } from 'dpdm';
import { relative } from 'path';
import { getPluginSearchPaths } from '@kbn/config';
import { REPO_ROOT, run } from '@kbn/dev-utils';

interface Options {
debug?: boolean;
filter?: string;
}

type CircularDepList = Set<string>;

const allowedList: CircularDepList = new Set([
'src/plugins/charts -> src/plugins/expressions',
'src/plugins/charts -> src/plugins/vis_default_editor',
'src/plugins/data -> src/plugins/embeddable',
'src/plugins/data -> src/plugins/expressions',
'src/plugins/data -> src/plugins/ui_actions',
'src/plugins/embeddable -> src/plugins/ui_actions',
'src/plugins/expressions -> src/plugins/visualizations',
'src/plugins/vis_default_editor -> src/plugins/visualizations',
'src/plugins/vis_default_editor -> src/plugins/visualize',
'src/plugins/visualizations -> src/plugins/visualize',
'x-pack/plugins/actions -> x-pack/plugins/case',
'x-pack/plugins/apm -> x-pack/plugins/infra',
'x-pack/plugins/lists -> x-pack/plugins/security_solution',
'x-pack/plugins/security -> x-pack/plugins/spaces',
mistic marked this conversation as resolved.
Show resolved Hide resolved
]);

run(
async ({ flags, log }) => {
const { debug, filter } = flags as Options;
const foundList: CircularDepList = new Set();

const pluginSearchPathGlobs = getPluginSearchPaths({
rootDir: REPO_ROOT,
oss: false,
examples: true,
}).map((pluginFolderPath) => `${relative(REPO_ROOT, pluginFolderPath)}/**/*`);

const depTree = await parseDependencyTree(pluginSearchPathGlobs, {
context: REPO_ROOT,
mistic marked this conversation as resolved.
Show resolved Hide resolved
});

// Build list of circular dependencies as well as the circular dependencies full paths
const circularDependenciesFullPaths = parseCircular(depTree).filter((circularDeps) => {
const first = circularDeps[0];
const last = circularDeps[circularDeps.length - 1];
const matchRegex = /(?<pluginFolder>(src|x-pack)\/plugins|examples|x-pack\/examples)\/(?<pluginName>[^\/]*)\/.*/;
const firstMatch = first.match(matchRegex);
const lastMatch = last.match(matchRegex);

if (
firstMatch?.groups?.pluginFolder &&
firstMatch?.groups?.pluginName &&
lastMatch?.groups?.pluginFolder &&
lastMatch?.groups?.pluginName
) {
const firstPlugin = `${firstMatch.groups.pluginFolder}/${firstMatch.groups.pluginName}`;
const lastPlugin = `${lastMatch.groups.pluginFolder}/${lastMatch.groups.pluginName}`;
const sortedPlugins = [firstPlugin, lastPlugin].sort();

// Exclude if both plugin paths involved in the circular dependency
// doesn't includes the provided filter
if (filter && !firstPlugin.includes(filter) && !lastPlugin.includes(filter)) {
return false;
}

if (firstPlugin !== lastPlugin) {
foundList.add(`${sortedPlugins[0]} -> ${sortedPlugins[1]}`);
return true;
}
}

return false;
});

if (!debug && filter) {
log.warning(
dedent(`
!!!!!!!!!!!!!! WARNING: FILTER WITHOUT DEBUG !!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Using the --filter flag without using --debug flag !
! will not allow you to see the filtered list of !
! the correct results. !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
`)
);
}

if (debug && filter) {
log.warning(
dedent(`
!!!!!!!!!!!!!!! WARNING: FILTER FLAG IS ON !!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Be aware the following results are not complete as !
! --filter flag has been passed. Ignore suggestions !
! to update the allowedList or any reports of failures !
! or successes. !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

The following filter has peen passed: ${filter}
`)
);
}

// Log the full circular dependencies path if we are under debug flag
if (debug && circularDependenciesFullPaths.length > 0) {
log.debug(
dedent(`
!!!!!!!!!!!!!! CIRCULAR DEPENDENCIES FOUND !!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Circular dependencies were found, you can find below !
! all the paths involved. !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
`)
);
log.debug(`${prettyCircular(circularDependenciesFullPaths)}\n`);
}

// Always log the result of comparing the found list with the allowed list
const diffSet = (first: CircularDepList, second: CircularDepList) =>
new Set([...first].filter((circularDep) => !second.has(circularDep)));

const printList = (list: CircularDepList) => {
return Array.from(list)
.sort()
.reduce((listStr, entry) => {
return listStr ? `${listStr}\n'${entry}',` : `'${entry}',`;
}, '');
};

const foundDifferences = diffSet(foundList, allowedList);

if (debug && !foundDifferences.size) {
log.debug(
dedent(`
!!!!!!!!!!!!!!!!! UP TO DATE ALLOWED LIST !!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! The declared circular dependencies allowed list is up !
! to date and includes every plugin listed in above paths. !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

The allowed circular dependencies list is (#${allowedList.size}):
${printList(allowedList)}
`)
);
}

if (foundDifferences.size > 0) {
log.error(
dedent(`
!!!!!!!!!!!!!!!!! OUT OF DATE ALLOWED LIST !!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! The declared circular dependencies allowed list is out !
! of date. Please run the following locally to know more: !
! !
! 'node scripts/find_plugins_with_circular_deps --debug' !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

The allowed circular dependencies list is (#${allowedList.size}):
${printList(allowedList)}

The found circular dependencies list is (#${foundList.size}):
${printList(foundList)}

The differences between both are (#${foundDifferences.size}):
${printList(foundDifferences)}

FAILED: circular dependencies in the allowed list declared on the file '${__filename}' did not match the found ones.
`)
);

process.exit(1);
}

log.success('None non allowed circular dependencies were found');
},
{
description:
'Searches circular dependencies between plugins located under src/plugins, x-pack/plugins, examples and x-pack/examples',
flags: {
boolean: ['debug'],
string: ['filter'],
default: {
debug: false,
},
help: `
--debug Run the script in debug mode which enables detailed path logs for circular dependencies
mistic marked this conversation as resolved.
Show resolved Hide resolved
--filter It will only include in the results circular deps where the plugin paths contains parts of the passed string in the filter
`,
},
}
);
6 changes: 6 additions & 0 deletions test/scripts/checks/plugins_with_circular_deps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash

source src/dev/ci_setup/setup_env.sh

checks-reporter-with-killswitch "Check plugins with circular dependencies" \
node scripts/find_plugins_with_circular_deps
1 change: 1 addition & 0 deletions vars/tasks.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def check() {
kibanaPipeline.scriptTask('Check i18n', 'test/scripts/checks/i18n.sh'),
kibanaPipeline.scriptTask('Check File Casing', 'test/scripts/checks/file_casing.sh'),
kibanaPipeline.scriptTask('Check Licenses', 'test/scripts/checks/licenses.sh'),
kibanaPipeline.scriptTask('Check Plugins With Circular Dependencies', 'test/scripts/checks/plugins_with_circular_deps.sh'),
kibanaPipeline.scriptTask('Verify NOTICE', 'test/scripts/checks/verify_notice.sh'),
kibanaPipeline.scriptTask('Test Projects', 'test/scripts/checks/test_projects.sh'),
kibanaPipeline.scriptTask('Test Hardening', 'test/scripts/checks/test_hardening.sh'),
Expand Down
Loading