mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 03:27: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 { service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { buildWaiter } from '@ember/test-waiters';
|
||||
import errorMessage from 'vault/utils/error-message';
|
||||
|
||||
const waiter = buildWaiter('transit-form-show');
|
||||
|
||||
export default class TransitFormShow extends Component {
|
||||
@service store;
|
||||
@service router;
|
||||
@service flashMessages;
|
||||
|
||||
@action async rotateKey() {
|
||||
const waiterToken = waiter.beginAsync();
|
||||
const { backend, id } = this.args.key;
|
||||
try {
|
||||
await this.store.adapterFor('transit-key').keyAction('rotate', { backend, id });
|
||||
@@ -22,6 +26,8 @@ export default class TransitFormShow extends Component {
|
||||
await this.router.refresh();
|
||||
} catch (e) {
|
||||
this.flashMessages.danger(errorMessage(e));
|
||||
} finally {
|
||||
waiter.endAsync(waiterToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,102 +4,113 @@
|
||||
*/
|
||||
|
||||
import Model, { attr } from '@ember-data/model';
|
||||
import { alias } from '@ember/object/computed';
|
||||
import { set, get, computed } from '@ember/object';
|
||||
import { set, get } from '@ember/object';
|
||||
import clamp from 'vault/utils/clamp';
|
||||
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
|
||||
|
||||
const ACTION_VALUES = {
|
||||
encrypt: {
|
||||
isSupported: 'supportsEncryption',
|
||||
description: 'Looks up wrapping properties for the given token',
|
||||
description: 'Looks up wrapping properties for the given token.',
|
||||
glyph: 'lock-fill',
|
||||
},
|
||||
decrypt: {
|
||||
isSupported: 'supportsDecryption',
|
||||
description: 'Decrypts the provided ciphertext using this key',
|
||||
description: 'Decrypts the provided ciphertext using this key.',
|
||||
glyph: 'mail-open',
|
||||
},
|
||||
datakey: {
|
||||
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',
|
||||
},
|
||||
rewrap: {
|
||||
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',
|
||||
},
|
||||
sign: {
|
||||
isSupported: 'supportsSigning',
|
||||
description: 'Get the cryptographic signature of the given data',
|
||||
description: 'Get the cryptographic signature of the given data.',
|
||||
glyph: 'pencil-tool',
|
||||
},
|
||||
hmac: {
|
||||
isSupported: true,
|
||||
description: 'Generate a data digest using a hash algorithm',
|
||||
description: 'Generate a data digest using a hash algorithm.',
|
||||
glyph: 'shuffle',
|
||||
},
|
||||
verify: {
|
||||
isSupported: true,
|
||||
description: 'Validate the provided signature for the given data',
|
||||
description: 'Validate the provided signature for the given data.',
|
||||
glyph: 'check-circle',
|
||||
},
|
||||
export: {
|
||||
isSupported: 'exportable',
|
||||
description: 'Get the named key',
|
||||
description: 'Get the named key.',
|
||||
glyph: 'external-link',
|
||||
},
|
||||
};
|
||||
|
||||
export default Model.extend({
|
||||
type: attr('string', {
|
||||
export default class TransitKeyModel extends Model {
|
||||
@attr('string') backend;
|
||||
@attr('string', {
|
||||
defaultValue: 'aes256-gcm96',
|
||||
}),
|
||||
name: attr('string', {
|
||||
})
|
||||
type;
|
||||
|
||||
@attr('string', {
|
||||
label: 'Name',
|
||||
readOnly: true,
|
||||
}),
|
||||
autoRotatePeriod: attr({
|
||||
})
|
||||
name;
|
||||
|
||||
@attr({
|
||||
defaultValue: '0',
|
||||
defaultShown: 'Key is not automatically rotated',
|
||||
editType: 'ttl',
|
||||
label: 'Auto-rotation period',
|
||||
}),
|
||||
deletionAllowed: attr('boolean'),
|
||||
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'),
|
||||
})
|
||||
autoRotatePeriod;
|
||||
|
||||
supportsSigning: attr('boolean'),
|
||||
supportsEncryption: attr('boolean'),
|
||||
supportsDecryption: attr('boolean'),
|
||||
supportsDerivation: attr('boolean'),
|
||||
@attr('boolean') deletionAllowed;
|
||||
@attr('boolean') derived;
|
||||
@attr('boolean') exportable;
|
||||
|
||||
@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) {
|
||||
if (val === true) {
|
||||
set(this, 'derived', val);
|
||||
}
|
||||
set(this, 'convergentEncryption', val);
|
||||
},
|
||||
}
|
||||
|
||||
setDerived(val) {
|
||||
if (val === false) {
|
||||
set(this, 'convergentEncryption', val);
|
||||
}
|
||||
set(this, 'derived', val);
|
||||
},
|
||||
}
|
||||
|
||||
supportedActions: computed('type', function () {
|
||||
get supportedActions() {
|
||||
return Object.keys(ACTION_VALUES)
|
||||
.filter((name) => {
|
||||
const { isSupported } = ACTION_VALUES[name];
|
||||
@@ -109,14 +120,14 @@ export default Model.extend({
|
||||
const { description, glyph } = ACTION_VALUES[name];
|
||||
return { name, description, glyph };
|
||||
});
|
||||
}),
|
||||
}
|
||||
|
||||
canDelete: computed('deletionAllowed', 'lastLoadTS', function () {
|
||||
get canDelete() {
|
||||
const deleteAttrChanged = Boolean(this.changedAttributes().deletionAllowed);
|
||||
return this.deletionAllowed && deleteAttrChanged === false;
|
||||
}),
|
||||
}
|
||||
|
||||
keyVersions: computed('validKeyVersions', function () {
|
||||
get keyVersions() {
|
||||
let maxVersion = Math.max(...this.validKeyVersions);
|
||||
const versions = [];
|
||||
while (maxVersion > 0) {
|
||||
@@ -124,25 +135,19 @@ export default Model.extend({
|
||||
maxVersion--;
|
||||
}
|
||||
return versions;
|
||||
}),
|
||||
}
|
||||
|
||||
encryptionKeyVersions: computed(
|
||||
'keyVerisons',
|
||||
'keyVersions',
|
||||
'latestVersion',
|
||||
'minDecryptionVersion',
|
||||
function () {
|
||||
const { keyVersions, minDecryptionVersion } = this;
|
||||
get encryptionKeyVersions() {
|
||||
const { keyVersions, minDecryptionVersion } = this;
|
||||
|
||||
return keyVersions
|
||||
.filter((version) => {
|
||||
return version >= minDecryptionVersion;
|
||||
})
|
||||
.reverse();
|
||||
}
|
||||
),
|
||||
return keyVersions
|
||||
.filter((version) => {
|
||||
return version >= minDecryptionVersion;
|
||||
})
|
||||
.reverse();
|
||||
}
|
||||
|
||||
keysForEncryption: computed('minEncryptionVersion', 'latestVersion', function () {
|
||||
get keysForEncryption() {
|
||||
let { minEncryptionVersion, latestVersion } = this;
|
||||
const minVersion = clamp(minEncryptionVersion - 1, 0, latestVersion);
|
||||
const versions = [];
|
||||
@@ -151,13 +156,13 @@ export default Model.extend({
|
||||
latestVersion--;
|
||||
}
|
||||
return versions;
|
||||
}),
|
||||
}
|
||||
|
||||
validKeyVersions: computed('keys', function () {
|
||||
get validKeyVersions() {
|
||||
return Object.keys(this.keys);
|
||||
}),
|
||||
}
|
||||
|
||||
exportKeyTypes: computed('exportable', 'supportsEncryption', 'supportsSigning', 'type', function () {
|
||||
get exportKeyTypes() {
|
||||
const types = ['hmac'];
|
||||
if (this.supportsSigning) {
|
||||
types.unshift('signing');
|
||||
@@ -166,13 +171,17 @@ export default Model.extend({
|
||||
types.unshift('encryption');
|
||||
}
|
||||
return types;
|
||||
}),
|
||||
}
|
||||
@lazyCapabilities(apiPath`${'backend'}/keys/${'id'}/rotate`, 'backend', 'id') rotatePath;
|
||||
@lazyCapabilities(apiPath`${'backend'}/keys/${'id'}`, 'backend', 'id') secretPath;
|
||||
|
||||
backend: attr('string'),
|
||||
|
||||
rotatePath: lazyCapabilities(apiPath`${'backend'}/keys/${'id'}/rotate`, 'backend', 'id'),
|
||||
canRotate: alias('rotatePath.canUpdate'),
|
||||
secretPath: lazyCapabilities(apiPath`${'backend'}/keys/${'id'}`, 'backend', 'id'),
|
||||
canRead: alias('secretPath.canUpdate'),
|
||||
canEdit: alias('secretPath.canUpdate'),
|
||||
});
|
||||
get canRotate() {
|
||||
return this.rotatePath.get('canUpdate') !== false;
|
||||
}
|
||||
get canRead() {
|
||||
return this.secretPath.get('canUpdate') !== false;
|
||||
}
|
||||
get canEdit() {
|
||||
return this.secretPath.get('canUpdate') !== false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* 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 { setupApplicationTest } from 'ember-qunit';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
@@ -345,17 +345,14 @@ module('Acceptance | transit (flaky)', function (hooks) {
|
||||
await click(SELECTORS.versionsTab);
|
||||
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.confirm);
|
||||
// wait for rotate call
|
||||
await waitUntil(() => find(SELECTORS.versionRow(2)));
|
||||
|
||||
assert.dom(SELECTORS.versionRow(2)).exists('two key versions after rotate');
|
||||
|
||||
// navigate back to actions tab
|
||||
await click(SELECTORS.actionsTab);
|
||||
|
||||
await waitUntil(() => find(SELECTORS.card('encrypt')));
|
||||
assert.dom(SELECTORS.card('encrypt')).exists(`renders encrypt action card for ${name}`);
|
||||
await click(SELECTORS.card('encrypt'));
|
||||
assert
|
||||
@@ -367,11 +364,6 @@ module('Acceptance | transit (flaky)', function (hooks) {
|
||||
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 = [
|
||||
{
|
||||
name: (uid) => `aes-${uid}`,
|
||||
@@ -459,7 +451,7 @@ module('Acceptance | transit (flaky)', function (hooks) {
|
||||
];
|
||||
|
||||
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);
|
||||
const name = await this.generateTransitKey(key);
|
||||
await visit(`vault/secrets/${this.path}/show/${name}`);
|
||||
@@ -473,12 +465,9 @@ module('Acceptance | transit (flaky)', function (hooks) {
|
||||
// wait for capabilities
|
||||
|
||||
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.confirm);
|
||||
// wait for rotate call
|
||||
await waitUntil(() => findAll('[data-test-transit-version]').length >= 2);
|
||||
assert
|
||||
.dom('[data-test-transit-version]')
|
||||
.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';
|
||||
await waitUntil(() => find(`[data-test-transit-action-title=${keyAction}]`));
|
||||
|
||||
assert
|
||||
.dom(`[data-test-transit-action-title=${keyAction}]`)
|
||||
|
||||
Reference in New Issue
Block a user