-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ui] Sentinel Policies CRUD UI (#20483)
* Gallery allows picking stuff * Small fixes * added sentinel templates * Can set enforcement level on policies * Working on the interactive sentinel dev mode * Very rough development flow on FE * Changed position in gutter menu * More sentinel stuff * PR cleanup: removed testmode, removed unneeded mixins and deps * Heliosification * Index-level sentinel policy deletion and page title fixes * Makes the Canaries sentinel policy real and then comments out the unfinished ones * rename Access Control to Administration in prep for moving Sentinel Policies and Node Pool admin there * Sentinel policies moved within the Administration section * Mirage fixture for sentinel policy endpoints * Description length check and 500 prevention * Sync review PR feedback addressed, implied butons on radio cards * Cull un-used sentinel policies --------- Co-authored-by: Mike Nomitch <mail@mikenomitch.com>
- Loading branch information
1 parent
4415fab
commit 86c858c
Showing
89 changed files
with
1,138 additions
and
231 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
```release-note:improvement | ||
ui: Added a UI for creating, editing and deleting Sentinel Policies | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/** | ||
* Copyright (c) HashiCorp, Inc. | ||
* SPDX-License-Identifier: BUSL-1.1 | ||
*/ | ||
|
||
import AbstractAbility from './abstract'; | ||
import { alias, and, or } from '@ember/object/computed'; | ||
import { computed } from '@ember/object'; | ||
|
||
export default class SentinelPolicy extends AbstractAbility { | ||
@alias('hasFeatureAndManagement') canRead; | ||
@alias('hasFeatureAndManagement') canList; | ||
@alias('hasFeatureAndManagement') canWrite; | ||
@alias('hasFeatureAndManagement') canUpdate; | ||
@alias('hasFeatureAndManagement') canDestroy; | ||
|
||
@or('bypassAuthorization', 'selfTokenIsManagement') | ||
hasAuthority; | ||
|
||
@and('sentinelIsPresent', 'hasAuthority') | ||
hasFeatureAndManagement; | ||
|
||
@computed('features.[]') | ||
get sentinelIsPresent() { | ||
return this.featureIsPresent('Sentinel Policies'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/** | ||
* Copyright (c) HashiCorp, Inc. | ||
* SPDX-License-Identifier: BUSL-1.1 | ||
*/ | ||
|
||
import { default as ApplicationAdapter } from './application'; | ||
import classic from 'ember-classic-decorator'; | ||
|
||
@classic | ||
export default class SentinelPolicyAdapter extends ApplicationAdapter { | ||
pathForType = () => 'sentinel/policies'; | ||
|
||
// namespace = namespace + '/acl'; | ||
urlForCreateRecord(_modelName, model) { | ||
return this.urlForUpdateRecord(model.attr('name'), 'sentinel/policy'); | ||
} | ||
|
||
urlForFindRecord(id) { | ||
return '/v1/sentinel/policy/' + id; | ||
} | ||
|
||
urlForDeleteRecord(id) { | ||
return '/v1/sentinel/policy/' + id; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
{{! | ||
Copyright (c) HashiCorp, Inc. | ||
SPDX-License-Identifier: BUSL-1.1 | ||
~}} | ||
|
||
<form class="acl-form" autocomplete="off" {{on "submit" this.save}}> | ||
{{#if @policy.isNew }} | ||
<Hds::Form::TextInput::Field | ||
@isRequired={{true}} | ||
data-test-policy-name-input | ||
@value={{@policy.name}} | ||
{{on "input" this.updatePolicyName}} | ||
{{autofocus}} | ||
as |F|> | ||
<F.Label>Policy Name</F.Label> | ||
</Hds::Form::TextInput::Field> | ||
{{/if}} | ||
|
||
<div class="boxed-section"> | ||
<div class="boxed-section-head"> | ||
Policy Definition | ||
</div> | ||
<div class="boxed-section-body is-full-bleed"> | ||
<div | ||
class="policy-editor" | ||
data-test-policy-editor | ||
{{code-mirror | ||
screenReaderLabel="Policy definition" | ||
theme="hashi" | ||
mode="ruby" | ||
content=@policy.policy | ||
onUpdate=this.updatePolicy | ||
autofocus=false | ||
extraKeys=(hash Cmd-Enter=this.save) | ||
}} /> | ||
</div> | ||
</div> | ||
|
||
<div> | ||
<label> | ||
<span> | ||
Description (optional) | ||
</span> | ||
<Input | ||
data-test-policy-description | ||
@value={{@policy.description}} | ||
class="input" | ||
/> | ||
</label> | ||
</div> | ||
|
||
<div> | ||
<Hds::Form::Radio::Group @layout="horizontal" @name="method-demo1" {{on "change" this.updatePolicyEnforcementLevel}} as |G|> | ||
<G.Legend>Enforcement Level</G.Legend> | ||
<G.HelperText>See <Hds::Link::Inline @href="https://developer.hashicorp.com/nomad/tutorials/access-control/access-control-tokens#token-types">Sentinel Policy documentation</Hds::Link::Inline> for more information.</G.HelperText> | ||
<G.Radio::Field | ||
@id="advisory" | ||
checked={{eq @policy.enforcementLevel "advisory"}} | ||
data-test-token-type="client" | ||
as |F|> | ||
<F.Label>Advisory</F.Label> | ||
</G.Radio::Field> | ||
<G.Radio::Field | ||
@id="soft-mandatory" | ||
checked={{eq @policy.enforcementLevel "soft-mandatory"}} | ||
data-test-token-type="soft-mandatory" | ||
as |F|> | ||
<F.Label>Soft Mandatory</F.Label> | ||
</G.Radio::Field> | ||
<G.Radio::Field | ||
@id="hard-mandatory" | ||
checked={{eq @policy.enforcementLevel "hard-mandatory"}} | ||
data-test-token-type="hard-mandatory" | ||
as |F|> | ||
<F.Label>Hard Mandatory</F.Label> | ||
</G.Radio::Field> | ||
</Hds::Form::Radio::Group> | ||
</div> | ||
|
||
<footer> | ||
{{#if (can "update sentinel-policy")}} | ||
<Hds::Button | ||
@text="Save Policy" | ||
@type="submit" | ||
data-test-save-policy | ||
{{on "click" this.save}} | ||
/> | ||
{{/if}} | ||
</footer> | ||
</form> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/** | ||
* Copyright (c) HashiCorp, Inc. | ||
* SPDX-License-Identifier: BUSL-1.1 | ||
*/ | ||
|
||
// @ts-check | ||
|
||
import Component from '@glimmer/component'; | ||
import { action } from '@ember/object'; | ||
import { inject as service } from '@ember/service'; | ||
import { alias } from '@ember/object/computed'; | ||
import messageFromAdapterError from 'nomad-ui/utils/message-from-adapter-error'; | ||
|
||
export default class SentinelPolicyEditorComponent extends Component { | ||
@service notifications; | ||
@service router; | ||
@service store; | ||
|
||
@alias('args.policy') policy; | ||
|
||
@action updatePolicy(value) { | ||
this.policy.set('policy', value); | ||
} | ||
|
||
@action updatePolicyName({ target: { value } }) { | ||
this.policy.set('name', value); | ||
} | ||
|
||
@action updatePolicyEnforcementLevel({ target: { id } }) { | ||
this.policy.set('enforcementLevel', id); | ||
} | ||
|
||
@action async save(e) { | ||
if (e instanceof Event) { | ||
e.preventDefault(); // code-mirror "command+enter" submits the form, but doesnt have a preventDefault() | ||
} | ||
try { | ||
const nameRegex = '^[a-zA-Z0-9-]{1,128}$'; | ||
if (!this.policy.name?.match(nameRegex)) { | ||
throw new Error( | ||
`Policy name must be 1-128 characters long and can only contain letters, numbers, and dashes.` | ||
); | ||
} | ||
if (this.policy.description?.length > 256) { | ||
throw new Error( | ||
`Policy description must be under 256 characters long.` | ||
); | ||
} | ||
|
||
const shouldRedirectAfterSave = this.policy.isNew; | ||
// Because we set the ID for adapter/serialization reasons just before save here, | ||
// that becomes a barrier to our Unique Name validation. So we explicltly exclude | ||
// the current policy when checking for uniqueness. | ||
if ( | ||
this.policy.isNew && | ||
this.store | ||
.peekAll('sentinel-policy') | ||
.filter((policy) => policy !== this.policy) | ||
.findBy('name', this.policy.name) | ||
) { | ||
throw new Error( | ||
`A sentinel policy with name ${this.policy.name} already exists.` | ||
); | ||
} | ||
this.policy.set('id', this.policy.name); | ||
await this.policy.save(); | ||
|
||
this.notifications.add({ | ||
title: 'Sentinel Policy Saved', | ||
color: 'success', | ||
}); | ||
|
||
if (shouldRedirectAfterSave) { | ||
this.router.transitionTo( | ||
'administration.sentinel-policies.policy', | ||
this.policy.name | ||
); | ||
} | ||
} catch (err) { | ||
let message = err.errors?.length | ||
? messageFromAdapterError(err) | ||
: err.message || 'Unknown Error'; | ||
|
||
this.notifications.add({ | ||
title: `Error creating Sentinel Policy ${this.policy.name}`, | ||
message, | ||
color: 'critical', | ||
sticky: true, | ||
}); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.