UI: Add PKI role attribute no_store_metadata (#27251)

* Add noStoreMetadata attribute to pki/role model and details component

* update tests

* Make noStoreMetadata enterprise only

* update tests

* Cleanup tests

* Address PR comments
This commit is contained in:
Chelsea Shaw
2024-05-30 12:19:32 -05:00
committed by GitHub
parent d8c241838a
commit ff873b65a9
6 changed files with 124 additions and 69 deletions

View File

@@ -5,7 +5,7 @@
import { expandAttributeMeta } from 'vault/utils/field-to-attrs';
import Model from '@ember-data/model';
import { assert } from '@ember/debug';
import { debug } from '@ember/debug';
/**
* sets allByKey properties on model class. These are all the attributes on the model
@@ -41,10 +41,9 @@ export function withExpandedAttributes() {
const [key, stringArray] = Object.entries(obj)[0];
const expanded = stringArray.map((fieldName) => this.allByKey[fieldName]).filter((f) => !!f);
// if this fails, it might mean there are missing fields in the model or the model must be hydrated via OpenAPI
assert(
`all model fields found in allByKey for group ${key}`,
expanded.length === stringArray.length
);
if (expanded.length !== stringArray.length) {
debug(`not all model fields found in allByKey for group "${key}"`);
}
return { [key]: expanded };
});
}

View File

@@ -4,17 +4,32 @@
*/
import Model, { attr } from '@ember-data/model';
import { service } from '@ember/service';
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
import { withModelValidations } from 'vault/decorators/model-validations';
import { withFormFields } from 'vault/decorators/model-form-fields';
import { withExpandedAttributes } from 'vault/decorators/model-expanded-attributes';
const validations = {
name: [{ type: 'presence', message: 'Name is required.' }],
};
const fieldGroups = [
{
default: [
@withExpandedAttributes()
@withModelValidations(validations)
export default class PkiRoleModel extends Model {
@service version; // noStoreMetadata is enterprise-only, so we need this available
get useOpenAPI() {
// must be a getter so it can be accessed in path-help.js
return true;
}
getHelpUrl(backend) {
return `/v1/${backend}/roles/example?help=1`;
}
@attr('string', { readOnly: true }) backend;
get formFieldGroups() {
let defaultArray = [
'name',
'issuerRef',
'customTtl',
@@ -22,8 +37,16 @@ const fieldGroups = [
'maxTtl',
'generateLease',
'noStore',
'noStoreMetadata',
'addBasicConstraints',
],
];
if (this.version.isCommunity) {
const entFields = ['noStoreMetadata'];
defaultArray = defaultArray.filter((field) => !entFields.includes(field));
}
return this._expandGroups([
{
default: defaultArray,
},
{
'Domain handling': [
@@ -69,20 +92,8 @@ const fieldGroups = [
'postalCode',
],
},
];
@withFormFields(null, fieldGroups)
@withModelValidations(validations)
export default class PkiRoleModel extends Model {
get useOpenAPI() {
// must be a getter so it can be accessed in path-help.js
return true;
]);
}
getHelpUrl(backend) {
return `/v1/${backend}/roles/example?help=1`;
}
@attr('string', { readOnly: true }) backend;
/* Overriding OpenApi default options */
@attr('string', {
@@ -146,6 +157,14 @@ export default class PkiRoleModel extends Model {
})
noStore;
@attr('boolean', {
label: 'Do not store certificate metadata in storage backend',
detailsLabel: 'Store metadata in storage backend', // template reverses value
subText:
'We dont recommend storing metadata, since this information creates overhead in storage, and requires clean up.',
})
noStoreMetadata;
@attr('boolean', {
label: 'Basic constraints valid for non-CA',
detailsLabel: 'Add basic constraints',

View File

@@ -72,7 +72,7 @@
@value={{val}}
@alwaysRender={{true}}
/>
{{else if (eq attr.name "noStore")}}
{{else if (includes attr.name (array "noStore" "noStoreMetadata"))}}
<InfoTableRow
@label={{capitalize (or attr.options.detailsLabel attr.options.label (humanize (dasherize attr.name)))}}
@value={{not val}}

View File

@@ -191,6 +191,7 @@ export const PKI_KEYS = {
export const PKI_ROLE_DETAILS = {
issuerLabel: '[data-test-row-label="Issuer"]',
noStoreValue: '[data-test-value-div="Store in storage backend"]',
noStoreMetadataValue: '[data-test-value-div="Store metadata in storage backend"]',
keyUsageValue: '[data-test-value-div="Key usage"]',
extKeyUsageValue: '[data-test-value-div="Ext key usage"]',
customTtlValue: '[data-test-value-div="Issued certificates expire after"]',

View File

@@ -20,6 +20,7 @@ module('Integration | Component | pki role details page', function (hooks) {
name: 'Foobar',
backend: 'pki',
noStore: false,
noStoreMetadata: true,
keyUsage: [],
extKeyUsage: ['bar', 'baz'],
ttl: 600,
@@ -27,7 +28,6 @@ module('Integration | Component | pki role details page', function (hooks) {
});
test('it should render the page component', async function (assert) {
assert.expect(5);
await render(
hbs`
<Page::PkiRoleDetails @role={{this.model}} />
@@ -44,9 +44,26 @@ module('Integration | Component | pki role details page', function (hooks) {
assert
.dom(PKI_ROLE_DETAILS.noStoreValue)
.containsText('Yes', 'noStore shows opposite of what the value is');
assert
.dom(PKI_ROLE_DETAILS.noStoreMetadataValue)
.doesNotExist('does not render value for enterprise-only field');
assert.dom(PKI_ROLE_DETAILS.customTtlValue).containsText('10 minutes', 'TTL shown as duration');
});
test('it should render the enterprise-only values in enterprise edition', async function (assert) {
const version = this.owner.lookup('service:version');
version.type = 'enterprise';
await render(
hbs`
<Page::PkiRoleDetails @role={{this.model}} />
`,
{ owner: this.engine }
);
assert
.dom(PKI_ROLE_DETAILS.noStoreMetadataValue)
.containsText('No', 'noStoreMetadata shows opposite of what the value is');
});
test('it should render the notAfter date if present', async function (assert) {
assert.expect(1);
this.model = this.store.createRecord('pki/role', {

View File

@@ -37,7 +37,6 @@ module('Integration | Component | pki-role-form', function (hooks) {
});
test('it should render default fields and toggle groups', async function (assert) {
assert.expect(13);
await render(
hbs`
<PkiRoleForm
@@ -55,6 +54,9 @@ module('Integration | Component | pki-role-form', function (hooks) {
assert.dom(GENERAL.ttl.toggle('Max TTL')).exists();
assert.dom(GENERAL.fieldByAttr('generateLease')).exists();
assert.dom(GENERAL.fieldByAttr('noStore')).exists();
assert
.dom(GENERAL.fieldByAttr('noStoreMetadata'))
.doesNotExist('noStoreMetadata is not shown b/c not enterprise');
assert.dom(GENERAL.inputByAttr('addBasicConstraints')).exists();
assert.dom(PKI_ROLE_FORM.domainHandling).exists('shows form-field group add domain handling');
assert.dom(PKI_ROLE_FORM.keyParams).exists('shows form-field group key params');
@@ -66,6 +68,23 @@ module('Integration | Component | pki-role-form', function (hooks) {
.exists('shows form-field group additional subject fields');
});
test('it renders enterprise-only values in enterprise edition', async function (assert) {
const version = this.owner.lookup('service:version');
version.type = 'enterprise';
await render(
hbs`
<PkiRoleForm
@role={{this.role}}
@issuers={{this.issuers}}
@onCancel={{this.onCancel}}
@onSave={{this.onSave}}
/>
`,
{ owner: this.engine }
);
assert.dom(GENERAL.fieldByAttr('noStoreMetadata')).exists();
});
test('it should save a new pki role with various options selected', async function (assert) {
// Key usage, Key params and Not valid after options are tested in their respective component tests
assert.expect(8);