backport of commit e3c3a52b7b9f8d41c1d04f26b469b53c585587ec (#21242)

Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
This commit is contained in:
hc-github-team-secure-vault-core 2023-06-15 14:26:58 -04:00 committed by GitHub
parent 7385e73a15
commit 67feccc7dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 14 deletions

View File

@ -1,6 +1,15 @@
<div class="box is-sideless is-fullwidth is-marginless">
{{#if this.errorBanner}}
<AlertBanner @type="danger" @message={{this.errorBanner}} data-test-error-banner />
{{#if this.errors}}
<AlertBanner @type="danger" data-test-error-banner>
<ul class={{if (gt this.errors.length 1) "bullet"}}>
{{#each this.errors as |error|}}
<li>
<code>POST config/{{error.modelName}}</code>:
{{error.message}}
</li>
{{/each}}
</ul>
</AlertBanner>
{{/if}}
<form {{on "submit" (perform this.save)}}>
<fieldset class="is-shadowless is-marginless is-borderless is-fullwidth" data-test-cluster-config-edit-section>

View File

@ -37,13 +37,18 @@ interface PkiConfigCrlBooleans {
disable: boolean;
ocspDisable: boolean;
}
interface ErrorObject {
modelName: string;
message: string;
}
export default class PkiConfigurationEditComponent extends Component<Args> {
@service declare readonly router: RouterService;
@service declare readonly flashMessages: FlashMessageService;
@service declare readonly version: VersionService;
@tracked invalidFormAlert = '';
@tracked errorBanner = '';
@tracked errors: Array<ErrorObject> = [];
get isEnterprise() {
return this.version.isEnterprise;
@ -53,18 +58,32 @@ export default class PkiConfigurationEditComponent extends Component<Args> {
@waitFor
*save(event: Event) {
event.preventDefault();
try {
for (const model of ['cluster', 'acme', 'urls', 'crl']) {
// only call save() if user has permission
if (this.args[model as keyof Args].canSet) {
yield this.args[model as keyof Args].save();
this.flashMessages.success(`Successfully updated ${model} config`);
}
// first clear errors and sticky flash messages
this.errors = [];
this.flashMessages.clearMessages();
// modelName is also the API endpoint (i.e. pki/config/cluster)
for (const modelName of ['cluster', 'acme', 'urls', 'crl']) {
const model = this.args[modelName as keyof Args];
// skip saving and continue to next iteration if user does not have permission
if (!model.canSet) continue;
try {
yield model.save();
this.flashMessages.success(`Successfully updated config/${modelName}`);
} catch (error) {
const errorObject: ErrorObject = {
modelName,
message: errorMessage(error),
};
this.flashMessages.danger(`Error updating config/${modelName}`, { sticky: true });
this.errors.pushObject(errorObject);
}
this.router.transitionTo('vault.cluster.secrets.backend.pki.configuration.index');
} catch (error) {
}
if (this.errors.length) {
this.invalidFormAlert = 'There was an error submitting this form.';
this.errorBanner = errorMessage(error);
} else {
this.router.transitionTo('vault.cluster.secrets.backend.pki.configuration.index');
}
}

View File

@ -9,6 +9,7 @@ import { click, fillIn, render } from '@ember/test-helpers';
import { setupEngine } from 'ember-engines/test-support';
import { hbs } from 'ember-cli-htmlbars';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { Response } from 'miragejs';
import { SELECTORS } from 'vault/tests/helpers/pki/page/pki-configuration-edit';
import sinon from 'sinon';
import { allowAllCapabilitiesStub } from 'vault/tests/helpers/stubs';
@ -19,10 +20,14 @@ module('Integration | Component | page/pki-configuration-edit', function (hooks)
setupMirage(hooks);
hooks.beforeEach(async function () {
// test context setup
this.server.post('/sys/capabilities-self', allowAllCapabilitiesStub());
this.context = { owner: this.engine }; // this.engine set by setupEngine
this.store = this.owner.lookup('service:store');
this.cancelSpy = sinon.spy();
this.router = this.owner.lookup('service:router');
sinon.stub(this.router, 'transitionTo');
// component data setup
this.backend = 'pki-engine';
// both models only use findRecord. API parameters for pki/crl
// are set by default backend values when the engine is mounted
@ -59,6 +64,10 @@ module('Integration | Component | page/pki-configuration-edit', function (hooks)
this.urls = this.store.peekRecord('pki/config/urls', this.backend);
});
hooks.afterEach(function () {
this.router.transitionTo.restore();
});
test('it renders with config data and updates config', async function (assert) {
assert.expect(32);
this.server.post(`/${this.backend}/config/acme`, (schema, req) => {
@ -401,4 +410,49 @@ module('Integration | Component | page/pki-configuration-edit', function (hooks)
"You do not have permission to set this mount's revocation configuration Ask your administrator if you think you should have access to: POST /pki-engine/config/crl"
);
});
test('it renders alert banner and endpoint respective error', async function (assert) {
assert.expect(4);
this.server.post(`/${this.backend}/config/acme`, () => {
return new Response(500, {}, { errors: ['something wrong with acme'] });
});
this.server.post(`/${this.backend}/config/cluster`, () => {
return new Response(500, {}, { errors: ['something wrong with cluster'] });
});
this.server.post(`/${this.backend}/config/crl`, () => {
return new Response(500, {}, { errors: ['something wrong with crl'] });
});
this.server.post(`/${this.backend}/config/urls`, () => {
return new Response(500, {}, { errors: ['something wrong with urls'] });
});
await render(
hbs`
<Page::PkiConfigurationEdit
@acme={{this.acme}}
@cluster={{this.cluster}}
@urls={{this.urls}}
@crl={{this.crl}}
@backend={{this.backend}}
/>
`,
this.context
);
await click(SELECTORS.saveButton);
assert
.dom(SELECTORS.errorBanner)
.hasText(
'Error POST config/cluster: something wrong with cluster POST config/acme: something wrong with acme POST config/urls: something wrong with urls POST config/crl: something wrong with crl'
);
assert.dom(`${SELECTORS.errorBanner} ul`).hasClass('bullet');
// change 3 out of 4 requests to be successful to assert single error renders correctly
this.server.post(`/${this.backend}/config/acme`, () => new Response(200));
this.server.post(`/${this.backend}/config/cluster`, () => new Response(200));
this.server.post(`/${this.backend}/config/crl`, () => new Response(200));
await click(SELECTORS.saveButton);
assert.dom(SELECTORS.errorBanner).hasText('Error POST config/urls: something wrong with urls');
assert.dom(`${SELECTORS.errorBanner} ul`).doesNotHaveClass('bullet');
});
});