diff --git a/.changelog/20483.txt b/.changelog/20483.txt
new file mode 100644
index 00000000000..ebe6ee298dc
--- /dev/null
+++ b/.changelog/20483.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: Added a UI for creating, editing and deleting Sentinel Policies
+```
diff --git a/ui/app/abilities/sentinel-policy.js b/ui/app/abilities/sentinel-policy.js
new file mode 100644
index 00000000000..1da17deb975
--- /dev/null
+++ b/ui/app/abilities/sentinel-policy.js
@@ -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');
+ }
+}
diff --git a/ui/app/adapters/sentinel-policy.js b/ui/app/adapters/sentinel-policy.js
new file mode 100644
index 00000000000..72bab4b5a9e
--- /dev/null
+++ b/ui/app/adapters/sentinel-policy.js
@@ -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;
+ }
+}
diff --git a/ui/app/components/access-control-subnav.js b/ui/app/components/administration-subnav.js
similarity index 81%
rename from ui/app/components/access-control-subnav.js
rename to ui/app/components/administration-subnav.js
index 9f15fc113a6..0e1e6ca1597 100644
--- a/ui/app/components/access-control-subnav.js
+++ b/ui/app/components/administration-subnav.js
@@ -8,6 +8,6 @@ import { tagName } from '@ember-decorators/component';
import { inject as service } from '@ember/service';
@tagName('')
-export default class AccessControlSubnav extends Component {
+export default class AdministrationSubnav extends Component {
@service keyboard;
}
diff --git a/ui/app/components/namespace-editor.js b/ui/app/components/namespace-editor.js
index fd2e84cc045..a67716556e0 100644
--- a/ui/app/components/namespace-editor.js
+++ b/ui/app/components/namespace-editor.js
@@ -78,7 +78,7 @@ export default class NamespaceEditorComponent extends Component {
if (shouldRedirectAfterSave) {
this.router.transitionTo(
- 'access-control.namespaces.acl-namespace',
+ 'administration.namespaces.acl-namespace',
this.namespace.name
);
}
diff --git a/ui/app/components/policy-editor.hbs b/ui/app/components/policy-editor.hbs
index 7d3b495680f..af2713152a3 100644
--- a/ui/app/components/policy-editor.hbs
+++ b/ui/app/components/policy-editor.hbs
@@ -26,12 +26,12 @@
class="policy-editor"
data-test-policy-editor
{{code-mirror
- screenReaderLabel="Policy definition"
- theme="hashi"
- mode="ruby"
- content=@policy.rules
- onUpdate=this.updatePolicyRules
- autofocus=false
+ screenReaderLabel="Policy definition"
+ theme="hashi"
+ mode="ruby"
+ content=@policy.rules
+ onUpdate=this.updatePolicyRules
+ autofocus=false
extraKeys=(hash Cmd-Enter=this.save)
}} />
diff --git a/ui/app/components/policy-editor.js b/ui/app/components/policy-editor.js
index 2f6c5ac90ac..040276485f5 100644
--- a/ui/app/components/policy-editor.js
+++ b/ui/app/components/policy-editor.js
@@ -60,7 +60,7 @@ export default class PolicyEditorComponent extends Component {
if (shouldRedirectAfterSave) {
this.router.transitionTo(
- 'access-control.policies.policy',
+ 'administration.policies.policy',
this.policy.id
);
}
diff --git a/ui/app/components/role-editor.hbs b/ui/app/components/role-editor.hbs
index 4eb18c126b3..a2cadb76816 100644
--- a/ui/app/components/role-editor.hbs
+++ b/ui/app/components/role-editor.hbs
@@ -55,7 +55,7 @@
User access tokens are associated with one or more policies or roles to grant specific capabilities.
-Roles group one or more Policies into higher-level sets of permissions.
-Sets of rules defining the capabilities granted to adhering tokens.
-Namespaces allow jobs and other objects to be segmented from each other.
-Sentinel Policies allow operators to express rules as code and have those rules automatically enforced when jobs are planned.
+