Merge branch 'master-oss' into approle-local-secretid
This commit is contained in:
commit
19e3f43573
|
@ -46,6 +46,9 @@ IMPROVEMENTS:
|
||||||
the rate of writes committed
|
the rate of writes committed
|
||||||
* secret/ssh: Update dynamic key install script to use shell locking to avoid
|
* secret/ssh: Update dynamic key install script to use shell locking to avoid
|
||||||
concurrent modifications [GH-4358]
|
concurrent modifications [GH-4358]
|
||||||
|
* ui: Access to `sys/mounts` is no longer needed to use the UI - the list of
|
||||||
|
engines will show you the ones you implicitly have access to (because you have
|
||||||
|
access to to secrets in those engines) [GH-4439]
|
||||||
|
|
||||||
BUG FIXES:
|
BUG FIXES:
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
import ApplicationAdapter from './application';
|
import ApplicationAdapter from './application';
|
||||||
import DS from 'ember-data';
|
|
||||||
|
|
||||||
export default ApplicationAdapter.extend({
|
export default ApplicationAdapter.extend({
|
||||||
url(path) {
|
url(path) {
|
||||||
|
@ -8,30 +7,16 @@ export default ApplicationAdapter.extend({
|
||||||
return path ? url + '/' + path : url;
|
return path ? url + '/' + path : url;
|
||||||
},
|
},
|
||||||
|
|
||||||
pathForType(type) {
|
pathForType() {
|
||||||
let path;
|
return 'mounts';
|
||||||
switch (type) {
|
|
||||||
case 'cluster':
|
|
||||||
path = 'clusters';
|
|
||||||
break;
|
|
||||||
case 'secret-engine':
|
|
||||||
path = 'mounts';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
path = Ember.String.pluralize(type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
query() {
|
query(store, type, query) {
|
||||||
return this.ajax(this.url(), 'GET').catch(e => {
|
let url = `/${this.urlPrefix()}/internal/ui/mounts`;
|
||||||
if (e instanceof DS.AdapterError) {
|
if (query.path) {
|
||||||
Ember.set(e, 'policyPath', 'sys/mounts');
|
url = `${url}/${query.path}`;
|
||||||
}
|
}
|
||||||
|
return this.ajax(url, 'GET');
|
||||||
throw e;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
createRecord(store, type, snapshot) {
|
createRecord(store, type, snapshot) {
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
|
||||||
queryParams: {
|
|
||||||
selectedAction: 'action',
|
|
||||||
},
|
|
||||||
|
|
||||||
selectedAction: 'wrap',
|
|
||||||
});
|
|
|
@ -116,7 +116,6 @@ Router.map(function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.route('response-wrapping');
|
|
||||||
this.route('not-found', { path: '/*path' });
|
this.route('not-found', { path: '/*path' });
|
||||||
});
|
});
|
||||||
this.route('not-found', { path: '/*path' });
|
this.route('not-found', { path: '/*path' });
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
import ClusterRoute from 'vault/mixins/cluster-route';
|
import ClusterRoute from 'vault/mixins/cluster-route';
|
||||||
|
|
||||||
export default Ember.Route.extend(ClusterRoute, {
|
export default Ember.Route.extend(ClusterRoute);
|
||||||
model() {
|
|
||||||
return this.store.query('secret-engine', {});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
|
@ -2,19 +2,31 @@ import Ember from 'ember';
|
||||||
const { inject } = Ember;
|
const { inject } = Ember;
|
||||||
export default Ember.Route.extend({
|
export default Ember.Route.extend({
|
||||||
flashMessages: inject.service(),
|
flashMessages: inject.service(),
|
||||||
beforeModel(transition) {
|
model(params) {
|
||||||
const target = transition.targetName;
|
let { backend } = params;
|
||||||
const { backend } = this.paramsFor(this.routeName);
|
return this.store
|
||||||
const backendModel = this.store.peekRecord('secret-engine', backend);
|
.query('secret-engine', {
|
||||||
const type = backendModel && backendModel.get('type');
|
path: backend,
|
||||||
if (type === 'kv' && backendModel.get('options.version') === 2) {
|
})
|
||||||
|
.then(model => {
|
||||||
|
if (model) {
|
||||||
|
return model.get('firstObject');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
afterModel(model, transition) {
|
||||||
|
let target = transition.targetName;
|
||||||
|
let path = model && model.get('path');
|
||||||
|
let type = model && model.get('type');
|
||||||
|
if (type === 'kv' && model.get('options.version') === 2) {
|
||||||
this.get('flashMessages').stickyInfo(
|
this.get('flashMessages').stickyInfo(
|
||||||
`"${backend}" is a newer version of the KV backend. The Vault UI does not currently support the additional versioning features. All actions taken through the UI in this engine will operate on the most recent version of a secret.`
|
`"${path}" is a newer version of the KV backend. The Vault UI does not currently support the additional versioning features. All actions taken through the UI in this engine will operate on the most recent version of a secret.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target === this.routeName) {
|
if (target === this.routeName) {
|
||||||
return this.replaceWith('vault.cluster.secrets.backend.list-root', backend);
|
return this.replaceWith('vault.cluster.secrets.backend.list-root', path);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,8 +7,7 @@ export default Ember.Route.extend(UnloadModel, {
|
||||||
templateName: 'vault/cluster/secrets/backend/credentials',
|
templateName: 'vault/cluster/secrets/backend/credentials',
|
||||||
|
|
||||||
backendModel() {
|
backendModel() {
|
||||||
const backend = this.paramsFor('vault.cluster.secrets.backend').backend;
|
return this.modelFor('vault.cluster.secrets.backend');
|
||||||
return this.store.peekRecord('secret-engine', backend);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
pathQuery(role, backend) {
|
pathQuery(role, backend) {
|
||||||
|
|
|
@ -45,7 +45,7 @@ export default Ember.Route.extend({
|
||||||
model(params) {
|
model(params) {
|
||||||
const secret = params.secret ? params.secret : '';
|
const secret = params.secret ? params.secret : '';
|
||||||
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
|
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
|
||||||
const backends = this.modelFor('vault.cluster.secrets').mapBy('id');
|
const backendModel = this.modelFor('vault.cluster.secrets.backend');
|
||||||
return Ember.RSVP.hash({
|
return Ember.RSVP.hash({
|
||||||
secret,
|
secret,
|
||||||
secrets: this.store
|
secrets: this.store
|
||||||
|
@ -62,12 +62,12 @@ export default Ember.Route.extend({
|
||||||
return model;
|
return model;
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
if (backends.includes(backend) && err.httpStatus === 404 && secret === '') {
|
if (backendModel && err.httpStatus === 404 && secret === '') {
|
||||||
return [];
|
return [];
|
||||||
} else {
|
} else {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -138,11 +138,9 @@ export default Ember.Route.extend({
|
||||||
error(error, transition) {
|
error(error, transition) {
|
||||||
const { secret } = this.paramsFor(this.routeName);
|
const { secret } = this.paramsFor(this.routeName);
|
||||||
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
|
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
|
||||||
const backends = this.modelFor('vault.cluster.secrets').mapBy('id');
|
|
||||||
|
|
||||||
Ember.set(error, 'secret', secret);
|
Ember.set(error, 'secret', secret);
|
||||||
Ember.set(error, 'isRoot', true);
|
Ember.set(error, 'isRoot', true);
|
||||||
Ember.set(error, 'hasBackend', backends.includes(backend));
|
|
||||||
Ember.set(error, 'backend', backend);
|
Ember.set(error, 'backend', backend);
|
||||||
const hasModel = this.controllerFor(this.routeName).get('hasModel');
|
const hasModel = this.controllerFor(this.routeName).get('hasModel');
|
||||||
// only swallow the error if we have a previous model
|
// only swallow the error if we have a previous model
|
||||||
|
|
|
@ -5,7 +5,7 @@ import UnloadModelRoute from 'vault/mixins/unload-model-route';
|
||||||
export default Ember.Route.extend(UnloadModelRoute, {
|
export default Ember.Route.extend(UnloadModelRoute, {
|
||||||
capabilities(secret) {
|
capabilities(secret) {
|
||||||
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
|
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
|
||||||
let backendModel = this.store.peekRecord('secret-engine', backend);
|
let backendModel = this.modelFor('vault.cluster.secrets.backend');
|
||||||
let backendType = backendModel.get('type');
|
let backendType = backendModel.get('type');
|
||||||
let version = backendModel.get('options.version');
|
let version = backendModel.get('options.version');
|
||||||
let path;
|
let path;
|
||||||
|
@ -21,8 +21,8 @@ export default Ember.Route.extend(UnloadModelRoute, {
|
||||||
return this.store.findRecord('capabilities', path);
|
return this.store.findRecord('capabilities', path);
|
||||||
},
|
},
|
||||||
|
|
||||||
backendType(path) {
|
backendType() {
|
||||||
return this.store.peekRecord('secret-engine', path).get('type');
|
return this.modelFor('vault.cluster.secrets.backend').get('type');
|
||||||
},
|
},
|
||||||
|
|
||||||
templateName: 'vault/cluster/secrets/backend/secretEditLayout',
|
templateName: 'vault/cluster/secrets/backend/secretEditLayout',
|
||||||
|
@ -50,7 +50,7 @@ export default Ember.Route.extend(UnloadModelRoute, {
|
||||||
aws: 'role-aws',
|
aws: 'role-aws',
|
||||||
pki: secret && secret.startsWith('cert/') ? 'pki-certificate' : 'role-pki',
|
pki: secret && secret.startsWith('cert/') ? 'pki-certificate' : 'role-pki',
|
||||||
};
|
};
|
||||||
let backendModel = this.store.peekRecord('secret-engine', backend);
|
let backendModel = this.modelFor('vault.cluster.secrets.backend', backend);
|
||||||
let defaultType = 'secret';
|
let defaultType = 'secret';
|
||||||
if (backendModel.get('type') === 'kv' && backendModel.get('options.version') === 2) {
|
if (backendModel.get('type') === 'kv' && backendModel.get('options.version') === 2) {
|
||||||
defaultType = 'secret-v2';
|
defaultType = 'secret-v2';
|
||||||
|
@ -81,7 +81,7 @@ export default Ember.Route.extend(UnloadModelRoute, {
|
||||||
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
|
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
|
||||||
const preferAdvancedEdit =
|
const preferAdvancedEdit =
|
||||||
this.controllerFor('vault.cluster.secrets.backend').get('preferAdvancedEdit') || false;
|
this.controllerFor('vault.cluster.secrets.backend').get('preferAdvancedEdit') || false;
|
||||||
const backendType = this.backendType(backend);
|
const backendType = this.backendType();
|
||||||
model.secret.setProperties({ backend });
|
model.secret.setProperties({ backend });
|
||||||
controller.setProperties({
|
controller.setProperties({
|
||||||
model: model.secret,
|
model: model.secret,
|
||||||
|
@ -105,10 +105,8 @@ export default Ember.Route.extend(UnloadModelRoute, {
|
||||||
error(error) {
|
error(error) {
|
||||||
const { secret } = this.paramsFor(this.routeName);
|
const { secret } = this.paramsFor(this.routeName);
|
||||||
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
|
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
|
||||||
const backends = this.modelFor('vault.cluster.secrets').mapBy('id');
|
|
||||||
Ember.set(error, 'keyId', backend + '/' + secret);
|
Ember.set(error, 'keyId', backend + '/' + secret);
|
||||||
Ember.set(error, 'backend', backend);
|
Ember.set(error, 'backend', backend);
|
||||||
Ember.set(error, 'hasBackend', backends.includes(backend));
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,7 @@ export default Ember.Route.extend(UnloadModel, {
|
||||||
templateName: 'vault/cluster/secrets/backend/sign',
|
templateName: 'vault/cluster/secrets/backend/sign',
|
||||||
|
|
||||||
backendModel() {
|
backendModel() {
|
||||||
const backend = this.paramsFor('vault.cluster.secrets.backend').backend;
|
return this.modelFor('vault.cluster.secrets.backend');
|
||||||
return this.store.peekRecord('secret-engine', backend);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
pathQuery(role, backend) {
|
pathQuery(role, backend) {
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import Ember from 'ember';
|
||||||
|
|
||||||
|
export default Ember.Route.extend({
|
||||||
|
model() {
|
||||||
|
return this.store.query('secret-engine', {});
|
||||||
|
},
|
||||||
|
});
|
|
@ -6,8 +6,8 @@ const CONFIGURABLE_BACKEND_TYPES = ['aws', 'ssh', 'pki'];
|
||||||
export default Ember.Route.extend({
|
export default Ember.Route.extend({
|
||||||
model() {
|
model() {
|
||||||
const { backend } = this.paramsFor(this.routeName);
|
const { backend } = this.paramsFor(this.routeName);
|
||||||
return this.store.query('secret-engine', {}).then(() => {
|
return this.store.query('secret-engine', { path: backend }).then(modelList => {
|
||||||
const model = this.store.peekRecord('secret-engine', backend);
|
let model = modelList && modelList.get('firstObject');
|
||||||
if (!model || !CONFIGURABLE_BACKEND_TYPES.includes(model.get('type'))) {
|
if (!model || !CONFIGURABLE_BACKEND_TYPES.includes(model.get('type'))) {
|
||||||
const error = new DS.AdapterError();
|
const error = new DS.AdapterError();
|
||||||
Ember.set(error, 'httpStatus', 404);
|
Ember.set(error, 'httpStatus', 404);
|
||||||
|
|
|
@ -38,7 +38,17 @@ export default DS.RESTSerializer.extend({
|
||||||
} else if (isQueryRecord) {
|
} else if (isQueryRecord) {
|
||||||
backends = this.normalizeBackend(null, payload);
|
backends = this.normalizeBackend(null, payload);
|
||||||
} else {
|
} else {
|
||||||
|
// this is terrible, I'm sorry
|
||||||
|
// TODO extract AWS and SSH config saving from the secret-engine model to simplify this
|
||||||
|
if (payload.data.secret) {
|
||||||
|
backends = Object.keys(payload.data.secret).map(id =>
|
||||||
|
this.normalizeBackend(id, payload.data.secret[id])
|
||||||
|
);
|
||||||
|
} else if (!payload.data.path) {
|
||||||
backends = Object.keys(payload.data).map(id => this.normalizeBackend(id, payload[id]));
|
backends = Object.keys(payload.data).map(id => this.normalizeBackend(id, payload[id]));
|
||||||
|
} else {
|
||||||
|
backends = [this.normalizeBackend(payload.data.path, payload.data)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const transformedPayload = { [primaryModelClass.modelName]: backends };
|
const transformedPayload = { [primaryModelClass.modelName]: backends };
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
value={{time}}
|
value={{time}}
|
||||||
id="time-{{elementId}}"
|
id="time-{{elementId}}"
|
||||||
type="text"
|
type="text"
|
||||||
name="time-{{elementId}}"
|
name="time"
|
||||||
class="input"
|
class="input"
|
||||||
oninput={{action 'changedValue' 'time'}}
|
oninput={{action 'changedValue' 'time'}}
|
||||||
/>
|
/>
|
||||||
|
@ -15,8 +15,8 @@
|
||||||
<div class="select is-fullwidth">
|
<div class="select is-fullwidth">
|
||||||
<select
|
<select
|
||||||
data-test-ttl-unit
|
data-test-ttl-unit
|
||||||
name="unit-{{elementId}}"
|
name="unit"
|
||||||
id="unit-{{elementId}}"
|
id="unit"
|
||||||
onchange={{action 'changedValue' 'unit'}}
|
onchange={{action 'changedValue' 'unit'}}
|
||||||
>
|
>
|
||||||
{{#each unitOptions as |unitOption|}}
|
{{#each unitOptions as |unitOption|}}
|
||||||
|
|
|
@ -26,17 +26,6 @@
|
||||||
<p>
|
<p>
|
||||||
Make sure the policy for the path <code>{{model.policyPath}}</code> includes <code>capabilities = ['update']</code>.
|
Make sure the policy for the path <code>{{model.policyPath}}</code> includes <code>capabilities = ['update']</code>.
|
||||||
</p>
|
</p>
|
||||||
{{else if (and
|
|
||||||
(eq model.httpStatus 403)
|
|
||||||
(eq model.policyPath 'sys/mounts')
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
<p data-test-sys-mounts-warning>
|
|
||||||
Your auth token does not have access to {{model.policyPath}}. This is necessary in order to browse secret backends.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Make sure the policy for the path <code>{{model.policyPath}}</code> has <code>capabilities = ['list', 'read']</code>.
|
|
||||||
</p>
|
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if model.message}}
|
{{#if model.message}}
|
||||||
<p>{{model.message}}</p>
|
<p>{{model.message}}</p>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<header class="page-header">
|
<header class="page-header">
|
||||||
<nav class="breadcrumb">
|
<nav class="breadcrumb">
|
||||||
<li>
|
<li>
|
||||||
<a href={{href-to params=(if model.hasBackend
|
<a href={{href-to params=(if model.backend
|
||||||
(array "vault.cluster.secrets.backend.list-root")
|
(array "vault.cluster.secrets.backend.list-root")
|
||||||
(array "vault.cluster.secrets")
|
(array "vault.cluster.secrets")
|
||||||
)
|
)
|
||||||
|
@ -30,9 +30,9 @@
|
||||||
{{#if (eq model.httpStatus 404)}}
|
{{#if (eq model.httpStatus 404)}}
|
||||||
<p data-test-secret-not-found>
|
<p data-test-secret-not-found>
|
||||||
Unable to find secret at <code>{{concat model.backend "/" model.secret}}</code>. Try going back to the
|
Unable to find secret at <code>{{concat model.backend "/" model.secret}}</code>. Try going back to the
|
||||||
{{#link-to params=(if model.hasBackend
|
{{#link-to params=(if model.backend
|
||||||
(reduce-to-array "vault.cluster.secrets.backend.list-root")
|
(array "vault.cluster.secrets.backend.list-root")
|
||||||
(reduce-to-array "vault.cluster.secrets")
|
(array "vault.cluster.secrets")
|
||||||
)
|
)
|
||||||
}}root{{/link-to}}
|
}}root{{/link-to}}
|
||||||
and navigating from there.
|
and navigating from there.
|
||||||
|
|
|
@ -27,9 +27,10 @@
|
||||||
<div class="level is-mobile">
|
<div class="level is-mobile">
|
||||||
<div class="level-left">
|
<div class="level-left">
|
||||||
<div>
|
<div>
|
||||||
<a data-test-secret-path href={{href-to 'vault.cluster.secrets.backend.list-root' backend.id}} class="has-text-black has-text-weight-semibold">
|
<a data-test-secret-path
|
||||||
{{i-con glyph="folder" size=14 class="has-text-grey-light"}}{{backend.path}}
|
href={{href-to 'vault.cluster.secrets.backend.list-root' backend.id}}
|
||||||
</a>
|
class="has-text-black has-text-weight-semibold"
|
||||||
|
>{{i-con glyph="folder" size=14 class="has-text-grey-light"}}{{backend.path}}</a>
|
||||||
<br />
|
<br />
|
||||||
<span class="tag">
|
<span class="tag">
|
||||||
<code>
|
<code>
|
||||||
|
|
|
@ -57,6 +57,9 @@ module.exports = function(environment) {
|
||||||
ENV.contentSecurityPolicyMeta = true;
|
ENV.contentSecurityPolicyMeta = true;
|
||||||
ENV.contentSecurityPolicy = {
|
ENV.contentSecurityPolicy = {
|
||||||
'connect-src': ["'self'"],
|
'connect-src': ["'self'"],
|
||||||
|
'img-src': ["'self'", 'data:'],
|
||||||
|
'form-action': ["'none'"],
|
||||||
|
'script-src': ["'self'"],
|
||||||
'style-src': ["'unsafe-inline'", "'self'"],
|
'style-src': ["'unsafe-inline'", "'self'"],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
import { test } from 'qunit';
|
|
||||||
import moduleForAcceptance from 'vault/tests/helpers/module-for-acceptance';
|
|
||||||
import listPage from 'vault/tests/pages/secrets/backend/list';
|
|
||||||
import { startMirage } from 'vault/initializers/ember-cli-mirage';
|
|
||||||
import Ember from 'ember';
|
|
||||||
|
|
||||||
let adapterException;
|
|
||||||
let loggerError;
|
|
||||||
|
|
||||||
moduleForAcceptance('Acceptance | secrets/secret/secret error', {
|
|
||||||
beforeEach() {
|
|
||||||
this.server = startMirage();
|
|
||||||
loggerError = Ember.Logger.error;
|
|
||||||
adapterException = Ember.Test.adapter.exception;
|
|
||||||
Ember.Test.adapter.exception = () => {};
|
|
||||||
Ember.Logger.error = () => {};
|
|
||||||
return authLogin();
|
|
||||||
},
|
|
||||||
afterEach() {
|
|
||||||
Ember.Test.adapter.exception = adapterException;
|
|
||||||
Ember.Logger.error = loggerError;
|
|
||||||
this.server.shutdown();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
test('it shows a warning if dont have access to the secrets list', function(assert) {
|
|
||||||
listPage.visitRoot({ backend: 'secret' });
|
|
||||||
andThen(() => {
|
|
||||||
assert.ok(find('[data-test-sys-mounts-warning]').length, 'shows the warning for sys/mounts');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -43,7 +43,7 @@ export default {
|
||||||
// we use name in the label `for` attribute
|
// we use name in the label `for` attribute
|
||||||
// this is consistent across all types of fields
|
// this is consistent across all types of fields
|
||||||
//(otherwise we'd have to use name on select or input or textarea)
|
//(otherwise we'd have to use name on select or input or textarea)
|
||||||
return this.filterBy('for', name)[0];
|
return this.toArray().findBy('for', name);
|
||||||
},
|
},
|
||||||
fillIn(name, value) {
|
fillIn(name, value) {
|
||||||
return this.findByName(name).input(value);
|
return this.findByName(name).input(value);
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
import { moduleFor, test } from 'ember-qunit';
|
||||||
|
import apiStub from 'vault/tests/helpers/noop-all-api-requests';
|
||||||
|
|
||||||
|
moduleFor('adapter:secret-engine', 'Unit | Adapter | secret engine', {
|
||||||
|
needs: ['service:auth', 'service:flash-messages'],
|
||||||
|
beforeEach() {
|
||||||
|
this.server = apiStub();
|
||||||
|
},
|
||||||
|
afterEach() {
|
||||||
|
this.server.shutdown();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const storeStub = {
|
||||||
|
serializerFor() {
|
||||||
|
return {
|
||||||
|
serializeIntoHash() {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const type = {
|
||||||
|
modelName: 'secret-engine',
|
||||||
|
};
|
||||||
|
|
||||||
|
const cases = [
|
||||||
|
{
|
||||||
|
description: 'Empty query',
|
||||||
|
adapterMethod: 'query',
|
||||||
|
args: [storeStub, type, {}],
|
||||||
|
url: '/v1/sys/internal/ui/mounts',
|
||||||
|
method: 'GET',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Query with a path',
|
||||||
|
adapterMethod: 'query',
|
||||||
|
args: [storeStub, type, { path: 'foo' }],
|
||||||
|
url: '/v1/sys/internal/ui/mounts/foo',
|
||||||
|
method: 'GET',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
description: 'Query with nested path',
|
||||||
|
adapterMethod: 'query',
|
||||||
|
args: [storeStub, type, { path: 'foo/bar/baz' }],
|
||||||
|
url: '/v1/sys/internal/ui/mounts/foo/bar/baz',
|
||||||
|
method: 'GET',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
cases.forEach(testCase => {
|
||||||
|
test(`secret-engine: ${testCase.description}`, function(assert) {
|
||||||
|
assert.expect(2);
|
||||||
|
let adapter = this.subject();
|
||||||
|
adapter[testCase.adapterMethod](...testCase.args);
|
||||||
|
let { url, method } = this.server.handledRequests[0];
|
||||||
|
assert.equal(url, testCase.url, `${testCase.adapterMethod} calls the correct url: ${testCase.url}`);
|
||||||
|
assert.equal(
|
||||||
|
method,
|
||||||
|
testCase.method,
|
||||||
|
`${testCase.adapterMethod} uses the correct http verb: ${testCase.method}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue