From ff873b65a9a66caf7f11139c2b4baf8a6bc86419 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
Date: Thu, 30 May 2024 12:19:32 -0500
Subject: [PATCH] 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
---
.../decorators/model-expanded-attributes.js | 9 +-
ui/app/models/pki/role.js | 141 ++++++++++--------
.../components/page/pki-role-details.hbs | 2 +-
ui/tests/helpers/pki/pki-selectors.ts | 1 +
.../pki/page/pki-role-details-test.js | 19 ++-
.../components/pki/pki-role-form-test.js | 21 ++-
6 files changed, 124 insertions(+), 69 deletions(-)
diff --git a/ui/app/decorators/model-expanded-attributes.js b/ui/app/decorators/model-expanded-attributes.js
index 8272505425..2eb40e56e6 100644
--- a/ui/app/decorators/model-expanded-attributes.js
+++ b/ui/app/decorators/model-expanded-attributes.js
@@ -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 };
});
}
diff --git a/ui/app/models/pki/role.js b/ui/app/models/pki/role.js
index b7fe845fe6..25704a8719 100644
--- a/ui/app/models/pki/role.js
+++ b/ui/app/models/pki/role.js
@@ -4,76 +4,20 @@
*/
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: [
- 'name',
- 'issuerRef',
- 'customTtl',
- 'notBeforeDuration',
- 'maxTtl',
- 'generateLease',
- 'noStore',
- 'addBasicConstraints',
- ],
- },
- {
- 'Domain handling': [
- 'allowedDomains',
- 'allowedDomainsTemplate',
- 'allowBareDomains',
- 'allowSubdomains',
- 'allowGlobDomains',
- 'allowWildcardCertificates',
- 'allowLocalhost', // default: true (returned true by OpenApi)
- 'allowAnyName',
- 'enforceHostnames', // default: true (returned true by OpenApi)
- ],
- },
- {
- 'Key parameters': ['keyType', 'keyBits', 'signatureBits'],
- },
- {
- 'Key usage': ['keyUsage', 'extKeyUsage', 'extKeyUsageOids'],
- },
- { 'Policy identifiers': ['policyIdentifiers'] },
- {
- 'Subject Alternative Name (SAN) Options': [
- 'allowIpSans',
- 'allowedUriSans',
- 'allowUriSansTemplate',
- 'allowedOtherSans',
- ],
- },
- {
- 'Additional subject fields': [
- 'allowedUserIds',
- 'allowedSerialNumbers',
- 'requireCn',
- 'useCsrCommonName',
- 'useCsrSans',
- 'ou',
- 'organization',
- 'country',
- 'locality',
- 'province',
- 'streetAddress',
- 'postalCode',
- ],
- },
-];
-
-@withFormFields(null, fieldGroups)
+@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;
@@ -84,6 +28,73 @@ export default class PkiRoleModel extends Model {
@attr('string', { readOnly: true }) backend;
+ get formFieldGroups() {
+ let defaultArray = [
+ 'name',
+ 'issuerRef',
+ 'customTtl',
+ 'notBeforeDuration',
+ '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': [
+ 'allowedDomains',
+ 'allowedDomainsTemplate',
+ 'allowBareDomains',
+ 'allowSubdomains',
+ 'allowGlobDomains',
+ 'allowWildcardCertificates',
+ 'allowLocalhost', // default: true (returned true by OpenApi)
+ 'allowAnyName',
+ 'enforceHostnames', // default: true (returned true by OpenApi)
+ ],
+ },
+ {
+ 'Key parameters': ['keyType', 'keyBits', 'signatureBits'],
+ },
+ {
+ 'Key usage': ['keyUsage', 'extKeyUsage', 'extKeyUsageOids'],
+ },
+ { 'Policy identifiers': ['policyIdentifiers'] },
+ {
+ 'Subject Alternative Name (SAN) Options': [
+ 'allowIpSans',
+ 'allowedUriSans',
+ 'allowUriSansTemplate',
+ 'allowedOtherSans',
+ ],
+ },
+ {
+ 'Additional subject fields': [
+ 'allowedUserIds',
+ 'allowedSerialNumbers',
+ 'requireCn',
+ 'useCsrCommonName',
+ 'useCsrSans',
+ 'ou',
+ 'organization',
+ 'country',
+ 'locality',
+ 'province',
+ 'streetAddress',
+ 'postalCode',
+ ],
+ },
+ ]);
+ }
+
/* Overriding OpenApi default options */
@attr('string', {
label: 'Role name',
@@ -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 don’t 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',
diff --git a/ui/lib/pki/addon/components/page/pki-role-details.hbs b/ui/lib/pki/addon/components/page/pki-role-details.hbs
index e06510b234..9ed5c90a89 100644
--- a/ui/lib/pki/addon/components/page/pki-role-details.hbs
+++ b/ui/lib/pki/addon/components/page/pki-role-details.hbs
@@ -72,7 +72,7 @@
@value={{val}}
@alwaysRender={{true}}
/>
- {{else if (eq attr.name "noStore")}}
+ {{else if (includes attr.name (array "noStore" "noStoreMetadata"))}}
@@ -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`
+
+ `,
+ { 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', {
diff --git a/ui/tests/integration/components/pki/pki-role-form-test.js b/ui/tests/integration/components/pki/pki-role-form-test.js
index c89b085380..107da6f8e1 100644
--- a/ui/tests/integration/components/pki/pki-role-form-test.js
+++ b/ui/tests/integration/components/pki/pki-role-form-test.js
@@ -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`
+ `,
+ { 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);