@hashgraph/solo
Version:
An opinionated CLI tool to deploy and manage private Hedera Networks.
311 lines • 16.3 kB
JavaScript
// SPDX-License-Identifier: Apache-2.0
import { expect } from 'chai';
import { describe, it } from 'mocha';
import { SensitiveDataRedactor } from '../../../../src/core/util/sensitive-data-redactor.js';
describe('SensitiveDataRedactor', () => {
describe('isSensitiveKey', () => {
it('should detect "password" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('password')).to.be.true;
});
it('should detect "global.operator.password" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('global.operator.password')).to.be.true;
});
it('should detect "secret" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('db.secret')).to.be.true;
});
it('should detect "token" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('auth-token')).to.be.true;
});
it('should detect "key" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('my_key')).to.be.true;
});
it('should detect "credential" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('user-credential')).to.be.true;
});
it('should detect "auth" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('auth')).to.be.true;
});
it('should detect "api_key" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('api_key')).to.be.true;
});
it('should detect "apikey" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('apikey')).to.be.true;
});
it('should detect "api-key" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('api-key')).to.be.true;
});
it('should detect "passphrase" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('passphrase')).to.be.true;
});
it('should detect "certificate" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('tls.certificate')).to.be.true;
});
it('should detect "private" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('private')).to.be.true;
});
it('should detect "passwd" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('db.passwd')).to.be.true;
});
it('should detect "privatekey" as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('privatekey')).to.be.true;
});
it('should detect "privateKey" (camelCase) as sensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('privateKey')).to.be.true;
});
it('should be case-insensitive', () => {
expect(SensitiveDataRedactor.isSensitiveKey('PASSWORD')).to.be.true;
expect(SensitiveDataRedactor.isSensitiveKey('Secret')).to.be.true;
expect(SensitiveDataRedactor.isSensitiveKey('API_KEY')).to.be.true;
});
it('should not flag non-sensitive keys', () => {
expect(SensitiveDataRedactor.isSensitiveKey('name')).to.be.false;
expect(SensitiveDataRedactor.isSensitiveKey('namespace')).to.be.false;
expect(SensitiveDataRedactor.isSensitiveKey('values')).to.be.false;
expect(SensitiveDataRedactor.isSensitiveKey('replicas')).to.be.false;
});
});
describe('redactArguments', () => {
describe('flag-based redaction', () => {
it('should redact the value after --password', () => {
const arguments_ = ['--password', 'mySecret'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
flagsToRedactNextArgument: ['--password'],
});
expect(result).to.deep.equal(['--password', '******']);
});
it('should redact the value after -p', () => {
const arguments_ = ['-p', 'mySecret'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
flagsToRedactNextArgument: ['-p'],
});
expect(result).to.deep.equal(['-p', '******']);
});
it('should handle flag at end of array without a value', () => {
const arguments_ = ['--password'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
flagsToRedactNextArgument: ['--password'],
});
expect(result).to.deep.equal(['--password']);
});
it('should redact multiple flag-based values', () => {
const arguments_ = ['--password', 'secret1', '-p', 'secret2'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
flagsToRedactNextArgument: ['--password', '-p'],
});
expect(result).to.deep.equal(['--password', '******', '-p', '******']);
});
});
describe('set-style redaction', () => {
it('should redact sensitive key=value after --set', () => {
const arguments_ = ['--set', 'global.password=mySecret'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
setStyleFlags: ['--set'],
});
expect(result).to.deep.equal(['--set', 'global.password=******']);
});
it('should redact sensitive key=value after --set-string', () => {
const arguments_ = ['--set-string', 'auth-token=abc123'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
setStyleFlags: ['--set-string'],
});
expect(result).to.deep.equal(['--set-string', 'auth-token=******']);
});
it('should redact sensitive key=value after --set-file', () => {
const arguments_ = ['--set-file', 'tls.certificate=/path/to/cert'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
setStyleFlags: ['--set-file'],
});
expect(result).to.deep.equal(['--set-file', 'tls.certificate=******']);
});
it('should not redact non-sensitive key=value after --set', () => {
const arguments_ = ['--set', 'replicas=3'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
setStyleFlags: ['--set'],
});
expect(result).to.deep.equal(['--set', 'replicas=3']);
});
it('should pass through --set value without = sign unchanged', () => {
const arguments_ = ['--set', 'someValue'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
setStyleFlags: ['--set'],
});
expect(result).to.deep.equal(['--set', 'someValue']);
});
it('should handle --set at end of array', () => {
const arguments_ = ['--set'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
setStyleFlags: ['--set'],
});
expect(result).to.deep.equal(['--set']);
});
});
describe('inline key=value redaction', () => {
it('should redact inline sensitive key=value args', () => {
const arguments_ = ['some-token=abc', 'api_key=xyz'];
const result = SensitiveDataRedactor.redactArguments(arguments_);
expect(result).to.deep.equal(['some-token=******', 'api_key=******']);
});
it('should not redact inline non-sensitive key=value args', () => {
const arguments_ = ['name=myApp', 'replicas=3'];
const result = SensitiveDataRedactor.redactArguments(arguments_);
expect(result).to.deep.equal(['name=myApp', 'replicas=3']);
});
});
describe('regex dynamic matching', () => {
it('should redact credential via regex', () => {
const arguments_ = ['--set', 'db.credential=secretValue'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
setStyleFlags: ['--set'],
});
expect(result).to.deep.equal(['--set', 'db.credential=******']);
});
it('should redact passphrase via regex', () => {
const arguments_ = ['ssh.passphrase=myPhrase'];
const result = SensitiveDataRedactor.redactArguments(arguments_);
expect(result).to.deep.equal(['ssh.passphrase=******']);
});
it('should redact api-key via regex', () => {
const arguments_ = ['api-key=abc123'];
const result = SensitiveDataRedactor.redactArguments(arguments_);
expect(result).to.deep.equal(['api-key=******']);
});
it('should redact certificate via regex', () => {
const arguments_ = ['tls.certificate=base64data'];
const result = SensitiveDataRedactor.redactArguments(arguments_);
expect(result).to.deep.equal(['tls.certificate=******']);
});
it('should redact auth via regex', () => {
const arguments_ = ['--set', 'global.auth=bearerXYZ'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
setStyleFlags: ['--set'],
});
expect(result).to.deep.equal(['--set', 'global.auth=******']);
});
it('should redact private via regex', () => {
const arguments_ = ['private=data'];
const result = SensitiveDataRedactor.redactArguments(arguments_);
expect(result).to.deep.equal(['private=******']);
});
it('should redact privatekey via regex', () => {
const arguments_ = ['privatekey=data'];
const result = SensitiveDataRedactor.redactArguments(arguments_);
expect(result).to.deep.equal(['privatekey=******']);
});
});
describe('nested dot-notation key redaction', () => {
it('should redact deeply nested password key', () => {
const arguments_ = ['--set', 'something.something.password=123456'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
setStyleFlags: ['--set'],
});
expect(result).to.deep.equal(['--set', 'something.something.password=******']);
});
it('should redact deeply nested secret key', () => {
const arguments_ = ['--set', 'a.b.c.secret=topSecret'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
setStyleFlags: ['--set'],
});
expect(result).to.deep.equal(['--set', 'a.b.c.secret=******']);
});
it('should redact nested privatekey', () => {
const arguments_ = ['tls.privatekey=base64data'];
const result = SensitiveDataRedactor.redactArguments(arguments_);
expect(result).to.deep.equal(['tls.privatekey=******']);
});
it('should not redact nested non-sensitive key', () => {
const arguments_ = ['--set', 'config.server.replicas=3'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
setStyleFlags: ['--set'],
});
expect(result).to.deep.equal(['--set', 'config.server.replicas=3']);
});
});
describe('combined options', () => {
it('should handle both flag-based and set-style redaction together', () => {
const arguments_ = [
'install',
'my-release',
'--password',
's3cret',
'--set',
'global.operator.password=mySecretValue',
'--set',
'global.db.secret=abc123',
'--namespace',
'default',
];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
flagsToRedactNextArgument: ['--password'],
setStyleFlags: ['--set'],
});
expect(result).to.deep.equal([
'install',
'my-release',
'--password',
'******',
'--set',
'global.operator.password=******',
'--set',
'global.db.secret=******',
'--namespace',
'default',
]);
});
});
describe('edge cases', () => {
it('should return empty array for empty input', () => {
const result = SensitiveDataRedactor.redactArguments([]);
expect(result).to.deep.equal([]);
});
it('should pass through args with no sensitive data unchanged', () => {
const arguments_ = ['install', 'my-release', '--namespace', 'default', '--values', 'values.yaml'];
const result = SensitiveDataRedactor.redactArguments(arguments_);
expect(result).to.deep.equal(['install', 'my-release', '--namespace', 'default', '--values', 'values.yaml']);
});
it('should use default options when none provided', () => {
const arguments_ = ['password=secret', 'name=test'];
const result = SensitiveDataRedactor.redactArguments(arguments_);
expect(result).to.deep.equal(['password=******', 'name=test']);
});
});
describe('composite argument splitting', () => {
it('should split and redact composite arguments containing multiple key-value pairs', () => {
const arguments_ = [
'--set foo.bar=false --set foo.privateKey=0x123456 --set foo.bar.password=123456',
];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
setStyleFlags: ['--set'],
});
expect(result).to.deep.equal([
'--set',
'foo.bar=false',
'--set',
'foo.privateKey=******',
'--set',
'foo.bar.password=******',
]);
});
it('should split composite arguments with flags and values', () => {
const arguments_ = ['--values values.yaml --set foo.bar=false'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
setStyleFlags: ['--set'],
});
expect(result).to.deep.equal(['--values', 'values.yaml', '--set', 'foo.bar=false']);
});
it('should handle composite arguments with password flag', () => {
const arguments_ = ['--password secret123 --set foo.bar=false'];
const result = SensitiveDataRedactor.redactArguments(arguments_, {
flagsToRedactNextArgument: ['--password'],
setStyleFlags: ['--set'],
});
expect(result).to.deep.equal(['--password', '******', '--set', 'foo.bar=false']);
});
it('should not split arguments that do not contain whitespace', () => {
const arguments_ = ['install', 'my-release', '--namespace', 'default'];
const result = SensitiveDataRedactor.redactArguments(arguments_);
expect(result).to.deep.equal(['install', 'my-release', '--namespace', 'default']);
});
});
});
});
//# sourceMappingURL=sensitive-data-redactor.test.js.map