Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI add custom metadata to KV2 #12169

Merged
merged 43 commits into from Aug 31, 2021
Merged

UI add custom metadata to KV2 #12169

merged 43 commits into from Aug 31, 2021

Conversation

Monkeychip
Copy link
Contributor

@Monkeychip Monkeychip commented Jul 26, 2021

This PR adds custom metadata to the KV2 secret engine. It also adds the config endpoint when you're mounting the KV2 secret engine.

Here is a movie walk-through of the changes. API changes have been made on main (see PR here).

  • Shows metadata on secret-engine setup
  • Shows creation of custom metadata
  • Shows view and edit page of custom metadata
  • I log in as a user bob with a policy that only lets me list metadata but not read update or create. I, therefore, don't have access to the metadata tab.
kv.mp4

TODOs that will happen in later PRs

  • Handle new view when only have secret data permissions (e.g. no metadata). Includes a view with a search box to find secret.
  • Add test coverage.
  • Conditionally hide config options when select version 1.

@vercel vercel bot temporarily deployed to Preview – vault July 27, 2021 22:09 Inactive
@Monkeychip Monkeychip changed the base branch from main to ui/kv-custom-metadata July 27, 2021 22:11
@vercel vercel bot temporarily deployed to Preview – vault August 25, 2021 17:09 Inactive
@Monkeychip Monkeychip changed the title initial setup UI add custom metadata to KV2 Aug 25, 2021
Copy link
Contributor

@hashishaw hashishaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary comments because this review is gonna take a while 😅

}))(data);
// remove extra params from data
/*eslint no-unused-vars: ["error", { "ignoreRestSiblings": true }]*/
let { max_versions, delete_version_after, cas_required, ...newData } = data;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If any of these are undefined this will blow up, so we just need to make sure the serializer always returns those values even if they're falsey

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you could help me on this one. In my testing by trying to set all values to falsey I couldn't get it to blow up, but maybe I'm missing something.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's no way for those to be undefined, we should be good! Just wanted to call that out as a thing to test with default values for example

// for kv2 we make two network requests
if (data.type === 'kv' && data.options.version !== 1) {
// data has both data for sys mount and the config, we need to separate them
let configData = (({ max_versions, delete_version_after, cas_required }) => ({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can pull out the splitting logic to a helper method so that we can reuse it in other areas (like update) and it will be easier to catch errors and unit test there

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. Let me work on that today.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, created a new helper called split-object

Copy link
Contributor

@hashishaw hashishaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on this beast so far! 👏

};
// for validation, return array of path names already assigned
if (Ember.testing) {
this.secretPaths = ['beep', 'bop', 'boop'];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very curious why we need to hardcode this for testing 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In validation, we test for secret paths that already exist, and throw a validation if they do. This ensures the paths already exist. It also prevents us from hitting the adapter and getting an error in testing for making an adapter call that returns a 404.

if (isV2) {
secret.set('id', key);
}
if (isV2 && Object.keys(secret.changedAttributes()).length) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've run into unexpected behavior before by treating .length as a boolean. Granted, usually it had to do with JSX but it may be safer to check > 0 if that's what you're aiming for

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea.

try {
await model.save();
} catch (err) {
// error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to do anything for error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, I added handling of the error.

@action
onSaveChanges(event) {
event.preventDefault();
this.save();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're not awaiting this async method, it's possible that the method returns before save finishes. Also, since save ends with a transition I wonder if we even need the return after this line. Maybe return this.save() instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Amended.

ui/app/helpers/split-object.js Show resolved Hide resolved
</InfoTooltip>
{{/if}}
</label>
{{#if true}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need the if true?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Amended.

<div class="box is-sideless is-fullwidth is-marginless is-paddingless">
<MessageError @model={{@modelForData}} @errorMessage={{this.error}} />
<NamespaceReminder @mode="edit" @noun="secret" />
{{#if (and (not @model.failedServerRead) (not @model.selectedVersion.failedServerRead) (not-eq @model.selectedVersion.version @model.currentVersion))}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is... so much template logic 🤯 Maybe we could pull that logic into the component js file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. This was a carry-over of previous templating, but it looks a lot better inside the js file. Amended.

@@ -45,7 +45,7 @@
</button>
</li>
{{else}}
{{#if @item.canRead}}
{{#if (or @item.canReadSecretData @item.canRead)}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, so to confirm canReadSecretData is for kvv2, canRead is for kvv1? (and so on with edit and delete)

await click('[data-test-secret-edit="true"]');
await editPage.save();
await settled();
await editPage.metadataTab();
await settled();
// convert to number for IE11 browserstack test
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly we should drop that test, we're not supporting IE11 anymore. But that's out of scope for this PR 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. I'll make a note in my test ticket.

Copy link
Contributor

@hashishaw hashishaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

@Monkeychip Monkeychip merged commit 9e4a095 into main Aug 31, 2021
@Monkeychip Monkeychip deleted the ui/kv-customer-custom-metadata branch August 31, 2021 15:41
jartek pushed a commit to jartek/vault that referenced this pull request Sep 11, 2021
* initial setup

* form field editType kv is very helpful

* setting up things

* setup two routes for metadata

* routing

* clean up routing

* meh router changes not my favorite but its working

* show metadata

* add controller for backendCrumb mixin

* setting up edit metadata and trimming SecretEditMetadata component

* add edit metadata save functionality

* create new version work

* setup model and formfieldgroups for added config data.

* add config network request to secret-engine

* fix validations on config

* add config rows

* breaking up secret edit

* add validation for metadata on create

* stuff, but broken now on metadata tab

* fix metadata route error

* permissions

* saving small text changes

* permissions

* cleanup

* some test fixes and convert secret create or update to glimmer

* all these changes fix secret create kv test

* remove alert banners per design request

* fix error for array instead of object in jsonEditor

* add changelog

* styling

* turn into glimmer component

* cleanup

* test failure fix

* add delete or

* clean up

* remove all hardcoded for api integration

* add helper and fix create mode on create new version

* address chelseas pr comments

* add jsdocs to helper

* fix test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants