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 { expandAttributeMeta } from 'vault/utils/field-to-attrs';
import Model from '@ember-data/model'; 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 * 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 [key, stringArray] = Object.entries(obj)[0];
const expanded = stringArray.map((fieldName) => this.allByKey[fieldName]).filter((f) => !!f); 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 // if this fails, it might mean there are missing fields in the model or the model must be hydrated via OpenAPI
assert( if (expanded.length !== stringArray.length) {
`all model fields found in allByKey for group ${key}`, debug(`not all model fields found in allByKey for group "${key}"`);
expanded.length === stringArray.length }
);
return { [key]: expanded }; return { [key]: expanded };
}); });
} }

View File

@@ -4,17 +4,32 @@
*/ */
import Model, { attr } from '@ember-data/model'; import Model, { attr } from '@ember-data/model';
import { service } from '@ember/service';
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities'; import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
import { withModelValidations } from 'vault/decorators/model-validations'; 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 = { const validations = {
name: [{ type: 'presence', message: 'Name is required.' }], name: [{ type: 'presence', message: 'Name is required.' }],
}; };
const fieldGroups = [ @withExpandedAttributes()
{ @withModelValidations(validations)
default: [ 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', 'name',
'issuerRef', 'issuerRef',
'customTtl', 'customTtl',
@@ -22,8 +37,16 @@ const fieldGroups = [
'maxTtl', 'maxTtl',
'generateLease', 'generateLease',
'noStore', 'noStore',
'noStoreMetadata',
'addBasicConstraints', 'addBasicConstraints',
], ];
if (this.version.isCommunity) {
const entFields = ['noStoreMetadata'];
defaultArray = defaultArray.filter((field) => !entFields.includes(field));
}
return this._expandGroups([
{
default: defaultArray,
}, },
{ {
'Domain handling': [ 'Domain handling': [
@@ -69,20 +92,8 @@ const fieldGroups = [
'postalCode', '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 */ /* Overriding OpenApi default options */
@attr('string', { @attr('string', {
@@ -146,6 +157,14 @@ export default class PkiRoleModel extends Model {
}) })
noStore; 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', { @attr('boolean', {
label: 'Basic constraints valid for non-CA', label: 'Basic constraints valid for non-CA',
detailsLabel: 'Add basic constraints', detailsLabel: 'Add basic constraints',

View File

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

View File

@@ -191,6 +191,7 @@ export const PKI_KEYS = {
export const PKI_ROLE_DETAILS = { export const PKI_ROLE_DETAILS = {
issuerLabel: '[data-test-row-label="Issuer"]', issuerLabel: '[data-test-row-label="Issuer"]',
noStoreValue: '[data-test-value-div="Store in storage backend"]', 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"]', keyUsageValue: '[data-test-value-div="Key usage"]',
extKeyUsageValue: '[data-test-value-div="Ext key usage"]', extKeyUsageValue: '[data-test-value-div="Ext key usage"]',
customTtlValue: '[data-test-value-div="Issued certificates expire after"]', 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', name: 'Foobar',
backend: 'pki', backend: 'pki',
noStore: false, noStore: false,
noStoreMetadata: true,
keyUsage: [], keyUsage: [],
extKeyUsage: ['bar', 'baz'], extKeyUsage: ['bar', 'baz'],
ttl: 600, 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) { test('it should render the page component', async function (assert) {
assert.expect(5);
await render( await render(
hbs` hbs`
<Page::PkiRoleDetails @role={{this.model}} /> <Page::PkiRoleDetails @role={{this.model}} />
@@ -44,9 +44,26 @@ module('Integration | Component | pki role details page', function (hooks) {
assert assert
.dom(PKI_ROLE_DETAILS.noStoreValue) .dom(PKI_ROLE_DETAILS.noStoreValue)
.containsText('Yes', 'noStore shows opposite of what the value is'); .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'); 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) { test('it should render the notAfter date if present', async function (assert) {
assert.expect(1); assert.expect(1);
this.model = this.store.createRecord('pki/role', { 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) { test('it should render default fields and toggle groups', async function (assert) {
assert.expect(13);
await render( await render(
hbs` hbs`
<PkiRoleForm <PkiRoleForm
@@ -55,6 +54,9 @@ module('Integration | Component | pki-role-form', function (hooks) {
assert.dom(GENERAL.ttl.toggle('Max TTL')).exists(); assert.dom(GENERAL.ttl.toggle('Max TTL')).exists();
assert.dom(GENERAL.fieldByAttr('generateLease')).exists(); assert.dom(GENERAL.fieldByAttr('generateLease')).exists();
assert.dom(GENERAL.fieldByAttr('noStore')).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(GENERAL.inputByAttr('addBasicConstraints')).exists();
assert.dom(PKI_ROLE_FORM.domainHandling).exists('shows form-field group add domain handling'); 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'); 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'); .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) { 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 // Key usage, Key params and Not valid after options are tested in their respective component tests
assert.expect(8); assert.expect(8);