mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 17:52:32 +00:00
* Add getRelativePath helper and use to calculate relativeNamespace * Always request capabilities-self on users root ns and prefix body with relative path * Update capabilities adapter with test * add changelog * Simplify getRelativePath logic * test update
This commit is contained in:
3
changelog/24168.txt
Normal file
3
changelog/24168.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:improvement
|
||||
ui: capabilities-self is always called in the user's root namespace
|
||||
```
|
||||
@@ -6,14 +6,28 @@
|
||||
import AdapterError from '@ember-data/adapter/error';
|
||||
import { set } from '@ember/object';
|
||||
import ApplicationAdapter from './application';
|
||||
import { sanitizePath } from 'core/utils/sanitize-path';
|
||||
|
||||
export default ApplicationAdapter.extend({
|
||||
pathForType() {
|
||||
return 'capabilities-self';
|
||||
},
|
||||
|
||||
formatPaths(path) {
|
||||
const { relativeNamespace } = this.namespaceService;
|
||||
if (!relativeNamespace) {
|
||||
return [path];
|
||||
}
|
||||
// ensure original path doesn't have leading slash
|
||||
return [`${relativeNamespace}/${path.replace(/^\//, '')}`];
|
||||
},
|
||||
|
||||
findRecord(store, type, id) {
|
||||
return this.ajax(this.buildURL(type), 'POST', { data: { paths: [id] } }).catch((e) => {
|
||||
const paths = this.formatPaths(id);
|
||||
return this.ajax(this.buildURL(type), 'POST', {
|
||||
data: { paths },
|
||||
namespace: sanitizePath(this.namespaceService.userRootNamespace),
|
||||
}).catch((e) => {
|
||||
if (e instanceof AdapterError) {
|
||||
set(e, 'policyPath', 'sys/capabilities-self');
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
import { alias, equal } from '@ember/object/computed';
|
||||
import Service, { inject as service } from '@ember/service';
|
||||
import { task } from 'ember-concurrency';
|
||||
import { computed } from '@ember/object';
|
||||
import { getRelativePath } from 'core/utils/sanitize-path';
|
||||
|
||||
const ROOT_NAMESPACE = '';
|
||||
export default Service.extend({
|
||||
@@ -20,6 +22,13 @@ export default Service.extend({
|
||||
|
||||
inRootNamespace: equal('path', ROOT_NAMESPACE),
|
||||
|
||||
relativeNamespace: computed('path', 'userRootNamespace', function () {
|
||||
// relative namespace is the current namespace minus the user's root.
|
||||
// so if we're in app/staging/group1 but the user's root is app, the
|
||||
// relative namespace is staging/group
|
||||
return getRelativePath(this.path, this.userRootNamespace);
|
||||
}),
|
||||
|
||||
setNamespace(path) {
|
||||
if (!path) {
|
||||
this.set('path', '');
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export function sanitizePath(path) {
|
||||
if (!path) return '';
|
||||
//remove whitespace + remove trailing and leading slashes
|
||||
return path.trim().replace(/^\/+|\/+$/g, '');
|
||||
}
|
||||
@@ -6,3 +7,22 @@ export function sanitizePath(path) {
|
||||
export function ensureTrailingSlash(path) {
|
||||
return path.replace(/(\w+[^/]$)/g, '$1/');
|
||||
}
|
||||
|
||||
/**
|
||||
* getRelativePath is for removing matching segments of a subpath from the front of a full path.
|
||||
* This method assumes that the full path starts with all of the root path.
|
||||
* @param {string} fullPath eg apps/prod/app_1/test
|
||||
* @param {string} rootPath eg apps/prod
|
||||
* @returns the leftover segment, eg app_1/test
|
||||
*/
|
||||
export function getRelativePath(fullPath = '', rootPath = '') {
|
||||
const root = sanitizePath(rootPath);
|
||||
const full = sanitizePath(fullPath);
|
||||
|
||||
if (!root) {
|
||||
return full;
|
||||
} else if (root === full) {
|
||||
return '';
|
||||
}
|
||||
return sanitizePath(full.substring(root.length));
|
||||
}
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
export { ensureTrailingSlash, sanitizePath } from 'core/utils/sanitize-path';
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
export { ensureTrailingSlash, sanitizePath, getRelativePath } from 'core/utils/sanitize-path';
|
||||
|
||||
@@ -24,4 +24,45 @@ module('Unit | Adapter | capabilities', function (hooks) {
|
||||
assert.deepEqual({ paths: ['foo'] }, options.data, 'data params OK');
|
||||
assert.strictEqual(method, 'POST', 'method OK');
|
||||
});
|
||||
|
||||
test('enterprise calls the correct url within namespace when userRoot = root', function (assert) {
|
||||
const namespaceSvc = this.owner.lookup('service:namespace');
|
||||
namespaceSvc.setNamespace('admin');
|
||||
|
||||
let url, method, options;
|
||||
const adapter = this.owner.factoryFor('adapter:capabilities').create({
|
||||
ajax: (...args) => {
|
||||
[url, method, options] = args;
|
||||
return resolve();
|
||||
},
|
||||
});
|
||||
|
||||
adapter.findRecord(null, 'capabilities', 'foo');
|
||||
assert.strictEqual(url, '/v1/sys/capabilities-self', 'calls the correct URL');
|
||||
assert.deepEqual({ paths: ['admin/foo'] }, options.data, 'data params prefix paths with namespace');
|
||||
assert.strictEqual(options.namespace, '', 'sent with root namespace');
|
||||
assert.strictEqual(method, 'POST', 'method OK');
|
||||
});
|
||||
|
||||
test('enterprise calls the correct url within namespace when userRoot is not root', function (assert) {
|
||||
const namespaceSvc = this.owner.lookup('service:namespace');
|
||||
namespaceSvc.setNamespace('admin/bar/baz');
|
||||
namespaceSvc.reopen({
|
||||
userRootNamespace: 'admin/bar',
|
||||
});
|
||||
|
||||
let url, method, options;
|
||||
const adapter = this.owner.factoryFor('adapter:capabilities').create({
|
||||
ajax: (...args) => {
|
||||
[url, method, options] = args;
|
||||
return resolve();
|
||||
},
|
||||
});
|
||||
|
||||
adapter.findRecord(null, 'capabilities', 'foo');
|
||||
assert.strictEqual(url, '/v1/sys/capabilities-self', 'calls the correct URL');
|
||||
assert.deepEqual({ paths: ['baz/foo'] }, options.data, 'data params prefix path with relative namespace');
|
||||
assert.strictEqual(options.namespace, 'admin/bar', 'sent with root namespace');
|
||||
assert.strictEqual(method, 'POST', 'method OK');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { ensureTrailingSlash, sanitizePath } from 'core/utils/sanitize-path';
|
||||
import { ensureTrailingSlash, getRelativePath, sanitizePath } from 'core/utils/sanitize-path';
|
||||
|
||||
module('Unit | Utility | sanitize-path', function () {
|
||||
test('it removes spaces and slashes from either side', function (assert) {
|
||||
@@ -9,10 +9,19 @@ module('Unit | Utility | sanitize-path', function () {
|
||||
'removes spaces and slashes on either side'
|
||||
);
|
||||
assert.strictEqual(sanitizePath('//foo/bar/baz/'), 'foo/bar/baz', 'removes more than one slash');
|
||||
assert.strictEqual(sanitizePath(undefined), '', 'handles falsey values');
|
||||
});
|
||||
|
||||
test('#ensureTrailingSlash', function (assert) {
|
||||
assert.strictEqual(ensureTrailingSlash('foo/bar'), 'foo/bar/', 'adds trailing slash');
|
||||
assert.strictEqual(ensureTrailingSlash('baz/'), 'baz/', 'keeps trailing slash if there is one');
|
||||
});
|
||||
|
||||
test('#getRelativePath', function (assert) {
|
||||
assert.strictEqual(getRelativePath('/', undefined), '', 'works with minimal inputs');
|
||||
assert.strictEqual(getRelativePath('/baz/bar/', undefined), 'baz/bar', 'sanitizes the output');
|
||||
assert.strictEqual(getRelativePath('recipes/cookies/choc-chip/', 'recipes/'), 'cookies/choc-chip');
|
||||
assert.strictEqual(getRelativePath('/recipes/cookies/choc-chip/', 'recipes/cookies'), 'choc-chip');
|
||||
assert.strictEqual(getRelativePath('/admin/bop/boop/admin_foo/baz/', 'admin'), 'bop/boop/admin_foo/baz');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user