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

Backport for 1.15.x: add full path to KV v2 capabilities check #24446

Merged
merged 4 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/24404.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
ui: fix issue where kv v2 capabilities checks were not passing in the full secret path if secret was inside a directory.
```
9 changes: 7 additions & 2 deletions ui/app/models/kv/metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,14 @@ export default class KvSecretMetadataModel extends Model {
};
}

get permissionsPath() {
return this.fullSecretPath || this.path;
}

// permissions needed for the list view where kv/data has not yet been called. Allows us to conditionally show action items in the LinkedBlock popups.
@lazyCapabilities(apiPath`${'backend'}/data/${'path'}`, 'backend', 'path') dataPath;
@lazyCapabilities(apiPath`${'backend'}/metadata/${'path'}`, 'backend', 'path') metadataPath;
@lazyCapabilities(apiPath`${'backend'}/data/${'permissionsPath'}`, 'backend', 'permissionsPath') dataPath;
@lazyCapabilities(apiPath`${'backend'}/metadata/${'permissionsPath'}`, 'backend', 'permissionsPath')
metadataPath;

get canDeleteMetadata() {
return this.metadataPath.get('canDelete') !== false;
Expand Down
8 changes: 6 additions & 2 deletions ui/lib/kv/addon/components/page/list.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@
{{/if}}
{{#if metadata.canCreateVersionData}}
<li>
<LinkTo @route="secret.details.edit" @model={{metadata.fullSecretPath}}>
<LinkTo
@route="secret.details.edit"
@model={{metadata.fullSecretPath}}
data-test-popup-create-new-version
>
Create new version
</LinkTo>
</li>
Expand All @@ -98,7 +102,7 @@
@onConfirmAction={{fn this.onDelete metadata}}
@confirmMessage="This will permanently delete this secret and all its versions."
@cancelButtonText="Cancel"
data-test-delete-metadata={{metadata.path}}
data-test-popup-metadata-delete
>
Permanently delete
</ConfirmAction>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,26 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook
});
});

module('secret-nested-creator persona', function (hooks) {
hooks.beforeEach(async function () {
const token = await runCmd(
tokenWithPolicyCmd('secret-nested-creator', personas.secretNestedCreator(this.backend))
);
await authPage.login(token);
clearRecords(this.store);
return;
});
test('can create a secret from the nested list view (snc)', async function (assert) {
assert.expect(1);
// go to nested secret directory list view
await visit(`/vault/secrets/${this.backend}/kv/list/app/`);
// correct popup menu items appear on list view
const popupSelector = `${PAGE.list.item('first')} ${PAGE.popup}`;
await click(popupSelector);
assert.dom(PAGE.list.listMenuCreate).exists('shows the option to create new version');
});
});

module('enterprise controlled access persona', function (hooks) {
hooks.beforeEach(async function () {
this.controlGroup = this.owner.lookup('service:control-group');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ module('Acceptance | kv-v2 workflow | delete, undelete, destroy', function (hook
this.store = this.owner.lookup('service:store');
this.backend = `kv-delete-${uuidv4()}`;
this.secretPath = 'bad-secret';
this.nestedSecretPath = 'app/nested/bad-secret';
await authPage.login();
await runCmd(mountEngineCmd('kv-v2', this.backend), false);
await writeVersionedSecret(this.backend, this.secretPath, 'foo', 'bar', 4);
await writeVersionedSecret(this.backend, this.nestedSecretPath, 'foo', 'bar', 1);
await writeVersionedSecret(this.backend, 'nuke', 'foo', 'bar', 2);
// Delete latest version for testing undelete for users that can't delete
await runCmd(deleteLatestCmd(this.backend, 'nuke'));
Expand Down Expand Up @@ -348,6 +350,33 @@ module('Acceptance | kv-v2 workflow | delete, undelete, destroy', function (hook
});
});

module('secret-nested-creator persona', function (hooks) {
hooks.beforeEach(async function () {
const token = await runCmd(
tokenWithPolicyCmd('secret-nested-creator', personas.secretNestedCreator(this.backend))
);
await authPage.login(token);
clearRecords(this.store);
return;
});
test('can delete all secret versions from the nested list view (snc)', async function (assert) {
assert.expect(1);
// go to nested secret directory list view
await visit(`/vault/secrets/${this.backend}/kv/list/app/nested`);
// correct popup menu items appear on list view
const popupSelector = `${PAGE.list.item('bad-secret')} ${PAGE.popup}`;
await click(popupSelector);
assert.dom(PAGE.list.listMenuDelete).exists('shows the option to permanently delete');
});
test('can not delete all secret versions from root list view (snc)', async function (assert) {
assert.expect(1);
// go to root secret directory list view
await visit(`/vault/secrets/${this.backend}/kv/list`);
// shows overview card and not list view
assert.dom(PAGE.list.overviewCard).exists('renders overview card');
});
});

module('secret-creator persona', function (hooks) {
hooks.beforeEach(async function () {
const token = await runCmd(tokenWithPolicyCmd('secret-creator', personas.secretCreator(this.backend)));
Expand Down
2 changes: 2 additions & 0 deletions ui/tests/helpers/kv/kv-selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ export const PAGE = {
createSecret: '[data-test-toolbar-create-secret]',
item: (secret) => (!secret ? '[data-test-list-item]' : `[data-test-list-item="${secret}"]`),
filter: `[data-test-kv-list-filter]`,
listMenuDelete: `[data-test-popup-metadata-delete]`,
listMenuCreate: `[data-test-popup-create-new-version]`,
overviewCard: '[data-test-overview-card-container="View secret"]',
overviewInput: '[data-test-view-secret] input',
overviewButton: '[data-test-get-secret-detail]',
Expand Down
19 changes: 19 additions & 0 deletions ui/tests/helpers/policy-generator/kv.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ export const dataPolicy = ({ backend, secretPath = '*', capabilities = root }) =
`;
};

export const dataNestedPolicy = ({ backend, secretPath = '*', capabilities = root }) => {
return `
path "${backend}/data/app/${secretPath}" {
capabilities = [${format(capabilities)}]
}
`;
};

export const metadataPolicy = ({ backend, secretPath = '*', capabilities = root }) => {
// "delete" capability on this path can destroy all versions
return `
Expand All @@ -34,6 +42,14 @@ export const metadataPolicy = ({ backend, secretPath = '*', capabilities = root
`;
};

export const metadataNestedPolicy = ({ backend, secretPath = '*', capabilities = root }) => {
return `
path "${backend}/metadata/app/${secretPath}" {
capabilities = [${format(capabilities)}]
}
`;
};

export const metadataListPolicy = (backend) => {
return `
path "${backend}/metadata" {
Expand Down Expand Up @@ -76,6 +92,9 @@ export const personas = {
deleteVersionsPolicy({ backend }) +
undeleteVersionsPolicy({ backend }) +
destroyVersionsPolicy({ backend }),
secretNestedCreator: (backend) =>
dataNestedPolicy({ backend, capabilities: ['create', 'update'] }) +
metadataNestedPolicy({ backend, capabilities: ['list', 'delete'] }),
secretCreator: (backend) =>
dataPolicy({ backend, capabilities: ['create', 'update'] }) +
metadataPolicy({ backend, capabilities: ['delete'] }),
Expand Down
Loading