mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-03 12:07:54 +00:00
Transit flaky test revisit (#25563)
* here we go... * glimmerize model to help —maybe—with capabilities checks * remove waitUntils
This commit is contained in:
@@ -6,14 +6,18 @@
|
|||||||
import Component from '@glimmer/component';
|
import Component from '@glimmer/component';
|
||||||
import { service } from '@ember/service';
|
import { service } from '@ember/service';
|
||||||
import { action } from '@ember/object';
|
import { action } from '@ember/object';
|
||||||
|
import { buildWaiter } from '@ember/test-waiters';
|
||||||
import errorMessage from 'vault/utils/error-message';
|
import errorMessage from 'vault/utils/error-message';
|
||||||
|
|
||||||
|
const waiter = buildWaiter('transit-form-show');
|
||||||
|
|
||||||
export default class TransitFormShow extends Component {
|
export default class TransitFormShow extends Component {
|
||||||
@service store;
|
@service store;
|
||||||
@service router;
|
@service router;
|
||||||
@service flashMessages;
|
@service flashMessages;
|
||||||
|
|
||||||
@action async rotateKey() {
|
@action async rotateKey() {
|
||||||
|
const waiterToken = waiter.beginAsync();
|
||||||
const { backend, id } = this.args.key;
|
const { backend, id } = this.args.key;
|
||||||
try {
|
try {
|
||||||
await this.store.adapterFor('transit-key').keyAction('rotate', { backend, id });
|
await this.store.adapterFor('transit-key').keyAction('rotate', { backend, id });
|
||||||
@@ -22,6 +26,8 @@ export default class TransitFormShow extends Component {
|
|||||||
await this.router.refresh();
|
await this.router.refresh();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.flashMessages.danger(errorMessage(e));
|
this.flashMessages.danger(errorMessage(e));
|
||||||
|
} finally {
|
||||||
|
waiter.endAsync(waiterToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,102 +4,113 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Model, { attr } from '@ember-data/model';
|
import Model, { attr } from '@ember-data/model';
|
||||||
import { alias } from '@ember/object/computed';
|
import { set, get } from '@ember/object';
|
||||||
import { set, get, computed } from '@ember/object';
|
|
||||||
import clamp from 'vault/utils/clamp';
|
import clamp from 'vault/utils/clamp';
|
||||||
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
|
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
|
||||||
|
|
||||||
const ACTION_VALUES = {
|
const ACTION_VALUES = {
|
||||||
encrypt: {
|
encrypt: {
|
||||||
isSupported: 'supportsEncryption',
|
isSupported: 'supportsEncryption',
|
||||||
description: 'Looks up wrapping properties for the given token',
|
description: 'Looks up wrapping properties for the given token.',
|
||||||
glyph: 'lock-fill',
|
glyph: 'lock-fill',
|
||||||
},
|
},
|
||||||
decrypt: {
|
decrypt: {
|
||||||
isSupported: 'supportsDecryption',
|
isSupported: 'supportsDecryption',
|
||||||
description: 'Decrypts the provided ciphertext using this key',
|
description: 'Decrypts the provided ciphertext using this key.',
|
||||||
glyph: 'mail-open',
|
glyph: 'mail-open',
|
||||||
},
|
},
|
||||||
datakey: {
|
datakey: {
|
||||||
isSupported: 'supportsEncryption',
|
isSupported: 'supportsEncryption',
|
||||||
description: 'Generates a new key and value encrypted with this key',
|
description: 'Generates a new key and value encrypted with this key.',
|
||||||
glyph: 'key',
|
glyph: 'key',
|
||||||
},
|
},
|
||||||
rewrap: {
|
rewrap: {
|
||||||
isSupported: 'supportsEncryption',
|
isSupported: 'supportsEncryption',
|
||||||
description: 'Rewraps the ciphertext using the latest version of the named key',
|
description: 'Rewraps the ciphertext using the latest version of the named key.',
|
||||||
glyph: 'reload',
|
glyph: 'reload',
|
||||||
},
|
},
|
||||||
sign: {
|
sign: {
|
||||||
isSupported: 'supportsSigning',
|
isSupported: 'supportsSigning',
|
||||||
description: 'Get the cryptographic signature of the given data',
|
description: 'Get the cryptographic signature of the given data.',
|
||||||
glyph: 'pencil-tool',
|
glyph: 'pencil-tool',
|
||||||
},
|
},
|
||||||
hmac: {
|
hmac: {
|
||||||
isSupported: true,
|
isSupported: true,
|
||||||
description: 'Generate a data digest using a hash algorithm',
|
description: 'Generate a data digest using a hash algorithm.',
|
||||||
glyph: 'shuffle',
|
glyph: 'shuffle',
|
||||||
},
|
},
|
||||||
verify: {
|
verify: {
|
||||||
isSupported: true,
|
isSupported: true,
|
||||||
description: 'Validate the provided signature for the given data',
|
description: 'Validate the provided signature for the given data.',
|
||||||
glyph: 'check-circle',
|
glyph: 'check-circle',
|
||||||
},
|
},
|
||||||
export: {
|
export: {
|
||||||
isSupported: 'exportable',
|
isSupported: 'exportable',
|
||||||
description: 'Get the named key',
|
description: 'Get the named key.',
|
||||||
glyph: 'external-link',
|
glyph: 'external-link',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Model.extend({
|
export default class TransitKeyModel extends Model {
|
||||||
type: attr('string', {
|
@attr('string') backend;
|
||||||
|
@attr('string', {
|
||||||
defaultValue: 'aes256-gcm96',
|
defaultValue: 'aes256-gcm96',
|
||||||
}),
|
})
|
||||||
name: attr('string', {
|
type;
|
||||||
|
|
||||||
|
@attr('string', {
|
||||||
label: 'Name',
|
label: 'Name',
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
}),
|
})
|
||||||
autoRotatePeriod: attr({
|
name;
|
||||||
|
|
||||||
|
@attr({
|
||||||
defaultValue: '0',
|
defaultValue: '0',
|
||||||
defaultShown: 'Key is not automatically rotated',
|
defaultShown: 'Key is not automatically rotated',
|
||||||
editType: 'ttl',
|
editType: 'ttl',
|
||||||
label: 'Auto-rotation period',
|
label: 'Auto-rotation period',
|
||||||
}),
|
})
|
||||||
deletionAllowed: attr('boolean'),
|
autoRotatePeriod;
|
||||||
derived: attr('boolean'),
|
|
||||||
exportable: attr('boolean'),
|
|
||||||
minDecryptionVersion: attr('number', {
|
|
||||||
defaultValue: 1,
|
|
||||||
}),
|
|
||||||
minEncryptionVersion: attr('number', {
|
|
||||||
defaultValue: 0,
|
|
||||||
}),
|
|
||||||
latestVersion: attr('number'),
|
|
||||||
keys: attr('object'),
|
|
||||||
convergentEncryption: attr('boolean'),
|
|
||||||
convergentEncryptionVersion: attr('number'),
|
|
||||||
|
|
||||||
supportsSigning: attr('boolean'),
|
@attr('boolean') deletionAllowed;
|
||||||
supportsEncryption: attr('boolean'),
|
@attr('boolean') derived;
|
||||||
supportsDecryption: attr('boolean'),
|
@attr('boolean') exportable;
|
||||||
supportsDerivation: attr('boolean'),
|
|
||||||
|
@attr('number', {
|
||||||
|
defaultValue: 1,
|
||||||
|
})
|
||||||
|
minDecryptionVersion;
|
||||||
|
|
||||||
|
@attr('number', {
|
||||||
|
defaultValue: 0,
|
||||||
|
})
|
||||||
|
minEncryptionVersion;
|
||||||
|
|
||||||
|
@attr('number') latestVersion;
|
||||||
|
@attr('object') keys;
|
||||||
|
@attr('boolean') convergentEncryption;
|
||||||
|
@attr('number') convergentEncryptionVersion;
|
||||||
|
|
||||||
|
@attr('boolean') supportsSigning;
|
||||||
|
@attr('boolean') supportsEncryption;
|
||||||
|
@attr('boolean') supportsDecryption;
|
||||||
|
@attr('boolean') supportsDerivation;
|
||||||
|
|
||||||
setConvergentEncryption(val) {
|
setConvergentEncryption(val) {
|
||||||
if (val === true) {
|
if (val === true) {
|
||||||
set(this, 'derived', val);
|
set(this, 'derived', val);
|
||||||
}
|
}
|
||||||
set(this, 'convergentEncryption', val);
|
set(this, 'convergentEncryption', val);
|
||||||
},
|
}
|
||||||
|
|
||||||
setDerived(val) {
|
setDerived(val) {
|
||||||
if (val === false) {
|
if (val === false) {
|
||||||
set(this, 'convergentEncryption', val);
|
set(this, 'convergentEncryption', val);
|
||||||
}
|
}
|
||||||
set(this, 'derived', val);
|
set(this, 'derived', val);
|
||||||
},
|
}
|
||||||
|
|
||||||
supportedActions: computed('type', function () {
|
get supportedActions() {
|
||||||
return Object.keys(ACTION_VALUES)
|
return Object.keys(ACTION_VALUES)
|
||||||
.filter((name) => {
|
.filter((name) => {
|
||||||
const { isSupported } = ACTION_VALUES[name];
|
const { isSupported } = ACTION_VALUES[name];
|
||||||
@@ -109,14 +120,14 @@ export default Model.extend({
|
|||||||
const { description, glyph } = ACTION_VALUES[name];
|
const { description, glyph } = ACTION_VALUES[name];
|
||||||
return { name, description, glyph };
|
return { name, description, glyph };
|
||||||
});
|
});
|
||||||
}),
|
}
|
||||||
|
|
||||||
canDelete: computed('deletionAllowed', 'lastLoadTS', function () {
|
get canDelete() {
|
||||||
const deleteAttrChanged = Boolean(this.changedAttributes().deletionAllowed);
|
const deleteAttrChanged = Boolean(this.changedAttributes().deletionAllowed);
|
||||||
return this.deletionAllowed && deleteAttrChanged === false;
|
return this.deletionAllowed && deleteAttrChanged === false;
|
||||||
}),
|
}
|
||||||
|
|
||||||
keyVersions: computed('validKeyVersions', function () {
|
get keyVersions() {
|
||||||
let maxVersion = Math.max(...this.validKeyVersions);
|
let maxVersion = Math.max(...this.validKeyVersions);
|
||||||
const versions = [];
|
const versions = [];
|
||||||
while (maxVersion > 0) {
|
while (maxVersion > 0) {
|
||||||
@@ -124,14 +135,9 @@ export default Model.extend({
|
|||||||
maxVersion--;
|
maxVersion--;
|
||||||
}
|
}
|
||||||
return versions;
|
return versions;
|
||||||
}),
|
}
|
||||||
|
|
||||||
encryptionKeyVersions: computed(
|
get encryptionKeyVersions() {
|
||||||
'keyVerisons',
|
|
||||||
'keyVersions',
|
|
||||||
'latestVersion',
|
|
||||||
'minDecryptionVersion',
|
|
||||||
function () {
|
|
||||||
const { keyVersions, minDecryptionVersion } = this;
|
const { keyVersions, minDecryptionVersion } = this;
|
||||||
|
|
||||||
return keyVersions
|
return keyVersions
|
||||||
@@ -140,9 +146,8 @@ export default Model.extend({
|
|||||||
})
|
})
|
||||||
.reverse();
|
.reverse();
|
||||||
}
|
}
|
||||||
),
|
|
||||||
|
|
||||||
keysForEncryption: computed('minEncryptionVersion', 'latestVersion', function () {
|
get keysForEncryption() {
|
||||||
let { minEncryptionVersion, latestVersion } = this;
|
let { minEncryptionVersion, latestVersion } = this;
|
||||||
const minVersion = clamp(minEncryptionVersion - 1, 0, latestVersion);
|
const minVersion = clamp(minEncryptionVersion - 1, 0, latestVersion);
|
||||||
const versions = [];
|
const versions = [];
|
||||||
@@ -151,13 +156,13 @@ export default Model.extend({
|
|||||||
latestVersion--;
|
latestVersion--;
|
||||||
}
|
}
|
||||||
return versions;
|
return versions;
|
||||||
}),
|
}
|
||||||
|
|
||||||
validKeyVersions: computed('keys', function () {
|
get validKeyVersions() {
|
||||||
return Object.keys(this.keys);
|
return Object.keys(this.keys);
|
||||||
}),
|
}
|
||||||
|
|
||||||
exportKeyTypes: computed('exportable', 'supportsEncryption', 'supportsSigning', 'type', function () {
|
get exportKeyTypes() {
|
||||||
const types = ['hmac'];
|
const types = ['hmac'];
|
||||||
if (this.supportsSigning) {
|
if (this.supportsSigning) {
|
||||||
types.unshift('signing');
|
types.unshift('signing');
|
||||||
@@ -166,13 +171,17 @@ export default Model.extend({
|
|||||||
types.unshift('encryption');
|
types.unshift('encryption');
|
||||||
}
|
}
|
||||||
return types;
|
return types;
|
||||||
}),
|
}
|
||||||
|
@lazyCapabilities(apiPath`${'backend'}/keys/${'id'}/rotate`, 'backend', 'id') rotatePath;
|
||||||
|
@lazyCapabilities(apiPath`${'backend'}/keys/${'id'}`, 'backend', 'id') secretPath;
|
||||||
|
|
||||||
backend: attr('string'),
|
get canRotate() {
|
||||||
|
return this.rotatePath.get('canUpdate') !== false;
|
||||||
rotatePath: lazyCapabilities(apiPath`${'backend'}/keys/${'id'}/rotate`, 'backend', 'id'),
|
}
|
||||||
canRotate: alias('rotatePath.canUpdate'),
|
get canRead() {
|
||||||
secretPath: lazyCapabilities(apiPath`${'backend'}/keys/${'id'}`, 'backend', 'id'),
|
return this.secretPath.get('canUpdate') !== false;
|
||||||
canRead: alias('secretPath.canUpdate'),
|
}
|
||||||
canEdit: alias('secretPath.canUpdate'),
|
get canEdit() {
|
||||||
});
|
return this.secretPath.get('canUpdate') !== false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { click, fillIn, find, currentURL, settled, visit, waitUntil, findAll } from '@ember/test-helpers';
|
import { click, fillIn, find, currentURL, settled, visit, findAll } from '@ember/test-helpers';
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
import { setupApplicationTest } from 'ember-qunit';
|
import { setupApplicationTest } from 'ember-qunit';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
@@ -345,17 +345,14 @@ module('Acceptance | transit (flaky)', function (hooks) {
|
|||||||
await click(SELECTORS.versionsTab);
|
await click(SELECTORS.versionsTab);
|
||||||
assert.dom(SELECTORS.versionRow(1)).hasTextContaining('Version 1', `${name}: only one key version`);
|
assert.dom(SELECTORS.versionRow(1)).hasTextContaining('Version 1', `${name}: only one key version`);
|
||||||
|
|
||||||
await waitUntil(() => find(SELECTORS.rotate.trigger));
|
|
||||||
await click(SELECTORS.rotate.trigger);
|
await click(SELECTORS.rotate.trigger);
|
||||||
await click(SELECTORS.rotate.confirm);
|
await click(SELECTORS.rotate.confirm);
|
||||||
// wait for rotate call
|
|
||||||
await waitUntil(() => find(SELECTORS.versionRow(2)));
|
|
||||||
assert.dom(SELECTORS.versionRow(2)).exists('two key versions after rotate');
|
assert.dom(SELECTORS.versionRow(2)).exists('two key versions after rotate');
|
||||||
|
|
||||||
// navigate back to actions tab
|
// navigate back to actions tab
|
||||||
await click(SELECTORS.actionsTab);
|
await click(SELECTORS.actionsTab);
|
||||||
|
|
||||||
await waitUntil(() => find(SELECTORS.card('encrypt')));
|
|
||||||
assert.dom(SELECTORS.card('encrypt')).exists(`renders encrypt action card for ${name}`);
|
assert.dom(SELECTORS.card('encrypt')).exists(`renders encrypt action card for ${name}`);
|
||||||
await click(SELECTORS.card('encrypt'));
|
await click(SELECTORS.card('encrypt'));
|
||||||
assert
|
assert
|
||||||
@@ -367,11 +364,6 @@ module('Acceptance | transit (flaky)', function (hooks) {
|
|||||||
await testConvergentEncryption(assert, name);
|
await testConvergentEncryption(assert, name);
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
|
||||||
OLD FLAKY TESTS (skipped)
|
|
||||||
It's been a while since we've updated the transit engine
|
|
||||||
keeping these tests to run locally the next time we touch that secret engine
|
|
||||||
*/
|
|
||||||
const KEY_TYPE_COMBINATIONS = [
|
const KEY_TYPE_COMBINATIONS = [
|
||||||
{
|
{
|
||||||
name: (uid) => `aes-${uid}`,
|
name: (uid) => `aes-${uid}`,
|
||||||
@@ -459,7 +451,7 @@ module('Acceptance | transit (flaky)', function (hooks) {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for (const key of KEY_TYPE_COMBINATIONS) {
|
for (const key of KEY_TYPE_COMBINATIONS) {
|
||||||
test.skip(`transit backend: ${key.type}`, async function (assert) {
|
test(`transit backend: ${key.type}`, async function (assert) {
|
||||||
assert.expect(key.convergent ? 43 : 7);
|
assert.expect(key.convergent ? 43 : 7);
|
||||||
const name = await this.generateTransitKey(key);
|
const name = await this.generateTransitKey(key);
|
||||||
await visit(`vault/secrets/${this.path}/show/${name}`);
|
await visit(`vault/secrets/${this.path}/show/${name}`);
|
||||||
@@ -473,12 +465,9 @@ module('Acceptance | transit (flaky)', function (hooks) {
|
|||||||
// wait for capabilities
|
// wait for capabilities
|
||||||
|
|
||||||
assert.dom('[data-test-transit-version]').exists({ count: 1 }, `${name}: only one key version`);
|
assert.dom('[data-test-transit-version]').exists({ count: 1 }, `${name}: only one key version`);
|
||||||
await waitUntil(() => find(SELECTORS.rotate.trigger));
|
|
||||||
await click(SELECTORS.rotate.trigger);
|
await click(SELECTORS.rotate.trigger);
|
||||||
|
|
||||||
await click(SELECTORS.rotate.confirm);
|
await click(SELECTORS.rotate.confirm);
|
||||||
// wait for rotate call
|
|
||||||
await waitUntil(() => findAll('[data-test-transit-version]').length >= 2);
|
|
||||||
assert
|
assert
|
||||||
.dom('[data-test-transit-version]')
|
.dom('[data-test-transit-version]')
|
||||||
.exists({ count: 2 }, `${name}: two key versions after rotate`);
|
.exists({ count: 2 }, `${name}: two key versions after rotate`);
|
||||||
@@ -491,7 +480,6 @@ module('Acceptance | transit (flaky)', function (hooks) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const keyAction = key.supportsEncryption ? 'encrypt' : 'sign';
|
const keyAction = key.supportsEncryption ? 'encrypt' : 'sign';
|
||||||
await waitUntil(() => find(`[data-test-transit-action-title=${keyAction}]`));
|
|
||||||
|
|
||||||
assert
|
assert
|
||||||
.dom(`[data-test-transit-action-title=${keyAction}]`)
|
.dom(`[data-test-transit-action-title=${keyAction}]`)
|
||||||
|
|||||||
Reference in New Issue
Block a user