Skip to content

Commit

Permalink
Fix modules settings persistence between updates (#4359)
Browse files Browse the repository at this point in the history
* fix(plugin-initialize): migrate the host configuration in the registry file when changing the plugin version or revision

- Migrated the existent host configuration in the registry file when changing the
  plugin version or revision instead of remove it when it was rebuilt.
- Removed not necessary return statements
- Removed not necessary try/catch block
- Added some logs
- Enhanced some log messages
- Created tests for the migration registry file

* changelog: add PR entry

* changelog: removed new line

Co-authored-by: Álex <[email protected]>
(cherry picked from commit 3e056c5)
  • Loading branch information
Desvelao committed Aug 5, 2022
1 parent b35023c commit 92636f6
Show file tree
Hide file tree
Showing 3 changed files with 426 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ All notable changes to the Wazuh app project will be documented in this file.
### Fixed

- Fixed path in logo customization section [#4352](https://github.com/wazuh/wazuh-kibana-app/pull/4352)
- Fixed persistence of the plugin registry file between updates [#4359](https://github.com/wazuh/wazuh-kibana-app/pull/4359)

## Wazuh v4.3.6 - OpenSearch Dashboards 1.2.0 - Revision 4307

Expand Down
350 changes: 350 additions & 0 deletions server/start/initialize/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,350 @@
import fs from 'fs';
import md5 from 'md5';
import { execSync } from 'child_process';
import path from 'path';
import { jobInitializeRun } from './index';
import { createDataDirectoryIfNotExists, createDirectoryIfNotExists } from '../../lib/filesystem';
import { WAZUH_DATA_ABSOLUTE_PATH, WAZUH_DATA_CONFIG_DIRECTORY_PATH, WAZUH_DATA_CONFIG_REGISTRY_PATH } from '../../../common/constants';
import packageInfo from '../../../package.json';

function mockContextCreator(loggerLevel: string) {
const logs = [];
const levels = ['debug', 'info', 'warn', 'error'];

function createLogger(level: string) {
return jest.fn(function (message: string) {
const levelLogIncluded: number = levels.findIndex((level) => level === loggerLevel);
levelLogIncluded > -1
&& levels.slice(levelLogIncluded).includes(level)
&& logs.push({ level, message });
});
};

const ctx = {
wazuh: {
logger: {
info: createLogger('info'),
warn: createLogger('warn'),
error: createLogger('error'),
debug: createLogger('debug')
},
},
server: {
config: {
kibana: {
index: '.kibana'
}
}
},
core: {
elasticsearch: {
client: {
asInternalUser: {
indices: {
exists: jest.fn(() => ({body: true}))
}
}
}
}
},
/* Mocked logs getter. It is only for testing purpose.*/
_getLogs(logLevel: string) {
return logLevel ? logs.filter(({ level }) => level === logLevel) : logs;
}
}
return ctx;
};

jest.mock('../../lib/logger', () => ({
log: jest.fn()
}));

jest.mock('../../lib/get-configuration', () => ({
getConfiguration: () => ({pattern: 'wazuh-alerts-*'})
}));

beforeAll(() => {
// Create <PLUGIN_PLATFORM_PATH>/data/wazuh directory.
createDataDirectoryIfNotExists();
// Create <PLUGIN_PLATFORM_PATH>/data/wazuh/config directory.
createDirectoryIfNotExists(WAZUH_DATA_CONFIG_DIRECTORY_PATH);
});

afterAll(() => {
// Remove <PLUGIN_PLATFORM_PATH>/data/wazuh directory.
execSync(`rm -rf ${WAZUH_DATA_ABSOLUTE_PATH}`);
});

describe("[initialize] `wazuh-registry.json` not created", () => {
let mockContext = mockContextCreator('debug');
afterEach(() => {
// Remove <PLUGIN_PLATFORM_PATH>/data/wazuh/config/wazuh-registry file.
execSync(`rm ${WAZUH_DATA_ABSOLUTE_PATH}/config/wazuh-registry.json || echo ""`);
});

it("Create registry file with plugin data and empty hosts", async () => {
// Migrate the directories
await jobInitializeRun(mockContext);
const contentRegistry = JSON.parse(fs.readFileSync(WAZUH_DATA_CONFIG_REGISTRY_PATH, 'utf8'));

expect(contentRegistry.name).toMatch('Wazuh App');
expect(contentRegistry['app-version']).toMatch(packageInfo.version);
expect(contentRegistry['revision']).toMatch(packageInfo.revision);
expect(typeof contentRegistry.installationDate).toBe('string');
expect(typeof contentRegistry.lastRestart).toBe('string');
expect(Object.keys(contentRegistry.hosts)).toHaveLength(0);
});
});

describe("[initialize] `wazuh-registry.json` created", () => {
let testID = 0;
const contentRegistryFile = [
{
before: {
name: 'Wazuh App',
'app-version': packageInfo.version,
revision: packageInfo.revision,
installationDate: '2022-07-25T13:55:04.363Z',
lastRestart: '2022-07-25T13:55:04.363Z',
hosts: {}
},
after: {
name: 'Wazuh App',
'app-version': packageInfo.version,
revision: packageInfo.revision,
installationDate: '2022-07-25T13:55:04.363Z',
lastRestart: '2022-07-25T13:55:04.363Z',
hosts: {}
}
},
{
before: {
name: 'Wazuh App',
'app-version': '0.0.0',
revision: '0',
installationDate: '2022-07-25T13:55:04.363Z',
lastRestart: '2022-07-25T13:55:04.363Z',
hosts: {}
},
after: {
name: 'Wazuh App',
'app-version': packageInfo.version,
revision: packageInfo.revision,
installationDate: '2022-07-25T13:55:04.363Z',
lastRestart: '2022-07-25T13:55:04.363Z',
hosts: {}
}
},
{
before: {
name: 'Wazuh App',
'app-version': '0.0.0',
revision: '0',
installationDate: '2022-07-25T13:55:04.363Z',
lastRestart: '2022-07-25T13:55:04.363Z',
hosts: {
default: {
extensions: {
pci: true,
gdpr: true,
hipaa: true,
nist: true,
tsc: true,
audit: true,
oscap: false,
ciscat: false,
aws: false,
office: false,
github: false,
gcp: false,
virustotal: false,
osquery: false,
docker: false
}
}
}
},
after: {
name: 'Wazuh App',
'app-version': packageInfo.version,
revision: packageInfo.revision,
installationDate: '2022-07-25T13:55:04.363Z',
lastRestart: '2022-07-25T13:55:04.363Z',
hosts: {
default: {
extensions: {
pci: true,
gdpr: true,
hipaa: true,
nist: true,
tsc: true,
audit: true,
oscap: false,
ciscat: false,
aws: false,
office: false,
github: false,
gcp: false,
virustotal: false,
osquery: false,
docker: false
}
}
}
}
},
{
before: {
name: 'Wazuh App',
'app-version': '0.0.0',
revision: '0',
installationDate: '2022-07-25T13:55:04.363Z',
lastRestart: '2022-07-25T13:55:04.363Z',
hosts: {
default: {
extensions: {
pci: true,
gdpr: true,
hipaa: true,
nist: true,
tsc: true,
audit: true,
oscap: false,
ciscat: false,
aws: true,
office: true,
github: true,
gcp: true,
virustotal: false,
osquery: false
}
}
}
},
after: {
name: 'Wazuh App',
'app-version': packageInfo.version,
revision: packageInfo.revision,
installationDate: '2022-07-25T13:55:04.363Z',
lastRestart: '2022-07-25T13:55:04.363Z',
hosts: {
default: {
extensions: {
pci: true,
gdpr: true,
hipaa: true,
nist: true,
tsc: true,
audit: true,
oscap: false,
ciscat: false,
aws: true,
office: true,
github: true,
gcp: true,
virustotal: false,
osquery: false,
docker: false
}
}
}
}
},
{
before: {
name: 'Wazuh App',
'app-version': '0.0.0',
revision: '0',
installationDate: '2022-07-25T13:55:04.363Z',
lastRestart: '2022-07-25T13:55:04.363Z',
hosts: {
default: {
extensions: {
pci: true,
gdpr: true,
hipaa: true,
nist: true,
tsc: true,
audit: true,
oscap: false,
ciscat: false,
aws: true,
gcp: true,
virustotal: false,
osquery: false
}
}
}
},
after: {
name: 'Wazuh App',
'app-version': packageInfo.version,
revision: packageInfo.revision,
installationDate: '2022-07-25T13:55:04.363Z',
lastRestart: '2022-07-25T13:55:04.363Z',
hosts: {
default: {
extensions: {
pci: true,
gdpr: true,
hipaa: true,
nist: true,
tsc: true,
audit: true,
oscap: false,
ciscat: false,
aws: true,
office: false,
github: false,
gcp: true,
virustotal: false,
osquery: false,
docker: false
}
}
}
}
},
];

beforeEach(() => {
// Remove <PLUGIN_PLATFORM_PATH>/data/wazuh/config/wazuh-registry.json.
execSync(`rm ${WAZUH_DATA_ABSOLUTE_PATH}/config/wazuh-registry.json || echo ""`);
// Create the wazuh-registry.json file.
fs.writeFileSync(WAZUH_DATA_CONFIG_REGISTRY_PATH, JSON.stringify(contentRegistryFile[testID].before), 'utf8');
testID++;
});

it.each`
titleTest | contentRegistryFile
${'Registry file is not rebuilt due version and revision match'} | ${JSON.stringify(contentRegistryFile[0].after)}
${'Registry file is rebuilt due to version/revision changed'} | ${JSON.stringify(contentRegistryFile[1].after)}
${'Registry file is rebuilt due to version/revision changed and keeps the extensions (no modified)'} | ${JSON.stringify(contentRegistryFile[2].after)}
${'Registry file is rebuilt due to version/revision changed and keeps the extensions (modified)'} | ${JSON.stringify(contentRegistryFile[3].after)}
${'Registry file is rebuilt due to version/revision changed and adds missing extensions with default values'} | ${JSON.stringify(contentRegistryFile[4].after)}
`(`$titleTest:
content: $contentRegistryFile`, async ({ contentRegistryFile: content }) => {
const mockContext = mockContextCreator('debug');

const contentRegistryExpected = JSON.parse(content);
await jobInitializeRun(mockContext);
const contentRegistryFile = JSON.parse(fs.readFileSync(WAZUH_DATA_CONFIG_REGISTRY_PATH, 'utf8'));

expect(contentRegistryFile.name).toMatch('Wazuh App');
expect(contentRegistryFile['app-version']).toMatch(contentRegistryExpected['app-version']);
expect(contentRegistryFile['revision']).toMatch(contentRegistryExpected.revision);
expect(typeof contentRegistryFile.installationDate).toBe('string');
expect(typeof contentRegistryFile.lastRestart).toBe('string');
expect(Object.keys(contentRegistryFile.hosts)).toHaveLength(Object.keys(contentRegistryExpected.hosts).length);

if ( Object.keys(contentRegistryFile.hosts).length ){
Object.entries(contentRegistryFile.hosts).forEach(([hostID, hostData]) => {
if(hostData.extensions){
Object.entries(hostData.extensions).forEach(([extensionID, extensionEnabled]) => {
expect(extensionEnabled).toBe(contentRegistryExpected.hosts[hostID].extensions[extensionID])
});
};
});
};
});
});
Loading

0 comments on commit 92636f6

Please sign in to comment.