Dan Rivera 404356a805
UI: Add Skip password rotation field on DB connection creation (#29820)
* adding skip flag to db creation

* update field name & add default val change to static role

* transfer both fields to be toggle buttons

* add changelog

* test updates

* leftover

* test fixes

* fix tests pt2

* test pt3

* adding conditional to disable role type selection

* adding alert when overriding db default

* cleanup

* pr comments pt1 -  updates to logic, adding empty state  & form field test

* moving empty state placement

* updating form field logic for subtext, test fixes

* restructuring a bit to use a getter / eliminate separate function

* update

* fix typo, bring back tests

* fixes and cleanup
2025-03-12 12:44:32 -04:00

186 lines
6.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Model, { attr } from '@ember-data/model';
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
import { getRoleFields } from 'vault/utils/model-helpers/database-helpers';
import { expandAttributeMeta } from 'vault/utils/field-to-attrs';
import { withModelValidations } from 'vault/decorators/model-validations';
const validations = {
name: [{ type: 'presence', message: 'Role name is required.' }],
database: [{ type: 'presence', message: 'Database is required.' }],
type: [{ type: 'presence', message: 'Type is required.' }],
username: [
{
validator(model) {
const { type, username } = model;
if (!type || type === 'dynamic') return true;
if (username) return true;
},
message: 'Username is required.',
},
],
};
@withModelValidations(validations)
export default class RoleModel extends Model {
idPrefix = 'role/';
@attr('string', { readOnly: true }) backend;
@attr('string', { label: 'Role name' }) name;
@attr('array', {
label: 'Connection name',
editType: 'searchSelect',
fallbackComponent: 'string-list',
models: ['database/connection'],
selectLimit: 1,
onlyAllowExisting: true,
subText: 'The database connection for which credentials will be generated.',
})
database;
@attr('string', {
label: 'Type of role',
noDefault: true,
possibleValues: ['static', 'dynamic'],
})
type;
@attr({
editType: 'ttl',
defaultValue: '1h',
label: 'Generated credentialss Time-to-Live (TTL)',
helperTextDisabled: 'Vault will use a TTL of 1 hour.',
defaultShown: 'Engine default',
})
default_ttl;
@attr({
editType: 'ttl',
defaultValue: '24h',
label: 'Generated credentialss maximum Time-to-Live (Max TTL)',
helperTextDisabled: 'Vault will use a TTL of 24 hours.',
defaultShown: 'Engine default',
})
max_ttl;
@attr('string', { subText: 'The database username that this Vault role corresponds to.' }) username;
@attr({
editType: 'ttl',
defaultValue: '24h',
helperTextDisabled:
'Specifies the amount of time Vault should wait before rotating the password. The minimum is 5 seconds. Default is 24 hours.',
helperTextEnabled: 'Vault will rotate password after.',
})
rotation_period;
@attr({
label: 'Skip initial rotation',
editType: 'toggleButton',
defaultValue: false, // this defaultValue will be set in database-role-setting-form.js based on parent database value
helperTextDisabled: 'Vault will rotate password for this static role on creation.',
helperTextEnabled: "Vault will not rotate this role's password on creation.",
})
skip_import_rotation;
@attr('array', {
editType: 'stringArray',
})
creation_statements;
@attr('array', {
editType: 'stringArray',
defaultShown: 'Default',
})
revocation_statements;
@attr('array', {
editType: 'stringArray',
defaultShown: 'Default',
})
rotation_statements;
@attr('array', {
editType: 'stringArray',
defaultShown: 'Default',
})
rollback_statements;
@attr('array', {
editType: 'stringArray',
defaultShown: 'Default',
})
renew_statements;
@attr('string', {
editType: 'json',
allowReset: true,
theme: 'hashi short',
defaultShown: 'Default',
})
creation_statement;
@attr('string', {
editType: 'json',
allowReset: true,
theme: 'hashi short',
defaultShown: 'Default',
})
revocation_statement;
/* FIELD ATTRIBUTES */
get fieldAttrs() {
// Main fields on edit/create form
const fields = ['name', 'database', 'type'];
return expandAttributeMeta(this, fields);
}
get showFields() {
let fields = ['name', 'database', 'type'];
fields = fields.concat(getRoleFields(this.type)).concat(['creation_statements']);
// elasticsearch does not support revocation statements: https://developer.hashicorp.com/vault/api-docs/secret/databases/elasticdb#parameters-1
if (this.database[0] !== 'elasticsearch') {
fields = fields.concat(['revocation_statements']);
}
return expandAttributeMeta(this, fields);
}
get roleSettingAttrs() {
// logic for which get displayed is on DatabaseRoleSettingForm
const allRoleSettingFields = [
'default_ttl',
'max_ttl',
'username',
'rotation_period',
'skip_import_rotation',
'creation_statements',
'creation_statement', // for editType: JSON
'revocation_statements',
'revocation_statement', // only for MongoDB (editType: JSON)
'rotation_statements',
'rollback_statements',
'renew_statements',
];
return expandAttributeMeta(this, allRoleSettingFields);
}
/* CAPABILITIES */
// only used for secretPath
@attr('string', { readOnly: true }) path;
@lazyCapabilities(apiPath`${'backend'}/${'path'}/${'id'}`, 'backend', 'path', 'id') secretPath;
@lazyCapabilities(apiPath`${'backend'}/roles/+`, 'backend') dynamicPath;
@lazyCapabilities(apiPath`${'backend'}/static-roles/+`, 'backend') staticPath;
@lazyCapabilities(apiPath`${'backend'}/creds/${'id'}`, 'backend', 'id') credentialPath;
@lazyCapabilities(apiPath`${'backend'}/static-creds/${'id'}`, 'backend', 'id') staticCredentialPath;
@lazyCapabilities(apiPath`${'backend'}/config/${'database[0]'}`, 'backend', 'database') databasePath;
@lazyCapabilities(apiPath`${'backend'}/rotate-role/${'id'}`, 'backend', 'id') rotateRolePath;
get canEditRole() {
return this.secretPath.get('canUpdate');
}
get canDelete() {
return this.secretPath.get('canDelete');
}
get canCreateDynamic() {
return this.dynamicPath.get('canCreate');
}
get canCreateStatic() {
return this.staticPath.get('canCreate');
}
get canGenerateCredentials() {
return this.credentialPath.get('canRead');
}
get canGetCredentials() {
return this.staticCredentialPath.get('canRead');
}
get canUpdateDb() {
return this.databasePath.get('canUpdate');
}
get canRotateRoleCredentials() {
return this.rotateRolePath.get('canUpdate');
}
}